1 # Copyright (c) 2017 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
22 from os import rename, remove
23 from os.path import join, getsize
24 from shutil import move
25 from zipfile import ZipFile, is_zipfile, BadZipfile
27 from httplib import responses
28 from requests import get, codes, RequestException, Timeout, TooManyRedirects, \
29 HTTPError, ConnectionError
31 from errors import PresentationError
34 # Chunk size used for file download
37 # Separator used in file names
40 REGEX_RELEASE = re.compile(r'(\D*)(\d{4}|master)(\D*)')
43 def download_data_files(spec):
44 """Download all data specified in the specification file in the section
45 type: input --> builds.
47 :param spec: Specification.
48 :type spec: Specification
49 :raises: PresentationError if there is no url defined for the job.
52 for job, builds in spec.builds.items():
54 if job.startswith("csit-"):
55 if spec.input["file-name"].endswith(".zip"):
56 url = spec.environment["urls"]["URL[JENKINS,CSIT]"]
57 elif spec.input["file-name"].endswith(".gz"):
58 url = spec.environment["urls"]["URL[NEXUS,LOG]"]
60 logging.error("Not supported file format.")
62 elif job.startswith("hc2vpp-"):
63 url = spec.environment["urls"]["URL[JENKINS,HC]"]
65 raise PresentationError("No url defined for the job '{}'.".
67 file_name = spec.input["file-name"]
68 full_name = spec.input["download-path"].\
69 format(job=job, build=build["build"], filename=file_name)
70 url = "{0}/{1}".format(url, full_name)
72 spec.environment["paths"]["DIR[WORKING,DATA]"],
73 "{job}{sep}{build}{sep}{name}".format(job=job,
78 "Downloading the file '{0}' to '{1}' ...".format(url, new_name))
82 response = get(url, stream=True)
83 code = response.status_code
85 # temporary workaround, remove when output.log.xml is not needed
86 if code != codes["OK"] and \
87 spec.input["file-name"].endswith(".gz"):
88 url = '.'.join(url.split('.')[:-1]) + ".log.gz"
89 response = get(url, stream=True)
90 code = response.status_code
92 if code != codes["OK"]:
94 "Jenkins: {0}: {1}.".format(code, responses[code]))
95 logging.info("Trying to download from Nexus:")
96 spec.set_input_state(job, build["build"], "not found")
97 if code == codes["not_found"]:
98 release = re.search(REGEX_RELEASE, job).group(2)
99 nexus_file_name = "{job}{sep}{build}{sep}{name}".\
100 format(job=job, sep=SEPARATOR, build=build["build"],
103 release = "rls".format(int(release))
106 url = "{url}/{release}/{dir}/{file}".\
107 format(url=spec.environment["urls"]["URL[NEXUS]"],
109 dir=spec.environment["urls"]["DIR[NEXUS]"],
110 file=nexus_file_name)
111 logging.info("Downloading the file '{0}' to '{1}' ...".
112 format(url, new_name))
113 response = get(url, stream=True)
114 code = response.status_code
115 if code != codes["OK"]:
117 "Nexus: {0}: {1}".format(code, responses[code]))
118 spec.set_input_state(
119 job, build["build"], "not found")
122 file_handle = open(new_name, "wb")
123 for chunk in response.iter_content(chunk_size=CHUNK_SIZE):
125 file_handle.write(chunk)
128 if spec.input["file-name"].endswith(".zip"):
129 expected_length = None
131 expected_length = int(response.
132 headers["Content-Length"])
133 logging.debug(" Expected file size: {0}B".
134 format(expected_length))
136 logging.debug(" No information about expected size.")
138 real_length = getsize(new_name)
139 logging.debug(" Downloaded size: {0}B".format(real_length))
142 if real_length == expected_length:
143 status = "downloaded"
144 logging.info("{0}: {1}".format(code,
147 logging.error("The file size differs from the "
150 status = "downloaded"
151 logging.info("{0}: {1}".format(code, responses[code]))
153 elif spec.input["file-name"].endswith(".gz"):
154 rename(new_name, new_name[:-3])
155 with open(new_name[:-3], 'r') as xml_file:
156 with gzip.open(new_name, 'w') as gz_file:
157 gz_file.write(xml_file.read())
158 new_name = new_name[:-3]
159 status = "downloaded"
160 logging.info("{0}: {1}".format(code, responses[code]))
162 except ConnectionError as err:
163 logging.error("Not possible to connect to '{0}'.".format(url))
165 except HTTPError as err:
166 logging.error("Invalid HTTP response from '{0}'.".format(url))
168 except TooManyRedirects as err:
169 logging.error("Request exceeded the configured number "
170 "of maximum re-directions.")
172 except Timeout as err:
173 logging.error("Request timed out.")
175 except RequestException as err:
176 logging.error("Unexpected HTTP request exception.")
178 except (IOError, ValueError, KeyError) as err:
179 logging.error("Download failed.")
180 logging.debug("Reason: {0}".format(err))
182 spec.set_input_state(job, build["build"], status)
183 spec.set_input_file_name(job, build["build"], new_name)
185 if status == "failed":
186 logging.info("Removing the file '{0}'".format(new_name))
189 except OSError as err:
190 logging.warning(str(err))
191 spec.set_input_file_name(job, build["build"], None)
196 def unzip_files(spec):
197 """Unzip downloaded zip files
199 :param spec: Specification.
200 :type spec: Specification
201 :raises: PresentationError if the zip file does not exist or it is not a
206 data_file = spec.debug["extract"]
208 data_file = spec.input["extract"]
210 for job, builds in spec.builds.items():
212 if build["status"] == "failed" or build["status"] == "not found":
216 directory = spec.environment["paths"]["DIR[WORKING,DATA]"]
217 file_name = join(build["file-name"])
219 if build["status"] == "downloaded":
220 logging.info("Unziping: '{0}' from '{1}'.".
221 format(data_file, file_name))
222 new_name = "{0}{1}{2}".format(file_name.rsplit('.')[-2],
224 data_file.split("/")[-1])
226 if is_zipfile(file_name):
227 with ZipFile(file_name, 'r') as zip_file:
228 zip_file.extract(data_file, directory)
229 logging.info("Moving {0} to {1} ...".
230 format(join(directory, data_file),
232 move(join(directory, data_file), directory)
233 logging.info("Renaming the file '{0}' to '{1}'".
234 format(join(directory,
235 data_file.split("/")[-1]),
237 rename(join(directory, data_file.split("/")[-1]),
239 spec.set_input_file_name(job, build["build"],
242 spec.set_input_state(job, build["build"], status)
243 except (BadZipfile, RuntimeError) as err:
244 logging.error("Failed to unzip the file '{0}': {1}.".
245 format(file_name, str(err)))
246 except OSError as err:
247 logging.error("Failed to rename the file '{0}': {1}.".
248 format(data_file, str(err)))
250 if status == "failed":
251 spec.set_input_file_name(job, build["build"], None)
253 raise PresentationError("The file '{0}' does not exist or "
254 "it is not a zip file".
257 spec.set_input_state(job, build["build"], status)