Skip to content

Commit bd0bcc4

Browse files
Retrieve and show version information from a Jenkins Job within the Qase Test Run (#388)
* feat: Completing run * feat: Adding job url on qase report * review_changes: Implemented suggestion * review_changes: Implemented run description suggestion * review_changes: Moved completeQaseReport function to qase client * feat: Created function to capture kubernetes and images versions from the cluster * feat: Added commit id info * lint: Added error condition * feat: Changed capture images to write the info on the file during the tests
1 parent 4b3a585 commit bd0bcc4

File tree

3 files changed

+118
-25
lines changed

3 files changed

+118
-25
lines changed

scripts/capture_images/capture_images.go

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import (
77
"os"
88
"os/signal"
99
"regexp"
10+
"strings"
1011
"sync"
1112
"syscall"
1213

1314
"github.com/rancher/shepherd/clients/rancher"
1415
"github.com/rancher/shepherd/extensions/clusters"
1516
"github.com/rancher/shepherd/extensions/kubeconfig"
17+
"github.com/rancher/shepherd/extensions/kubectl"
18+
"github.com/rancher/shepherd/extensions/rancherversion"
1619
"github.com/rancher/shepherd/pkg/config"
1720
"github.com/rancher/shepherd/pkg/session"
1821

@@ -21,6 +24,13 @@ import (
2124
"k8s.io/client-go/kubernetes"
2225
)
2326

27+
const (
28+
logBufferSize = "2MB"
29+
kubernetesVersionCommand = "kubectl version -o json | jq -r '\"kubernetes:\" + .serverVersion.gitVersion'"
30+
imagesVersionsCommand = "kubectl get pods --all-namespaces -o jsonpath=\"{..image}\" |tr -s '[[:space:]]' '\n' |sort |uniq"
31+
imagesPath = "/app/images/"
32+
)
33+
2434
var (
2535
pulledRegex = regexp.MustCompile(`Successfully pulled image "([^"]+)"`)
2636
existingRegex = regexp.MustCompile(`Container image "([^"]+)" already present on machine`)
@@ -33,25 +43,25 @@ type ClusterInfo struct {
3343

3444
// Connects to the specified Rancher managed Kubernetes cluster, monitoring and parsing its events while the test
3545
// is run. Writes all pulled image names to a file.
36-
func connectAndMonitor(client *rancher.Client, sigChan chan struct{}, clusterID string) (map[string]struct{}, error) {
46+
func connectAndMonitor(client *rancher.Client, sigChan chan struct{}, clusterID string, file *os.File) error {
3747
clientConfig, err := kubeconfig.GetKubeconfig(client, clusterID)
3848
if err != nil {
39-
return nil, fmt.Errorf("Failed building client config from string: %v", err)
49+
return fmt.Errorf("Failed building client config from string: %v", err)
4050
}
4151

4252
restConfig, err := (*clientConfig).ClientConfig()
4353
if err != nil {
44-
return nil, fmt.Errorf("Failed building client config from string: %v", err)
54+
return fmt.Errorf("Failed building client config from string: %v", err)
4555
}
4656

4757
clientset, err := kubernetes.NewForConfig(restConfig)
4858
if err != nil {
49-
return nil, fmt.Errorf("Failed creating clientset object: %v", err)
59+
return fmt.Errorf("Failed creating clientset object: %v", err)
5060
}
5161

5262
previousEvents, err := clientset.CoreV1().Events("").List(context.Background(), metav1.ListOptions{})
5363
if err != nil {
54-
return nil, fmt.Errorf("Failed creating previous events: %v", err)
64+
return fmt.Errorf("Failed creating previous events: %v", err)
5565
}
5666

5767
listOptions := metav1.ListOptions{
@@ -61,18 +71,16 @@ func connectAndMonitor(client *rancher.Client, sigChan chan struct{}, clusterID
6171

6272
eventWatcher, err := clientset.CoreV1().Events("").Watch(context.Background(), listOptions)
6373
if err != nil {
64-
return nil, fmt.Errorf("Failed watching events: %v", err)
74+
return fmt.Errorf("Failed watching events: %v", err)
6575
}
6676
defer eventWatcher.Stop()
6777

6878
log.Println("Listening to events on cluster with ID " + clusterID)
6979

70-
imageSet := make(map[string]struct{})
71-
7280
for {
7381
select {
7482
case <-sigChan:
75-
return imageSet, nil
83+
return nil
7684
case rawEvent := <-eventWatcher.ResultChan():
7785
k8sEvent, ok := rawEvent.Object.(*corev1.Event)
7886
if !ok {
@@ -82,14 +90,14 @@ func connectAndMonitor(client *rancher.Client, sigChan chan struct{}, clusterID
8290
matches := pulledRegex.FindStringSubmatch(k8sEvent.Message)
8391

8492
if len(matches) > 1 {
85-
imageSet[matches[1]+" (pulled during test)"] = struct{}{}
93+
file.WriteString(fmt.Sprintf("%s (pulled during test)\n", matches[1]))
8694
continue
8795
}
8896

8997
matches = existingRegex.FindStringSubmatch(k8sEvent.Message)
9098

9199
if len(matches) > 1 {
92-
imageSet[matches[1]] = struct{}{}
100+
file.WriteString(fmt.Sprintf("%s \n", matches[1]))
93101
}
94102
}
95103
}
@@ -136,6 +144,33 @@ func main() {
136144
}
137145
}
138146

147+
c, err := clusters.NewClusterMeta(client, rancherConfig.ClusterName)
148+
if err != nil {
149+
panic(fmt.Errorf("Failed to create file for versions: %v", err))
150+
}
151+
152+
versions, err := captureVersions(client, c.ID)
153+
if err != nil {
154+
panic(fmt.Errorf("Failed to create file for versions: %v", err))
155+
}
156+
157+
file, err := os.Create(imagesPath + "version-information")
158+
if err != nil {
159+
panic(fmt.Errorf("Failed to create file for version-information: %v", err))
160+
}
161+
defer file.Close()
162+
file.Write([]byte(versions + "\n"))
163+
164+
filesMap := make(map[string]*os.File)
165+
for _, clusterInfo := range clusterList {
166+
file, err := os.Create(imagesPath + clusterInfo.Name)
167+
if err != nil {
168+
panic(fmt.Errorf("Failed to create file for image names: %v", err))
169+
}
170+
defer file.Close()
171+
filesMap[clusterInfo.Name] = file
172+
}
173+
139174
var wg sync.WaitGroup
140175
wg.Add(len(clusterList))
141176

@@ -146,21 +181,12 @@ func main() {
146181
channelList = append(channelList, doneChan)
147182

148183
go func() {
149-
imageSet, err := connectAndMonitor(client, doneChan, clusterInfo.ID)
184+
file = filesMap[clusterInfo.Name]
185+
err := connectAndMonitor(client, doneChan, clusterInfo.ID, file)
150186
if err != nil {
151187
panic(fmt.Errorf("Failed to capture used images: %v", err))
152188
}
153189

154-
file, err := os.Create("/app/images/" + clusterInfo.Name)
155-
if err != nil {
156-
panic(fmt.Errorf("Failed to create file for image names: %v", err))
157-
}
158-
defer file.Close()
159-
160-
for image := range imageSet {
161-
file.Write([]byte(image + "\n"))
162-
}
163-
164190
wg.Done()
165191
}()
166192
}
@@ -172,3 +198,29 @@ func main() {
172198

173199
wg.Wait()
174200
}
201+
202+
// captureVersions gets the images, rancher and kubernetes versions on the cluster
203+
func captureVersions(client *rancher.Client, clusterID string) (string, error) {
204+
var b strings.Builder
205+
206+
config, err := rancherversion.RequestRancherVersion(client.RancherConfig.Host)
207+
if err != nil {
208+
return "", err
209+
}
210+
211+
b.WriteString(fmt.Sprintf("rancher:%s\n", config.RancherVersion))
212+
b.WriteString(fmt.Sprintf("rancher-commit:%s\n", config.GitCommit))
213+
b.WriteString(fmt.Sprintf("is-prime:%t\n", config.IsPrime))
214+
215+
versionsCommand := []string{
216+
"sh", "-c", fmt.Sprintf("%s && %s", kubernetesVersionCommand, imagesVersionsCommand),
217+
}
218+
219+
log, err := kubectl.Command(client, nil, clusterID, versionsCommand, logBufferSize)
220+
if err != nil {
221+
return "", err
222+
}
223+
224+
b.WriteString(log)
225+
return b.String(), nil
226+
}

validation/Jenkinsfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ node {
129129
}
130130
}
131131
stage('Run Validation Tests') {
132+
sh "mkdir -p ./validation/images"
132133
try {
133134
if (env.CAPTURE_IMAGES == "true") {
134-
sh "mkdir -p ./validation/images"
135135
sh """
136136
docker run -d --name imageCapturer \
137137
-v ./validation/config.yaml:/app/config.yaml \
@@ -142,7 +142,7 @@ node {
142142
}
143143

144144
sh """
145-
docker run --name ${testContainer} -t --env-file ${envFile} ${imageName} \
145+
docker run --name ${testContainer} -v ./validation/images/:/app/images -t --env-file ${envFile} ${imageName} \
146146
sh -c "/root/go/bin/gotestsum --format standard-verbose --packages=${testsDir} --junitfile ${testResultsOut} --jsonfile ${testResultsJSON} -- -tags=${TAGS} ${GOTEST_TESTCASE} -timeout=${timeout} -v; \
147147
${rootPath}pipeline/scripts/${reporterScript}; \
148148
if [ -f ${rootPath}reporter ]; then ${rootPath}reporter; else echo \\"Reporter script not present\\"; fi"

validation/pipeline/qase/reporter-v2/main.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var (
3131

3232
const (
3333
requestLimit = 100
34+
imagesPath = "/app/images/"
3435
)
3536

3637
func main() {
@@ -294,8 +295,48 @@ func createRunDescription(buildUrl string) string {
294295
var description strings.Builder
295296

296297
if buildUrl != "" {
297-
description.WriteString(fmt.Sprintf("Jenkins Job: %s", buildUrl))
298+
description.WriteString("Jenkins Job")
299+
description.WriteString("\n")
300+
description.WriteString(buildUrl)
301+
}
302+
303+
versions := getVersionInformation()
304+
if versions != "" {
305+
if description.Len() > 0 {
306+
description.WriteString("\n")
307+
description.WriteString("\n")
308+
}
309+
description.WriteString(versions)
298310
}
299311

300312
return description.String()
301313
}
314+
315+
// getVersionInformation gets versions and commits id from cluster
316+
func getVersionInformation() string {
317+
318+
files, err := os.ReadDir(imagesPath)
319+
if err != nil {
320+
logrus.Warning(fmt.Errorf("Failed to get files: %v", err))
321+
return ""
322+
}
323+
324+
var b strings.Builder
325+
326+
for _, file := range files {
327+
path := filepath.Join(imagesPath, file.Name())
328+
329+
data, err := os.ReadFile(path)
330+
if err != nil {
331+
logrus.Warning(fmt.Errorf("Failed to read file: %v", err))
332+
continue
333+
}
334+
335+
b.WriteString(fmt.Sprintf("Images used within %s", file.Name()))
336+
b.WriteString("\n")
337+
b.WriteString(string(data))
338+
b.WriteString("\n")
339+
}
340+
341+
return b.String()
342+
}

0 commit comments

Comments
 (0)