diff --git a/release-assistant/javcra/api/jenkins_api.py b/release-assistant/javcra/api/jenkins_api.py index 9e697b84c1c2affe3ec7bfdafd0077acbda0578a..b4c8f657dfa8474a0e37bb0ecf4f1897eca7b05a 100644 --- a/release-assistant/javcra/api/jenkins_api.py +++ b/release-assistant/javcra/api/jenkins_api.py @@ -34,6 +34,8 @@ from javcra.common.constant import TRIGGER_TM_JOB from javcra.common.constant import AARCH64_TM_JOB from javcra.common.constant import X86_TM_JOB from javcra.common.constant import ACTUATOR_DICT +from javcra.common.constant import ISO_BUILD_WAIT_NUMBER +from javcra.common.constant import MIN_JENKINS_BUILD_WAIT_TIME def catch_jenkins_error(func): @@ -570,3 +572,55 @@ class JenkinsJob(object): } job_status_list.append(job_name_status_dict) return job_status_list + + + @catch_jenkins_error + def get_jenkins_job_build_result(self, params, job_name, wait_time=MIN_JENKINS_BUILD_WAIT_TIME): + """ + get job status of jenkins job according to job name + Args: + params: params to build jenkins job + job_name: job name + wait_time: The amount of time it takes to get jenkins' result + Returns: + job_status_dict: jenkins build result + """ + build_id = self.build_specific_job(job_name, params) + + if build_id: + job_status = self.wait_job_result_status(job_name, build_id, wait_time) + job_status_dict = { + "name": job_name, + "status": job_status, + "output": self.get_output_hyperlink(job_name, build_id), + } + return [job_status_dict] + + return [] + + @catch_jenkins_error + def wait_job_result_status(self, job_name, job_id, wait_time): + """ + get jenkins job result status + Args: + job_name: job name + job_id: jenkins job build id + wait_time: The amount of time it takes to get jenkins' result + Returns: + build_res: SUCCESS, FAILURE, ABORTED, None(means the job is under building) + """ + get_status_results = 0 + while True: + time.sleep(wait_time) + build_res = self.server.get_build_info(job_name, job_id)["result"] + get_status_results += 1 + if build_res: + break + if get_status_results > ISO_BUILD_WAIT_NUMBER: + build_res = "BUILD" + break + logger.info( + "%s %s build finished. The result status is %s" + % (job_name, job_id, build_res) + ) + return build_res \ No newline at end of file diff --git a/release-assistant/javcra/application/majun/__init__.py b/release-assistant/javcra/application/majun/__init__.py index cf304b61d9356686d9f420cd91450df531da365f..397c988a67a091d61861de1d6eaaadf5a6849f5c 100644 --- a/release-assistant/javcra/application/majun/__init__.py +++ b/release-assistant/javcra/application/majun/__init__.py @@ -31,6 +31,13 @@ class MessageCode(Enum): FAILED_CODE = "400" +@unique +class ConstantNumber(Enum): + CON_NUMBER_ZERO = 0 + CON_NUMBER_ONE = 1 + CON_NUMBER_TWO = 2 + + def combine_content(content, majun_id, multip_start): """ jenkins run result @@ -43,9 +50,19 @@ def combine_content(content, majun_id, multip_start): """ content_dic = {"data": content, "id": majun_id} if any([content, multip_start]): - content_dic.update({"code": MessageCode.SUCCESS_CODE.value, "msg": MessageCode.SUCCESS_MESSAGE.value}) + content_dic.update( + { + "code": MessageCode.SUCCESS_CODE.value, + "msg": MessageCode.SUCCESS_MESSAGE.value, + } + ) else: - content_dic.update({"code": MessageCode.FAILED_CODE.value, "msg": MessageCode.FAILURE_MESSAGE.value}) + content_dic.update( + { + "code": MessageCode.FAILED_CODE.value, + "msg": MessageCode.FAILURE_MESSAGE.value, + } + ) return content_dic @@ -89,9 +106,7 @@ def get_product_version(task_title): base_re_str = r"^(.+)_([a-zA-Z]+)(\d+)" if "Multi" in task_title: - re_content = re.compile(f"{base_re_str}_(.+)", re.MULTILINE).search( - task_title - ) + re_content = re.compile(f"{base_re_str}_(.+)", re.MULTILINE).search(task_title) branch_name, release_date, multi_content = ( re_content.group(1), re_content.group(3), @@ -108,16 +123,17 @@ def get_product_version(task_title): raise ValueError(f"This branch {branch_name} is not supported yet") if release_date.isdigit(): freeze_date = ( - datetime.datetime.strptime(release_date, "%Y%m%d") - + datetime.timedelta(days=2) + datetime.datetime.strptime(release_date, "%Y%m%d") + + datetime.timedelta(days=2) ).strftime("%Y%m%d") else: re_release_date = re.compile(r"(\d+)(\D+)", re.MULTILINE).search(release_date) new_update_time, temporary_str = re_content.group(1), re_release_date.group(2) - freeze_date = (datetime.datetime.strptime(new_update_time, "%Y%m%d") + - datetime.timedelta(days=2)).strftime( - "%Y%m%d") + temporary_str + freeze_date = ( + datetime.datetime.strptime(new_update_time, "%Y%m%d") + + datetime.timedelta(days=2) + ).strftime("%Y%m%d") + temporary_str return branch_name, freeze_date, multi_content @@ -140,15 +156,14 @@ def catch_majun_error(func): ) return func(*args, **kwargs) except ( - ValueError, - AttributeError, - KeyError, - TypeError, - FileNotFoundError, - IndexError + ValueError, + AttributeError, + KeyError, + TypeError, + FileNotFoundError, + IndexError, ) as err: logger.error(f"repo {err}") return send_content_majun(False, params.id) return inner - diff --git a/release-assistant/javcra/application/majun/majun_at.py b/release-assistant/javcra/application/majun/majun_at.py new file mode 100644 index 0000000000000000000000000000000000000000..fa67d663935db60bdc5bd7b75f748156c87d74df --- /dev/null +++ b/release-assistant/javcra/application/majun/majun_at.py @@ -0,0 +1,162 @@ +#!/usr/bin/python3 +# ****************************************************************************** +# Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. +# licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# ******************************************************************************/ +""" +at use-case results assist in obtaining +""" +import re +import datetime +import requests +from javcra.common.constant import ( + DAYLIBUILD_URL, + ISO_ARCH_MAP, + MAX_PARAL_NUM, + OBS_KEY_NAMES, + OBS_VALUES_NAMES, + VM_IP_MAP, + MAX_ISO_BUILD_WAIT_TIME, +) +from javcra.application.majun import ( + ConstantNumber, + catch_majun_error, + get_product_version, + send_content_majun, +) +from javcra.application.majun.majun_operate import MajunOperate + + +class MaJunAt: + def __init__(self) -> None: + self.task_title = None + self.iso_build_first_info = None + self.iso_build_last_info = None + self.jenkins_server_obj = None + self.iso_build_url = None + self.headers = { + "Content-Type": "application/json; charset=utf8", + "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0", + } + + @staticmethod + def get_iso_single_build_time(branch_name, arch_url): + """ + The iso address of the single arch + Args: + branch_name: branch name + arch_url: arch name url + + Returns: + iso_build_url: iso build url + + """ + try: + resp = requests.get(f"{DAYLIBUILD_URL}{branch_name}/{arch_url}/release_iso") + except requests.RequestException as error: + raise ValueError( + f"An error occurred at the parse iso build time, because {error}" + ) from error + if not resp or resp.status_code != requests.codes.ok: + raise ValueError("Failed to obtain the iso compile time. Procedure") + iso_build_url = resp.text.rstrip() + base_re = r"^(.+)(openeuler-)([\d|-]+)(.+)" + openeuler_build_time = re.compile(base_re).search(iso_build_url) + iso_build_time = datetime.datetime.strptime( + openeuler_build_time.group(3), + "%Y-%m-%d-%H-%M-%S", + ) + return iso_build_url, iso_build_time + + @staticmethod + def jenkins_param(branch_name): + """ + Compose jenkins task parameters + Args: + branch_name: branch name + + Returns: + base_param: jenkins parameters after composition + """ + base_param = { + "set_release_dir": ConstantNumber.CON_NUMBER_ONE.value, + "update_release_info": ConstantNumber.CON_NUMBER_ZERO.value, + "make_iso": ConstantNumber.CON_NUMBER_ONE.value, + "make_docker_image": ConstantNumber.CON_NUMBER_ONE.value, + "make_iso_everything": ConstantNumber.CON_NUMBER_ONE.value, + "make_iso_everysrc": ConstantNumber.CON_NUMBER_ONE.value, + "make_debug_everything": ConstantNumber.CON_NUMBER_ONE.value, + "make_hmi": ConstantNumber.CON_NUMBER_ONE.value, + "make_netinst_iso": ConstantNumber.CON_NUMBER_ONE.value, + "make_raspi_image": ConstantNumber.CON_NUMBER_ONE.value, + } + base_param.update(dict(vm_ip=VM_IP_MAP.get(branch_name))) + base_param.update(dict(zip(OBS_KEY_NAMES, OBS_VALUES_NAMES.get(branch_name)))) + return base_param + + def all_iso_time(self, branch_name): + """ + Get the iso urls for the different arch + Args: + branch_name: branch name + + Returns: + all_iso_info: iso addresses for different architectures + """ + all_iso_info = dict() + for arch_name, arch_url in ISO_ARCH_MAP.items(): + iso_build_url, iso_build_time = self.get_iso_single_build_time( + branch_name, arch_url + ) + all_iso_info[arch_name] = dict( + iso_build_url=iso_build_url, iso_build_time=iso_build_time + ) + return all_iso_info + + @catch_majun_error + def run(self, params): + """ + Function main entry + Args: + params: Parameter from the command line + + Returns: + Send the results to majun + """ + self.task_title = params.task_title + branch_name, freeze_date, _ = get_product_version(self.task_title) + # Gets the first build time of the iso build. + self.iso_build_first_info = self.all_iso_time(branch_name) + self.jenkins_server_obj = MajunOperate.jenkins_server( + params, MAX_PARAL_NUM, branch_name, freeze_date + ) + jenkins_params = self.jenkins_param(branch_name) + jenkins_job = f"openEuler-OS-build/Main-{branch_name}-build" + res = self.jenkins_server_obj.get_jenkins_job_build_result( + jenkins_params, jenkins_job, MAX_ISO_BUILD_WAIT_TIME + ) + if not res or res[0].get("status") != "SUCCESS": + raise ValueError( + "The iso construction fails. Check the cause of the failure" + ) + # Gets the last build time of the iso build. + self.iso_build_last_info = self.all_iso_time(branch_name) + iso_urls = list() + for arch_name, iso_info in self.iso_build_last_info.items(): + if ( + iso_info.get("iso_build_time") + - self.iso_build_first_info.get(arch_name).get("iso_build_time") + ).seconds <= 0: + raise ValueError( + "The iso url is not updated. Check the cause manually" + ) + else: + iso_urls.append(iso_info.get("iso_build_url")) + return send_content_majun(";".join(iso_urls), params.id) diff --git a/release-assistant/javcra/common/constant.py b/release-assistant/javcra/common/constant.py index 69f80f283bc4bd4f4eb872bee9ed44edfb931338..96d1dd62daf9eb593e9e6894e47b9b5ecf3b8297 100644 --- a/release-assistant/javcra/common/constant.py +++ b/release-assistant/javcra/common/constant.py @@ -201,4 +201,43 @@ CVE_UPDATE_INFO_JOB_NAME = "function-item/update_repodata_by_updateinfo_automati # Test milestone routing TEST_MILESTONE_URL = "http://radiatest.openeuler.org/api/v1/openeuler/update-release/validate" -MILESTONE_SUCCESS_CODE = "2000" \ No newline at end of file +MILESTONE_SUCCESS_CODE = "2000" +DAYLIBUILD_URL = "http://121.36.84.172/dailybuild/" + +ISO_ARCH_MAP = {"ARM64": "openeuler_ARM64", "X86": "openeuler_X86"} + +OBS_KEY_NAMES = ["obs_standard_prj", "obs_epol_prj", "obs_extras_prj"] + +OBS_VALUES_NAMES = { + "openEuler-22.09": [ + "openEuler:22.09", + "openEuler:22.09:Epol", + "openEuler:22.09:Extras", + ], + "openEuler-20.03-LTS-SP1": [ + "openEuler:20.03:LTS:SP1", + "openEuler:20.03:LTS:SP1:Epol", + "openEuler:20.03:LTS:SP1:Extras", + ], + "openEuler-20.03-LTS-SP3": [ + "openEuler:20.03:LTS:SP3", + "openEuler:20.03:LTS:SP3:Epol", + "openEuler:20.03:LTS:SP3:Extras", + ], + "openEuler-22.03-LTS": [ + "openEuler:22.03:LTS", + "openEuler:22.03:LTS:Epol", + "openEuler:22.03:LTS:Epol:Extras", + ], +} + +VM_IP_MAP = { + "openEuler-22.09": "172.16.1.155", + "openEuler-20.03-LTS-SP1": "172.16.1.32", + "openEuler-20.03-LTS-SP3": "172.16.1.32", + "openEuler-22.03-LTS": "172.16.1.32", +} + +MIN_JENKINS_BUILD_WAIT_TIME = 5 +MAX_ISO_BUILD_WAIT_TIME = 1200 +ISO_BUILD_WAIT_NUMBER = 6