2c96bf4ec7de1df8854a5074d46c1a37121f32c4
16 import xml
.etree
.ElementTree
as ET
18 from email
.utils
import formatdate
19 from pathlib
import Path
21 from urllib
import parse
23 import dump_trace_images
25 TRACES_DB_PATH
= "./traces-db/"
26 RESULTS_PATH
= "./results/"
27 MINIO_HOST
= "minio-packet.freedesktop.org"
28 DASHBOARD_URL
= "https://tracie.freedesktop.org/dashboard"
30 minio_credentials
= None
32 def replay(trace_path
, device_name
):
33 success
= dump_trace_images
.dump_from_trace(trace_path
, [], device_name
)
36 print("[check_image] Trace %s couldn't be replayed. See above logs for more information." % (str(trace_path
)))
37 return None, None, None
39 base_path
= trace_path
.parent
40 file_name
= trace_path
.name
41 files
= glob
.glob(str(base_path
/ "test" / device_name
/ (file_name
+ "-*" + ".png")))
44 files
= glob
.glob(str(base_path
/ "test" / device_name
/ (file_name
+ ".log")))
47 return hashlib
.md5(Image
.open(image_file
).tobytes()).hexdigest(), image_file
, log_file
49 def gitlab_ensure_trace(project_url
, trace
):
50 trace_path
= TRACES_DB_PATH
+ trace
['path']
51 if project_url
is None:
52 if not os
.path
.exists(trace_path
):
53 print("{} missing".format(trace_path
))
57 os
.makedirs(os
.path
.dirname(trace_path
), exist_ok
=True)
59 if os
.path
.exists(trace_path
):
62 print("[check_image] Downloading trace %s" % (trace
['path']), end
=" ", flush
=True)
63 download_time
= time
.time()
64 r
= requests
.get(project_url
+ trace
['path'])
65 open(trace_path
, "wb").write(r
.content
)
66 print("took %ds." % (time
.time() - download_time
), flush
=True)
68 def sign_with_hmac(key
, message
):
69 key
= key
.encode("UTF-8")
70 message
= message
.encode("UTF-8")
72 signature
= hmac
.new(key
, message
, hashlib
.sha1
).digest()
74 return base64
.encodebytes(signature
).strip().decode()
76 def ensure_minio_credentials():
77 global minio_credentials
79 if minio_credentials
is None:
80 minio_credentials
= {}
82 params
= {'Action': 'AssumeRoleWithWebIdentity',
83 'Version': '2011-06-15',
84 'RoleArn': 'arn:aws:iam::123456789012:role/FederatedWebIdentityRole',
85 'RoleSessionName': '%s:%s' % (os
.environ
['CI_PROJECT_PATH'], os
.environ
['CI_JOB_ID']),
86 'DurationSeconds': 900,
87 'WebIdentityToken': os
.environ
['CI_JOB_JWT']}
88 r
= requests
.post('https://%s' % (MINIO_HOST
), params
=params
)
89 if r
.status_code
>= 400:
93 root
= ET
.fromstring(r
.text
)
94 for attr
in root
.iter():
95 if attr
.tag
== '{https://sts.amazonaws.com/doc/2011-06-15/}AccessKeyId':
96 minio_credentials
['AccessKeyId'] = attr
.text
97 elif attr
.tag
== '{https://sts.amazonaws.com/doc/2011-06-15/}SecretAccessKey':
98 minio_credentials
['SecretAccessKey'] = attr
.text
99 elif attr
.tag
== '{https://sts.amazonaws.com/doc/2011-06-15/}SessionToken':
100 minio_credentials
['SessionToken'] = attr
.text
102 def upload_to_minio(file_name
, resource
, content_type
):
103 ensure_minio_credentials()
105 minio_key
= minio_credentials
['AccessKeyId']
106 minio_secret
= minio_credentials
['SecretAccessKey']
107 minio_token
= minio_credentials
['SessionToken']
109 date
= formatdate(timeval
=None, localtime
=False, usegmt
=True)
110 url
= 'https://%s%s' % (MINIO_HOST
, resource
)
111 to_sign
= "PUT\n\n%s\n%s\nx-amz-security-token:%s\n%s" % (content_type
, date
, minio_token
, resource
)
112 signature
= sign_with_hmac(minio_secret
, to_sign
)
114 with
open(file_name
, 'rb') as data
:
115 headers
= {'Host': MINIO_HOST
,
117 'Content-Type': content_type
,
118 'Authorization': 'AWS %s:%s' % (minio_key
, signature
),
119 'x-amz-security-token': minio_token
}
120 print("Uploading artifact to %s" % url
);
121 r
= requests
.put(url
, headers
=headers
, data
=data
)
122 if r
.status_code
>= 400:
126 def upload_artifact(file_name
, key
, content_type
):
127 resource
= '/artifacts/%s/%s/%s/%s' % (os
.environ
['CI_PROJECT_PATH'],
128 os
.environ
['CI_PIPELINE_ID'],
129 os
.environ
['CI_JOB_ID'],
131 upload_to_minio(file_name
, resource
, content_type
)
133 def ensure_reference_image(file_name
, checksum
):
134 resource
= '/mesa-tracie-results/%s/%s.png' % (os
.environ
['CI_PROJECT_PATH'], checksum
)
135 url
= 'https://%s%s' % (MINIO_HOST
, resource
)
136 r
= requests
.head(url
, allow_redirects
=True)
137 if r
.status_code
== 200:
139 upload_to_minio(file_name
, resource
, 'image/png')
141 def gitlab_check_trace(project_url
, device_name
, trace
, expectation
):
142 gitlab_ensure_trace(project_url
, trace
)
145 result
[trace
['path']] = {}
146 result
[trace
['path']]['expected'] = expectation
['checksum']
148 trace_path
= Path(TRACES_DB_PATH
+ trace
['path'])
149 checksum
, image_file
, log_file
= replay(trace_path
, device_name
)
151 result
[trace
['path']]['actual'] = 'error'
153 elif checksum
== expectation
['checksum']:
154 print("[check_image] Images match for %s" % (trace
['path']))
157 print("[check_image] Images differ for %s (expected: %s, actual: %s)" %
158 (trace
['path'], expectation
['checksum'], checksum
))
159 print("[check_image] For more information see "
160 "https://gitlab.freedesktop.org/mesa/mesa/blob/master/.gitlab-ci/tracie/README.md")
161 image_diff_url
= "%s/imagediff/%s/%s/%s/%s/%s" % (DASHBOARD_URL
,
162 os
.environ
['CI_PROJECT_PATH'],
163 os
.environ
['CI_PIPELINE_ID'],
164 os
.environ
['CI_JOB_ID'],
165 expectation
['checksum'],
167 print("[check_image] %s" % image_diff_url
)
170 trace_dir
= os
.path
.split(trace
['path'])[0]
171 dir_in_results
= os
.path
.join(trace_dir
, "test", device_name
)
172 results_path
= os
.path
.join(RESULTS_PATH
, dir_in_results
)
173 os
.makedirs(results_path
, exist_ok
=True)
174 shutil
.move(log_file
, os
.path
.join(results_path
, os
.path
.split(log_file
)[1]))
175 if os
.environ
.get('TRACIE_UPLOAD_TO_MINIO', '0') == '1':
177 if os
.environ
['CI_PROJECT_PATH'] == 'mesa/mesa':
178 ensure_reference_image(image_file
, checksum
)
180 upload_artifact(image_file
, 'traces/%s.png' % checksum
, 'image/png')
181 if not ok
or os
.environ
.get('TRACIE_STORE_IMAGES', '0') == '1':
182 image_name
= os
.path
.split(image_file
)[1]
183 shutil
.move(image_file
, os
.path
.join(results_path
, image_name
))
184 result
[trace
['path']]['image'] = os
.path
.join(dir_in_results
, image_name
)
186 result
[trace
['path']]['actual'] = checksum
190 def run(filename
, device_name
):
192 with
open(filename
, 'r') as f
:
193 y
= yaml
.safe_load(f
)
196 project_url
= y
["traces-db"]["download-url"]
200 traces
= y
['traces'] or []
204 for expectation
in trace
['expectations']:
205 if expectation
['device'] == device_name
:
206 ok
, result
= gitlab_check_trace(project_url
,
209 all_ok
= all_ok
and ok
210 results
.update(result
)
212 os
.makedirs(RESULTS_PATH
, exist_ok
=True)
213 with
open(os
.path
.join(RESULTS_PATH
, 'results.yml'), 'w') as f
:
214 yaml
.safe_dump(results
, f
, default_flow_style
=False)
215 if os
.environ
.get('TRACIE_UPLOAD_TO_MINIO', '0') == '1':
216 upload_artifact(os
.path
.join(RESULTS_PATH
, 'results.yml'), 'traces/results.yml', 'text/yaml')
221 parser
= argparse
.ArgumentParser()
222 parser
.add_argument('--file', required
=True,
223 help='the name of the traces.yml file listing traces and their checksums for each device')
224 parser
.add_argument('--device-name', required
=True,
225 help="the name of the graphics device used to replay traces")
227 args
= parser
.parse_args(args
)
228 return run(args
.file, args
.device_name
)
230 if __name__
== "__main__":
231 all_ok
= main(sys
.argv
[1:])
232 sys
.exit(0 if all_ok
else 1)