From ef4660eb016fef7f0611f0e43c95c3a724910070 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:20:06 +0100 Subject: [PATCH 01/20] Remove interval option - we run it as systemd timer for a while --- totest-manager.py | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index dfbcec98..42e02ad9 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -1179,7 +1179,6 @@ class CommandlineInterface(cmdln.Cmdln): return self.totest_class[project](project, self.options.dry, not release, self.options.obs_api_url, self.options.openqa_server) - @cmdln.option('-n', '--interval', metavar="minutes", type="int", help="periodic interval in minutes") def do_run(self, subcmd, opts, project='openSUSE:Factory'): """${cmd_name}: run the ToTest Manager @@ -1187,39 +1186,8 @@ class CommandlineInterface(cmdln.Cmdln): ${cmd_option_list} """ - class ExTimeout(Exception): - - """raised on timeout""" - - if opts.interval: - def alarm_called(nr, frame): - raise ExTimeout() - signal.signal(signal.SIGALRM, alarm_called) - - while True: - try: - totest = self._setup_totest(project) - totest.totest() - except Exception as e: - logger.error(e) - - if opts.interval: - if os.isatty(0): - logger.info( - "sleeping %d minutes. Press enter to check now ..." % opts.interval) - signal.alarm(opts.interval * 60) - try: - raw_input() - except ExTimeout: - pass - signal.alarm(0) - logger.info("recheck at %s" % - datetime.datetime.now().isoformat()) - else: - logger.info("sleeping %d minutes." % opts.interval) - time.sleep(opts.interval * 60) - continue - break + totest = self._setup_totest(project) + totest.totest() def do_release(self, subcmd, opts, project='openSUSE:Factory'): """${cmd_name}: manually release all media. Use with caution! @@ -1229,7 +1197,6 @@ class CommandlineInterface(cmdln.Cmdln): """ totest = self._setup_totest(project) - totest.release() From 0d4a233fd89f9128084e2c57140a6bd288ffd971 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:22:11 +0100 Subject: [PATCH 02/20] Harmonize get_current_snapshot to take first main_product --- totest-manager.py | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 42e02ad9..a8229e9b 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -108,9 +108,6 @@ class ToTestBase(object): def openqa_group(self): return self.project - def iso_prefix(self): - return self.project - def jobs_num(self): return 70 @@ -137,15 +134,7 @@ class ToTestBase(object): return ret def get_current_snapshot(self): - """Return the current snapshot in the test project""" - - for binary in self.binaries_of_product(self.test_project, '000product:%s-cd-mini-%s' % (self.project_base, self.arch())): - result = re.match(r'%s-%s-NET-.*-Snapshot(.*)-Media.iso' % (self.project_base, self.iso_prefix()), - binary) - if result: - return result.group(1) - - return None + return self.iso_build_version(self.test_project, self.main_products[0]) def ftp_build_version(self, project, tree, base=None): if not base: @@ -795,9 +784,6 @@ class ToTestFactory(ToTestBase): def openqa_group(self): return 'openSUSE Tumbleweed' - def iso_prefix(self): - return 'Tumbleweed' - def arch(self): return 'x86_64' @@ -823,9 +809,6 @@ class ToTestFactoryPowerPC(ToTestBase): def arch(self): return 'ppc64le' - def iso_prefix(self): - return 'Tumbleweed' - def jobs_num(self): return 4 @@ -845,9 +828,6 @@ class ToTestFactoryzSystems(ToTestBase): def arch(self): return 's390x' - def iso_prefix(self): - return 'Tumbleweed' - def jobs_num(self): return 1 @@ -898,9 +878,6 @@ class ToTest151(ToTestBaseNew): def openqa_group(self): return 'openSUSE Leap 15' - def get_current_snapshot(self): - return self.iso_build_version(self.project + ':ToTest', self.main_products[0]) - class ToTest151ARM(ToTest151): main_products = [ @@ -959,10 +936,6 @@ class ToTest150Ports(ToTestBaseNew): def jobs_num(self): return 10 - def get_current_snapshot(self): - return self.iso_build_version(self.project + ':ToTest', self.main_products[0]) - - class ToTest150Images(ToTestBaseNew): image_products = [ ImageProduct('livecd-leap-gnome', ['x86_64']), @@ -995,7 +968,7 @@ class ToTest150Images(ToTestBaseNew): arch=self.image_products[0].archs[0]) def get_current_snapshot(self): - return self.iso_build_version(self.project + ':ToTest', self.image_products[0].package, + return self.iso_build_version(self.test_project, self.image_products[0].package, arch=self.image_products[0].archs[0]) def _release(self, set_release=None): @@ -1048,9 +1021,6 @@ class ToTestSLE(ToTestBaseNew): def openqa_group(self): return 'Functional' - def get_current_snapshot(self): - return self.iso_build_version(self.project + ':TEST', self.main_products[0]) - def ftp_build_version(self, project, tree): return super(ToTestSLE, self).ftp_build_version(project, tree, base='SLE') From 2f1c2cb2e6e39aef33fe77cd49811196596426eb Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:24:57 +0100 Subject: [PATCH 03/20] Remove basically duplicated release_version function This used to differ between _product and 000product - but meanwhile we all use the same mechanism --- totest-manager.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index a8229e9b..e9667c19 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -699,19 +699,6 @@ class ToTestBaseNew(ToTestBase): self._release_package('%s:Live' % self.project, cd.package, set_release=set_release) - def release_version(self): - url = self.api.makeurl(['build', self.project, 'standard', self.arch(), - '000product:%s-release' % self.project_base]) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - for binary in root.findall('binary'): - binary = binary.get('filename', '') - result = re.match(r'.*-([^-]*)-[^-]*.src.rpm', binary) - if result: - return result.group(1) - - raise NotFoundException("can't find %s release version" % self.project) - def current_version(self): return self.iso_build_version(self.project, self.main_products[0]) From c7a81596bcda13c1af337c119baa96d327c57816 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:26:43 +0100 Subject: [PATCH 04/20] Remove overloaded iso_ and ftp_ function for SLE All your base belong to us! --- totest-manager.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index e9667c19..15b69dfb 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -136,18 +136,14 @@ class ToTestBase(object): def get_current_snapshot(self): return self.iso_build_version(self.test_project, self.main_products[0]) - def ftp_build_version(self, project, tree, base=None): - if not base: - base = self.project_base + def ftp_build_version(self, project, tree): for binary in self.binaries_of_product(project, tree): - result = re.match(r'%s.*Build(.*)-Media1.report' % base, binary) + result = re.match(r'.*-Build(.*)-Media1.report', binary) if result: return result.group(1) raise NotFoundException("can't find %s ftp version" % project) - def iso_build_version(self, project, tree, base=None, repo=None, arch=None): - if not base: - base = self.project_base + def iso_build_version(self, project, tree, repo=None, arch=None): for binary in self.binaries_of_product(project, tree, repo=repo, arch=arch): result = re.match(r'.*-(?:Build|Snapshot)([0-9.]+)(?:-Media.*\.iso|\.docker\.tar\.xz|\.raw\.xz)', binary) if result: @@ -1008,13 +1004,6 @@ class ToTestSLE(ToTestBaseNew): def openqa_group(self): return 'Functional' - def ftp_build_version(self, project, tree): - return super(ToTestSLE, self).ftp_build_version(project, tree, base='SLE') - - def iso_build_version(self, project, tree): - return super(ToTestSLE, self).iso_build_version(project, tree, base='SLE') - - class ToTestSLE12(ToTestSLE): main_products = [ '_product:SLES-dvd5-DVD-aarch64', From fa33f864cf0e0ded1cedb3c0dea7316127f5544c Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:31:02 +0100 Subject: [PATCH 05/20] Move set_snapshot_number to ToTestBase --- totest-manager.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 15b69dfb..944cbb4f 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -516,6 +516,9 @@ class ToTestBase(object): target_repository=self.totest_container_repo) def update_totest(self, snapshot=None): + # omit snapshot, we don't want to rename on release + if not self.set_snapshot_number: + snapshot = None release = 'Snapshot%s' % snapshot if snapshot else None logger.info('Updating snapshot %s' % snapshot) if not (self.dryrun or self.norelease): @@ -668,9 +671,6 @@ class ToTestBaseNew(ToTestBase): # whether all medias need to have the same build number need_same_build_number = True - # whether to set a snapshot number on release - set_snapshot_number = False - """Base class for new product builder""" def _release(self, set_release=None): @@ -721,11 +721,7 @@ class ToTestBaseNew(ToTestBase): return ret - def update_totest(self, snapshot): - if not self.set_snapshot_number: - snapshot = None - # omit snapshot, we don't want to rename on release - super(ToTestBaseNew, self).update_totest(snapshot) + class ToTestFactory(ToTestBase): @@ -849,6 +845,10 @@ class ToTestFactoryARM(ToTestFactory): class ToTest151(ToTestBaseNew): + + # whether to set a snapshot number on release + set_snapshot_number = False + main_products = [ '000product:openSUSE-cd-mini-x86_64', '000product:openSUSE-dvd5-dvd-x86_64', @@ -998,6 +998,9 @@ class ToTest151ARMImages(ToTest151Images): class ToTestSLE(ToTestBaseNew): + # whether to set a snapshot number on release + set_snapshot_number = False + def __init__(self, *args, **kwargs): ToTestBaseNew.__init__(self, test_subproject='TEST', *args, **kwargs) From 0ed0c0ebcdc4edb24c0e0e61b5ae1af60e939160 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:50:32 +0100 Subject: [PATCH 06/20] Change the current_source override to a config --- totest-manager.py | 60 ++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 944cbb4f..2a8b90e2 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -111,8 +111,27 @@ class ToTestBase(object): def jobs_num(self): return 70 - def current_version(self): - return self.release_version() + def release_version(self): + url = self.api.makeurl(['build', self.project, 'standard', self.arch(), + '000release-packages:%s-release' % self.project_base]) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + for binary in root.findall('binary'): + binary = binary.get('filename', '') + result = re.match(r'.*-([^-]*)-[^-]*.src.rpm', binary) + if result: + return result.group(1) + + raise NotFoundException("can't find %s version" % self.project) + + def current_sources(self): + if self.take_source_from_product is None: + raise Exception('No idea where to take the source version from') + + if self.take_source_from_product: + return self.iso_build_version(self.project, self.main_products[0]) + else: + return self.release_version() def binaries_of_product(self, project, product, repo=None, arch=None): if repo is None: @@ -150,19 +169,6 @@ class ToTestBase(object): return result.group(1) raise NotFoundException("can't find %s iso version" % project) - def release_version(self): - url = self.api.makeurl(['build', self.project, 'standard', self.arch(), - '000release-packages:%s-release' % self.project_base]) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - for binary in root.findall('binary'): - binary = binary.get('filename', '') - result = re.match(r'.*-([^-]*)-[^-]*.src.rpm', binary) - if result: - return result.group(1) - - raise NotFoundException("can't find %s version" % self.project) - def current_qa_version(self): return self.api.pseudometa_file_load('version_totest') @@ -565,7 +571,7 @@ class ToTestBase(object): # nothing in test project (yet) logger.warn(e) current_snapshot = None - new_snapshot = self.current_version() + new_snapshot = self.current_sources() self.update_pinned_descr = False current_result = self.overall_result(current_snapshot) current_qa_version = self.current_qa_version() @@ -658,7 +664,7 @@ class ToTestBase(object): logger.error('Could not send out AMQP event for %s tries, aborting.' % tries) def release(self): - new_snapshot = self.current_version() + new_snapshot = self.current_sources() self.update_totest(new_snapshot) def write_version_to_dashboard(self, target, version): @@ -670,6 +676,7 @@ class ToTestBaseNew(ToTestBase): # whether all medias need to have the same build number need_same_build_number = True + take_source_from_product = True """Base class for new product builder""" @@ -695,9 +702,6 @@ class ToTestBaseNew(ToTestBase): self._release_package('%s:Live' % self.project, cd.package, set_release=set_release) - def current_version(self): - return self.iso_build_version(self.project, self.main_products[0]) - def is_snapshottable(self): ret = super(ToTestBaseNew, self).is_snapshottable() if ret and self.need_same_build_number: @@ -721,9 +725,6 @@ class ToTestBaseNew(ToTestBase): return ret - - - class ToTestFactory(ToTestBase): main_products = ['000product:openSUSE-dvd5-dvd-i586', '000product:openSUSE-dvd5-dvd-x86_64', @@ -757,6 +758,8 @@ class ToTestFactory(ToTestBase): for flavor in ['MicroOS-podman', 'kubeadm-cri-o'] ] + take_source_from_product = False + def __init__(self, *args, **kwargs): ToTestBase.__init__(self, *args, **kwargs) @@ -779,6 +782,8 @@ class ToTestFactoryPowerPC(ToTestBase): ImageProduct('kubic-kured-image', ['ppc64le']), ImageProduct('kubic-pause-image', ['ppc64le'])] + take_source_from_product = False + def __init__(self, *args, **kwargs): ToTestBase.__init__(self, *args, **kwargs) @@ -798,6 +803,8 @@ class ToTestFactoryzSystems(ToTestBase): ftp_products = ['000product:openSUSE-ftp-ftp-s390x'] + take_source_from_product = False + def __init__(self, *args, **kwargs): ToTestBase.__init__(self, *args, **kwargs) @@ -831,6 +838,8 @@ class ToTestFactoryARM(ToTestFactory): # JeOS doesn't follow build numbers of main isos need_same_build_number = False + take_source_from_product = False + def __init__(self, *args, **kwargs): ToTestFactory.__init__(self, *args, **kwargs) @@ -936,6 +945,7 @@ class ToTest150Images(ToTestBaseNew): # docker image has a different number need_same_build_number = False set_snapshot_number = True + take_source_from_product = True def openqa_group(self): return 'openSUSE Leap 15.0 Images' @@ -946,7 +956,7 @@ class ToTest150Images(ToTestBaseNew): def write_version_to_dashboard(self, target, version): super(ToTest150Images, self).write_version_to_dashboard('{}_images'.format(target), version) - def current_version(self): + def current_sources(self): return self.iso_build_version(self.project, self.image_products[0].package, arch=self.image_products[0].archs[0]) @@ -1001,6 +1011,8 @@ class ToTestSLE(ToTestBaseNew): # whether to set a snapshot number on release set_snapshot_number = False + take_source_from_product = True + def __init__(self, *args, **kwargs): ToTestBaseNew.__init__(self, test_subproject='TEST', *args, **kwargs) From 40346475e0163ce18ce99305550e9a10c9663c99 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 15:59:01 +0100 Subject: [PATCH 07/20] Merge is_snapshottable variants --- totest-manager.py | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 2a8b90e2..38c51d6e 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -472,6 +472,24 @@ class ToTestBase(object): self.product_repo, arch): return False + if self.need_same_build_number: + # make sure all medias have the same build number + builds = set() + for p in self.ftp_products: + if 'Addon-NonOss' in p: + # XXX: don't care about nonoss atm. + continue + builds.add(self.ftp_build_version(self.project, p)) + for p in self.main_products: + builds.add(self.iso_build_version(self.project, p)) + for p in self.livecd_products + self.image_products: + for arch in p.archs: + builds.add(self.iso_build_version(self.project, p.package, + arch=arch)) + if len(builds) != 1: + logger.debug("not all medias have the same build number") + return False + return True def _release_package(self, project, package, set_release=None, repository=None, @@ -702,28 +720,7 @@ class ToTestBaseNew(ToTestBase): self._release_package('%s:Live' % self.project, cd.package, set_release=set_release) - def is_snapshottable(self): - ret = super(ToTestBaseNew, self).is_snapshottable() - if ret and self.need_same_build_number: - # make sure all medias have the same build number - builds = set() - for p in self.ftp_products: - if 'Addon-NonOss' in p: - # XXX: don't care about nonoss atm. - continue - builds.add(self.ftp_build_version(self.project, p)) - for p in self.main_products: - builds.add(self.iso_build_version(self.project, p)) - for p in self.livecd_products + self.image_products: - for arch in p.archs: - builds.add(self.iso_build_version(self.project, p.package, - arch=arch)) - ret = (len(builds) == 1) - if ret is False: - logger.debug("not all medias have the same build number") - - return ret class ToTestFactory(ToTestBase): main_products = ['000product:openSUSE-dvd5-dvd-i586', From 46a135090a358990846efc977b2a397d1b8147ec Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 16:57:28 +0100 Subject: [PATCH 08/20] Merge _release functions --- totest-manager.py | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 38c51d6e..e11b487c 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -494,6 +494,10 @@ class ToTestBase(object): def _release_package(self, project, package, set_release=None, repository=None, target_project=None, target_repository=None): + if package.startswith('000product:'): + logger.debug('Ignoring to release {}'.format(package)) + return + query = {'cmd': 'release'} if set_release: @@ -516,6 +520,10 @@ class ToTestBase(object): self.api.retried_POST(url) def _release(self, set_release=None): + # release 000product as a whole + if self.main_products[0].startswith('000product'): + self._release_package(self.project, '000product', set_release=set_release) + for product in self.ftp_products: self._release_package(self.project, product, repository=self.product_repo) @@ -696,32 +704,6 @@ class ToTestBaseNew(ToTestBase): need_same_build_number = True take_source_from_product = True - """Base class for new product builder""" - - def _release(self, set_release=None): - query = {'cmd': 'release'} - - package = '000product' - project = self.project - - if set_release: - query['setrelease'] = set_release - - baseurl = ['source', project, package] - - url = self.api.makeurl(baseurl, query=query) - if self.dryrun or self.norelease: - logger.info("release %s/%s (%s)" % (project, package, set_release)) - else: - self.api.retried_POST(url) - - # XXX still legacy - for cd in self.livecd_products: - self._release_package('%s:Live' % - self.project, cd.package, set_release=set_release) - - - class ToTestFactory(ToTestBase): main_products = ['000product:openSUSE-dvd5-dvd-i586', '000product:openSUSE-dvd5-dvd-x86_64', From 31568f2b3733275312db93a7b5c667068b4f29d6 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 17:05:01 +0100 Subject: [PATCH 09/20] ToTestBaseNew is history --- totest-manager.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index e11b487c..9b0ee574 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -698,12 +698,6 @@ class ToTestBase(object): self.api.pseudometa_file_ensure('version_%s' % target, version, comment='Update version') -class ToTestBaseNew(ToTestBase): - - # whether all medias need to have the same build number - need_same_build_number = True - take_source_from_product = True - class ToTestFactory(ToTestBase): main_products = ['000product:openSUSE-dvd5-dvd-i586', '000product:openSUSE-dvd5-dvd-x86_64', @@ -832,7 +826,11 @@ class ToTestFactoryARM(ToTestFactory): return 2 -class ToTest151(ToTestBaseNew): +class ToTest151(ToTestBase): + + # whether all medias need to have the same build number + need_same_build_number = True + take_source_from_product = True # whether to set a snapshot number on release set_snapshot_number = False @@ -882,8 +880,7 @@ class ToTest151PowerPC(ToTest151): def jobs_num(self): return 10 - -class ToTest150Ports(ToTestBaseNew): +class ToTest150Ports(ToTestBase): main_products = [ '000product:openSUSE-cd-mini-aarch64', '000product:openSUSE-dvd5-dvd-aarch64', @@ -893,6 +890,11 @@ class ToTest150Ports(ToTestBaseNew): '000product:openSUSE-ftp-ftp-armv7hl', ] + + # whether all medias need to have the same build number + need_same_build_number = True + take_source_from_product = True + # Leap 15.0 Ports still need to update snapshot set_snapshot_number = True @@ -907,7 +909,7 @@ class ToTest150Ports(ToTestBaseNew): def jobs_num(self): return 10 -class ToTest150Images(ToTestBaseNew): +class ToTest150Images(ToTestBase): image_products = [ ImageProduct('livecd-leap-gnome', ['x86_64']), ImageProduct('livecd-leap-kde', ['x86_64']), @@ -943,9 +945,6 @@ class ToTest150Images(ToTestBaseNew): return self.iso_build_version(self.test_project, self.image_products[0].package, arch=self.image_products[0].archs[0]) - def _release(self, set_release=None): - ToTestBase._release(self, set_release) - def jobs_num(self): return 13 @@ -979,21 +978,21 @@ class ToTest151ARMImages(ToTest151Images): def openqa_group(self): return 'openSUSE Leap 15.1 AArch64 Images' - def _release(self, set_release=None): - ToTestBase._release(self, set_release) - def jobs_num(self): return 2 -class ToTestSLE(ToTestBaseNew): +class ToTestSLE(ToTestBase): # whether to set a snapshot number on release set_snapshot_number = False + # whether all medias need to have the same build number + need_same_build_number = True + take_source_from_product = True def __init__(self, *args, **kwargs): - ToTestBaseNew.__init__(self, test_subproject='TEST', *args, **kwargs) + ToTestBase.__init__(self, test_subproject='TEST', *args, **kwargs) def openqa_group(self): return 'Functional' From af4acbe91d8c393aaaec2bebda6b052f3f608b8c Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 17:26:09 +0100 Subject: [PATCH 10/20] Remove bad quotes (flake) --- totest-manager.py | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 9b0ee574..d4017934 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -230,8 +230,8 @@ class ToTestBase(object): 'preparing' if self.status_for_openqa['can_release'] else \ 'testing' if self.status_for_openqa['snapshotable'] else \ 'building' - status_msg = "tag:{}:{}:{}".format(self.status_for_openqa['new_snapshot'], status_flag, status_flag) - msg = "pinned-description: Ignored issues\r\n\r\n{}\r\n\r\n{}".format(issues, status_msg) + status_msg = 'tag:{}:{}:{}'.format(self.status_for_openqa['new_snapshot'], status_flag, status_flag) + msg = 'pinned-description: Ignored issues\r\n\r\n{}\r\n\r\n{}'.format(issues, status_msg) data = {'text': msg} url = makeurl(self.openqa_server, @@ -307,24 +307,24 @@ class ToTestBase(object): # remove flag - unfortunately can't delete comment unless admin data = {'text': text} if self.dryrun: - logger.info("Would label {} with: {}".format(job['id'], text)) + logger.info('Would label {} with: {}'.format(job['id'], text)) else: self.openqa.openqa_request( 'PUT', 'jobs/%s/comments/%d' % (job['id'], labeled), data=data) - logger.info("job %s failed, but was ignored", job['name']) + logger.info('job %s failed, but was ignored', job['name']) else: self.failed_relevant_jobs.append(job['id']) if not labeled and len(refs) > 0: data = {'text': 'label:unknown_failure'} if self.dryrun: - logger.info("Would label {} as unknown".format(job['id'])) + logger.info('Would label {} as unknown'.format(job['id'])) else: self.openqa.openqa_request( 'POST', 'jobs/%s/comments' % job['id'], data=data) joburl = '%s/tests/%s' % (self.openqa_server, job['id']) - logger.info("job %s failed, see %s", job['name'], joburl) + logger.info('job %s failed, see %s', job['name'], joburl) elif job['result'] == 'passed' or job['result'] == 'softfailed': continue @@ -416,7 +416,7 @@ class ToTestBase(object): f = self.api.retried_GET(url) root = ET.parse(f).getroot() # [@code!='succeeded'] is not supported by ET - failed = [status for status in root.findall("result/status") if status.get('code') != 'succeeded'] + failed = [status for status in root.findall('result/status') if status.get('code') != 'succeeded'] if any(failed): logger.info( @@ -487,7 +487,7 @@ class ToTestBase(object): builds.add(self.iso_build_version(self.project, p.package, arch=arch)) if len(builds) != 1: - logger.debug("not all medias have the same build number") + logger.debug('not all medias have the same build number') return False return True @@ -515,7 +515,7 @@ class ToTestBase(object): url = self.api.makeurl(baseurl, query=query) if self.dryrun or self.norelease: - logger.info("release %s/%s (%s)" % (project, package, query)) + logger.info('release %s/%s (%s)' % (project, package, query)) else: self.api.retried_POST(url) @@ -608,12 +608,12 @@ class ToTestBase(object): logger.debug('current_qa_version %s', current_qa_version) snapshotable = self.is_snapshottable() - logger.debug("snapshotable: %s", snapshotable) + logger.debug('snapshotable: %s', snapshotable) can_release = ((current_snapshot is None or current_result != QA_INPROGRESS) and snapshotable) # not overwriting if new_snapshot == current_qa_version: - logger.debug("no change in snapshot version") + logger.debug('no change in snapshot version') can_release = False elif not self.all_repos_done(self.test_project): logger.debug("not all repos done, can't release") @@ -628,7 +628,7 @@ class ToTestBase(object): # already published totest_is_publishing = self.totest_is_publishing() if totest_is_publishing: - logger.debug("totest already publishing") + logger.debug('totest already publishing') can_publish = False if self.update_pinned_descr: @@ -644,18 +644,18 @@ class ToTestBase(object): if can_publish: if current_qa_version == current_snapshot: self.publish_factory_totest() - self.write_version_to_dashboard("snapshot", current_snapshot) + self.write_version_to_dashboard('snapshot', current_snapshot) can_release = False # we have to wait else: # We reached a very bad status: openQA testing is 'done', but not of the same version # currently in test project. This can happen when 'releasing' the # product failed - raise Exception("Publishing stopped: tested version (%s) does not match version in test project (%s)" + raise Exception('Publishing stopped: tested version (%s) does not match version in test project (%s)' % (current_qa_version, current_snapshot)) if can_release: self.update_totest(new_snapshot) - self.write_version_to_dashboard("totest", new_snapshot) + self.write_version_to_dashboard('totest', new_snapshot) def send_amqp_event(self, current_snapshot, current_result): if not self.amqp_url: @@ -663,7 +663,7 @@ class ToTestBase(object): return logger.debug('Sending AMQP message') - inf = re.sub(r"ed$", '', self._result2str(current_result)) + inf = re.sub(r'ed$', '', self._result2str(current_result)) msg_topic = '%s.ttm.build.%s' % (self.project_base.lower(), inf) msg_body = json.dumps({ 'build': current_snapshot, @@ -1060,18 +1060,18 @@ class CommandlineInterface(cmdln.Cmdln): def get_optparser(self): parser = cmdln.CmdlnOptionParser(self) - parser.add_option("--dry", action="store_true", help="dry run") - parser.add_option("--debug", action="store_true", help="debug output") - parser.add_option("--release", action="store_true", help="trigger release in build service (default for openSUSE)") - parser.add_option("--norelease", action="store_true", help="do not trigger release in build service (default for SLE)") - parser.add_option("--verbose", action="store_true", help="verbose") + parser.add_option('--dry', action='store_true', help='dry run') + parser.add_option('--debug', action='store_true', help='debug output') + parser.add_option('--release', action='store_true', help='trigger release in build service (default for openSUSE)') + parser.add_option('--norelease', action='store_true', help='do not trigger release in build service (default for SLE)') + parser.add_option('--verbose', action='store_true', help='verbose') parser.add_option( - "--osc-debug", action="store_true", help="osc debug output") + '--osc-debug', action='store_true', help='osc debug output') parser.add_option( - "--openqa-server", help="""Full URL to the openQA server that should be queried, default based on project selection, e.g. + '--openqa-server', help="""Full URL to the openQA server that should be queried, default based on project selection, e.g. 'https://openqa.opensuse.org' for 'openSUSE'""") parser.add_option( - "--obs-api-url", help="""Full URL to OBS instance to be queried, default based on project selection, e.g. + '--obs-api-url', help="""Full URL to OBS instance to be queried, default based on project selection, e.g. 'https://api.opensuse.org' for 'openSUSE'""") return parser @@ -1139,6 +1139,6 @@ class CommandlineInterface(cmdln.Cmdln): totest.release() -if __name__ == "__main__": +if __name__ == '__main__': app = CommandlineInterface() sys.exit(app.main()) From dc932a67d7446ae0eef7e52b1bc3ff4daa7e1926 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 17:35:23 +0100 Subject: [PATCH 11/20] Make is_image_product a config --- totest-manager.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index d4017934..222c2032 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -129,6 +129,9 @@ class ToTestBase(object): raise Exception('No idea where to take the source version from') if self.take_source_from_product: + if self.is_image_product: + return self.iso_build_version(self.project, self.image_products[0].package, + arch=self.image_products[0].archs[0]) return self.iso_build_version(self.project, self.main_products[0]) else: return self.release_version() @@ -153,6 +156,9 @@ class ToTestBase(object): return ret def get_current_snapshot(self): + if self.is_image_product: + return self.iso_build_version(self.test_project, self.image_products[0].package, + arch=self.image_products[0].archs[0]) return self.iso_build_version(self.test_project, self.main_products[0]) def ftp_build_version(self, project, tree): @@ -170,7 +176,11 @@ class ToTestBase(object): raise NotFoundException("can't find %s iso version" % project) def current_qa_version(self): - return self.api.pseudometa_file_load('version_totest') + version_file = 'version_totest' + if self.is_image_product: + version_file = 'version_totest_images' + + return self.api.pseudometa_file_load(version_file) def find_openqa_results(self, snapshot): """Return the openqa jobs of a given snapshot and filter out the @@ -694,9 +704,11 @@ class ToTestBase(object): self.update_totest(new_snapshot) def write_version_to_dashboard(self, target, version): + version_file = 'version_%s' % target + if self.is_image_product: + version_file = version_file + '_images' if not (self.dryrun or self.norelease): - self.api.pseudometa_file_ensure('version_%s' % target, version, comment='Update version') - + self.api.pseudometa_file_ensure(version_file, version, comment='Update version') class ToTestFactory(ToTestBase): main_products = ['000product:openSUSE-dvd5-dvd-i586', @@ -928,23 +940,11 @@ class ToTest150Images(ToTestBase): set_snapshot_number = True take_source_from_product = True + is_image_product = True + def openqa_group(self): return 'openSUSE Leap 15.0 Images' - def current_qa_version(self): - return self.api.pseudometa_file_load('version_totest_images') - - def write_version_to_dashboard(self, target, version): - super(ToTest150Images, self).write_version_to_dashboard('{}_images'.format(target), version) - - def current_sources(self): - return self.iso_build_version(self.project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - - def get_current_snapshot(self): - return self.iso_build_version(self.test_project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - def jobs_num(self): return 13 From 55301c87ae5815b7ee375601945b42de05d7b949 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 17:35:57 +0100 Subject: [PATCH 12/20] Stop the fallback - we pass the real project name --- totest-manager.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/totest-manager.py b/totest-manager.py index 222c2032..77411c29 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -1093,10 +1093,6 @@ class CommandlineInterface(cmdln.Cmdln): osc.conf.config['debug'] = True def _setup_totest(self, project): - fallback_project = 'openSUSE:%s' % project - if project not in self.totest_class and fallback_project in self.totest_class: - project = fallback_project - project_base = project.split(':')[0] if not self.options.openqa_server: self.options.openqa_server = self.openqa_server[project_base] From e66d5054d763b683c2dfa2dbcff6a57872ea4ec3 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Mon, 25 Mar 2019 14:09:56 +0100 Subject: [PATCH 13/20] Add config --- totest-manager.py | 39 ++++++++- ttm/config/SUSE:SLE-12-SP4:GA.yaml | 19 +++++ ttm/config/SUSE:SLE-15-SP1:GA.yaml | 19 +++++ ttm/config/SUSE:SLE-15:GA.yaml | 19 +++++ ttm/config/openSUSE:Factory.yaml | 81 +++++++++++++++++++ ttm/config/openSUSE:Factory:ARM.yaml | 31 +++++++ ttm/config/openSUSE:Factory:PowerPC.yaml | 23 ++++++ ttm/config/openSUSE:Factory:zSystems.yaml | 13 +++ ttm/config/openSUSE:Leap:15.0:Images.yaml | 31 +++++++ ttm/config/openSUSE:Leap:15.0:Ports.yaml | 16 ++++ ttm/config/openSUSE:Leap:15.1.yaml | 15 ++++ ttm/config/openSUSE:Leap:15.1:ARM.yaml | 15 ++++ ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml | 18 +++++ ttm/config/openSUSE:Leap:15.1:Images.yaml | 32 ++++++++ ttm/config/openSUSE:Leap:15.1:PowerPC.yaml | 14 ++++ 15 files changed, 382 insertions(+), 3 deletions(-) create mode 100644 ttm/config/SUSE:SLE-12-SP4:GA.yaml create mode 100644 ttm/config/SUSE:SLE-15-SP1:GA.yaml create mode 100644 ttm/config/SUSE:SLE-15:GA.yaml create mode 100644 ttm/config/openSUSE:Factory.yaml create mode 100644 ttm/config/openSUSE:Factory:ARM.yaml create mode 100644 ttm/config/openSUSE:Factory:PowerPC.yaml create mode 100644 ttm/config/openSUSE:Factory:zSystems.yaml create mode 100644 ttm/config/openSUSE:Leap:15.0:Images.yaml create mode 100644 ttm/config/openSUSE:Leap:15.0:Ports.yaml create mode 100644 ttm/config/openSUSE:Leap:15.1.yaml create mode 100644 ttm/config/openSUSE:Leap:15.1:ARM.yaml create mode 100644 ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml create mode 100644 ttm/config/openSUSE:Leap:15.1:Images.yaml create mode 100644 ttm/config/openSUSE:Leap:15.1:PowerPC.yaml diff --git a/totest-manager.py b/totest-manager.py index 77411c29..d046f22f 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -63,6 +63,10 @@ class ToTestBase(object): """Base class to store the basic interface""" + need_same_build_number = False + set_snapshot_number = False + is_image_product = False + product_repo = 'images' product_arch = 'local' livecd_repo = 'images' @@ -82,9 +86,10 @@ class ToTestBase(object): api_url = osc.conf.config['apiurl'] self.api = StagingAPI(api_url, project=project) self.openqa_server = openqa_server + self.test_subproject = test_subproject if not test_subproject: - test_subproject = 'ToTest' - self.test_project = '%s:%s' % (self.project, test_subproject) + self.test_subproject = 'ToTest' + self.test_project = '%s:%s' % (self.project, self.test_subproject) self.openqa = OpenQA_Client(server=openqa_server) self.load_issues_to_ignore() self.project_base = project.split(':')[0] @@ -124,6 +129,9 @@ class ToTestBase(object): raise NotFoundException("can't find %s version" % self.project) + def arch(self): + return None + def current_sources(self): if self.take_source_from_product is None: raise Exception('No idea where to take the source version from') @@ -1114,6 +1122,12 @@ class CommandlineInterface(cmdln.Cmdln): return self.totest_class[project](project, self.options.dry, not release, self.options.obs_api_url, self.options.openqa_server) + def convert_image_products(self, arr): + ret = [] + for product in arr: + ret.append({product.package: product.archs}) + return ret + def do_run(self, subcmd, opts, project='openSUSE:Factory'): """${cmd_name}: run the ToTest Manager @@ -1122,7 +1136,26 @@ class CommandlineInterface(cmdln.Cmdln): """ totest = self._setup_totest(project) - totest.totest() + products = {'main': totest.main_products} + products['ftp'] = totest.ftp_products + products['livecds'] = self.convert_image_products(totest.livecd_products) + products['images'] = self.convert_image_products(totest.image_products) + products['container'] = self.convert_image_products(totest.container_products) + + hash = { 'products': products } + hash['openqa_group'] = totest.openqa_group() + hash['take_source_from_product'] = totest.take_source_from_product + hash['arch'] = totest.arch() + hash['jobs_num'] = totest.jobs_num() + hash['need_same_build_number'] = totest.need_same_build_number + hash['set_snapshot_number'] = totest.set_snapshot_number + hash['product_repo'] = totest.product_repo + hash['is_image_product'] = totest.is_image_product + hash['test_subproject'] = totest.test_subproject + hash['openqa_server'] = totest.openqa_server + + print(yaml.dump(hash, default_flow_style=False)) + #totest.totest() def do_release(self, subcmd, opts, project='openSUSE:Factory'): """${cmd_name}: manually release all media. Use with caution! diff --git a/ttm/config/SUSE:SLE-12-SP4:GA.yaml b/ttm/config/SUSE:SLE-12-SP4:GA.yaml new file mode 100644 index 00000000..cf1a0cdd --- /dev/null +++ b/ttm/config/SUSE:SLE-12-SP4:GA.yaml @@ -0,0 +1,19 @@ +jobs_num: 70 +need_same_build_number: true +openqa_group: Functional +openqa_server: https://openqa.suse.de +product_repo: images +products: + ftp: + - _product:SLES-ftp-POOL-aarch64 + - _product:SLES-ftp-POOL-ppc64le + - _product:SLES-ftp-POOL-s390x + - _product:SLES-ftp-POOL-x86_64 + main: + - _product:SLES-dvd5-DVD-aarch64 + - _product:SLES-dvd5-DVD-ppc64le + - _product:SLES-dvd5-DVD-s390x + - _product:SLES-dvd5-DVD-x86_64 +take_source_from_product: true +test_subproject: TEST + diff --git a/ttm/config/SUSE:SLE-15-SP1:GA.yaml b/ttm/config/SUSE:SLE-15-SP1:GA.yaml new file mode 100644 index 00000000..08f86c73 --- /dev/null +++ b/ttm/config/SUSE:SLE-15-SP1:GA.yaml @@ -0,0 +1,19 @@ +jobs_num: 70 +need_same_build_number: true +openqa_group: Functional +openqa_server: https://openqa.suse.de +product_repo: images +products: + ftp: + - 000product:SLES-ftp-POOL-aarch64 + - 000product:SLES-ftp-POOL-ppc64le + - 000product:SLES-ftp-POOL-s390x + - 000product:SLES-ftp-POOL-x86_64 + main: + - 000product:SLES-cd-DVD-aarch64 + - 000product:SLES-cd-DVD-ppc64le + - 000product:SLES-cd-DVD-s390x + - 000product:SLES-cd-DVD-x86_64 +take_source_from_product: true +test_subproject: TEST + diff --git a/ttm/config/SUSE:SLE-15:GA.yaml b/ttm/config/SUSE:SLE-15:GA.yaml new file mode 100644 index 00000000..08f86c73 --- /dev/null +++ b/ttm/config/SUSE:SLE-15:GA.yaml @@ -0,0 +1,19 @@ +jobs_num: 70 +need_same_build_number: true +openqa_group: Functional +openqa_server: https://openqa.suse.de +product_repo: images +products: + ftp: + - 000product:SLES-ftp-POOL-aarch64 + - 000product:SLES-ftp-POOL-ppc64le + - 000product:SLES-ftp-POOL-s390x + - 000product:SLES-ftp-POOL-x86_64 + main: + - 000product:SLES-cd-DVD-aarch64 + - 000product:SLES-cd-DVD-ppc64le + - 000product:SLES-cd-DVD-s390x + - 000product:SLES-cd-DVD-x86_64 +take_source_from_product: true +test_subproject: TEST + diff --git a/ttm/config/openSUSE:Factory.yaml b/ttm/config/openSUSE:Factory.yaml new file mode 100644 index 00000000..bbc4ddfb --- /dev/null +++ b/ttm/config/openSUSE:Factory.yaml @@ -0,0 +1,81 @@ +arch: x86_64 +jobs_num: 70 +openqa_group: openSUSE Tumbleweed +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + container: + - opensuse-tumbleweed-image:docker: + - i586 + - x86_64 + - kubic-kured-image: + - x86_64 + - kubic-pause-image: + - i586 + - x86_64 + ftp: + - 000product:openSUSE-ftp-ftp-i586_x86_64 + - 000product:openSUSE-Addon-NonOss-ftp-ftp-i586_x86_64 + images: + - opensuse-tumbleweed-image:lxc: + - i586 + - x86_64 + - openSUSE-Tumbleweed-JeOS:MS-HyperV: + - x86_64 + - openSUSE-Tumbleweed-JeOS:OpenStack-Cloud: + - x86_64 + - openSUSE-Tumbleweed-JeOS:VMware: + - x86_64 + - openSUSE-Tumbleweed-JeOS:XEN: + - x86_64 + - openSUSE-Tumbleweed-JeOS:kvm-and-xen: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-MS-HyperV: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-MS-HyperV: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-OpenStack-Cloud: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-OpenStack-Cloud: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-VMware: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-VMware: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-Vagrant-x86_64: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-Vagrant-x86_64: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-XEN: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-XEN: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-hardware-x86_64: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-hardware-x86_64: + - x86_64 + - openSUSE-Tumbleweed-Kubic:MicroOS-podman-kvm-and-xen: + - x86_64 + - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-kvm-and-xen: + - x86_64 + livecds: + - livecd-tumbleweed-kde: + - i586 + - x86_64 + - livecd-tumbleweed-gnome: + - i586 + - x86_64 + - livecd-tumbleweed-x11: + - i586 + - x86_64 + - livecd-tumbleweed-xfce: + - i586 + - x86_64 + main: + - 000product:openSUSE-dvd5-dvd-i586 + - 000product:openSUSE-dvd5-dvd-x86_64 + - 000product:openSUSE-cd-mini-i586 + - 000product:openSUSE-cd-mini-x86_64 + - 000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-x86_64 +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Factory:ARM.yaml b/ttm/config/openSUSE:Factory:ARM.yaml new file mode 100644 index 00000000..10b3cabb --- /dev/null +++ b/ttm/config/openSUSE:Factory:ARM.yaml @@ -0,0 +1,31 @@ +arch: aarch64 +jobs_num: 2 +openqa_group: openSUSE Tumbleweed AArch64 +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + container: + - opensuse-tumbleweed-image:docker: + - aarch64 + - kubic-kured-image: + - aarch64 + - kubic-pause-image: + - aarch64 + ftp: + - 000product:openSUSE-ftp-ftp-aarch64 + - 000product:openSUSE-ftp-ftp-armv7hl + - 000product:openSUSE-ftp-ftp-armv6hl + images: + - opensuse-tumbleweed-image:lxc: + - armv6l + - armv7l + - aarch64 + livecds: + - JeOS: + - armv7l + main: + - 000product:openSUSE-cd-mini-aarch64 + - 000product:openSUSE-dvd5-dvd-aarch64 + - 000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-aarch64 +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Factory:PowerPC.yaml b/ttm/config/openSUSE:Factory:PowerPC.yaml new file mode 100644 index 00000000..ac5a54ea --- /dev/null +++ b/ttm/config/openSUSE:Factory:PowerPC.yaml @@ -0,0 +1,23 @@ +arch: ppc64le +jobs_num: 4 +openqa_group: openSUSE Tumbleweed PowerPC +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + container: + - opensuse-tumbleweed-image:docker: + - ppc64le + - kubic-kured-image: + - ppc64le + - kubic-pause-image: + - ppc64le + ftp: + - 000product:openSUSE-ftp-ftp-ppc64_ppc64le + images: + - opensuse-tumbleweed-image:lxc: + - ppc64le + main: + - 000product:openSUSE-dvd5-dvd-ppc64le + - 000product:openSUSE-cd-mini-ppc64le +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Factory:zSystems.yaml b/ttm/config/openSUSE:Factory:zSystems.yaml new file mode 100644 index 00000000..ef01212a --- /dev/null +++ b/ttm/config/openSUSE:Factory:zSystems.yaml @@ -0,0 +1,13 @@ +arch: s390x +jobs_num: 1 +openqa_group: openSUSE Tumbleweed s390x +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + ftp: + - 000product:openSUSE-ftp-ftp-s390x + main: + - 000product:openSUSE-dvd5-dvd-s390x + - 000product:openSUSE-cd-mini-s390x +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.0:Images.yaml b/ttm/config/openSUSE:Leap:15.0:Images.yaml new file mode 100644 index 00000000..cf82d70a --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.0:Images.yaml @@ -0,0 +1,31 @@ +is_image_product: true +jobs_num: 13 +openqa_group: openSUSE Leap 15.0 Images +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + images: + - livecd-leap-gnome: + - x86_64 + - livecd-leap-kde: + - x86_64 + - livecd-leap-x11: + - x86_64 + - opensuse-leap-image:docker: + - x86_64 + - opensuse-leap-image:lxc: + - x86_64 + - kiwi-templates-Leap15-JeOS:MS-HyperV: + - x86_64 + - kiwi-templates-Leap15-JeOS:OpenStack-Cloud: + - x86_64 + - kiwi-templates-Leap15-JeOS:VMware: + - x86_64 + - kiwi-templates-Leap15-JeOS:XEN: + - x86_64 + - kiwi-templates-Leap15-JeOS:kvm-and-xen: + - x86_64 +set_snapshot_number: true +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.0:Ports.yaml b/ttm/config/openSUSE:Leap:15.0:Ports.yaml new file mode 100644 index 00000000..5912d0dd --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.0:Ports.yaml @@ -0,0 +1,16 @@ +jobs_num: 10 +need_same_build_number: true +openqa_group: openSUSE Leap 15.0 AArch64 +openqa_server: https://openqa.opensuse.org +product_repo: images_arm +products: + ftp: + - 000product:openSUSE-ftp-ftp-aarch64 + - 000product:openSUSE-ftp-ftp-armv7hl + main: + - 000product:openSUSE-cd-mini-aarch64 + - 000product:openSUSE-dvd5-dvd-aarch64 +set_snapshot_number: true +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.1.yaml b/ttm/config/openSUSE:Leap:15.1.yaml new file mode 100644 index 00000000..b2185168 --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.1.yaml @@ -0,0 +1,15 @@ +jobs_num: 70 +need_same_build_number: true +openqa_group: openSUSE Leap 15 +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + ftp: + - 000product:openSUSE-ftp-ftp-x86_64 + - 000product:openSUSE-Addon-NonOss-ftp-ftp-x86_64 + main: + - 000product:openSUSE-cd-mini-x86_64 + - 000product:openSUSE-dvd5-dvd-x86_64 +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.1:ARM.yaml b/ttm/config/openSUSE:Leap:15.1:ARM.yaml new file mode 100644 index 00000000..ef769a7f --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.1:ARM.yaml @@ -0,0 +1,15 @@ +jobs_num: 10 +need_same_build_number: true +openqa_group: openSUSE Leap 15 AArch64 +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + ftp: + - 000product:openSUSE-ftp-ftp-aarch64 + - 000product:openSUSE-ftp-ftp-armv7hl + main: + - 000product:openSUSE-cd-mini-aarch64 + - 000product:openSUSE-dvd5-dvd-aarch64 +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml b/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml new file mode 100644 index 00000000..49f741af --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml @@ -0,0 +1,18 @@ +is_image_product: true +jobs_num: 2 +openqa_group: openSUSE Leap 15.1 AArch64 Images +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + container: + - opensuse-leap-image:docker: + - aarch64 + images: + - JeOS:JeOS-efi.aarch64: + - aarch64 + - JeOS: + - armv7l +set_snapshot_number: true +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.1:Images.yaml b/ttm/config/openSUSE:Leap:15.1:Images.yaml new file mode 100644 index 00000000..89033e6c --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.1:Images.yaml @@ -0,0 +1,32 @@ +is_image_product: true +jobs_num: 13 +openqa_group: openSUSE Leap 15.1 Images +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + container: + - opensuse-leap-image:docker: + - x86_64 + images: + - livecd-leap-gnome: + - x86_64 + - livecd-leap-kde: + - x86_64 + - livecd-leap-x11: + - x86_64 + - opensuse-leap-image:lxc: + - x86_64 + - openSUSE-Leap-15.1-JeOS:MS-HyperV: + - x86_64 + - openSUSE-Leap-15.1-JeOS:OpenStack-Cloud: + - x86_64 + - openSUSE-Leap-15.1-JeOS:VMware: + - x86_64 + - openSUSE-Leap-15.1-JeOS:XEN: + - x86_64 + - openSUSE-Leap-15.1-JeOS:kvm-and-xen: + - x86_64 +set_snapshot_number: true +take_source_from_product: true +test_subproject: ToTest + diff --git a/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml b/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml new file mode 100644 index 00000000..ca8de86d --- /dev/null +++ b/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml @@ -0,0 +1,14 @@ +jobs_num: 10 +need_same_build_number: true +openqa_group: openSUSE Leap 15 PowerPC +openqa_server: https://openqa.opensuse.org +product_repo: images +products: + ftp: + - 000product:openSUSE-ftp-ftp-ppc64le + main: + - 000product:openSUSE-cd-mini-ppc64le + - 000product:openSUSE-dvd5-dvd-ppc64le +take_source_from_product: true +test_subproject: ToTest + From bb438bde4fe1608cf1999eb7bb8c9be60f57db2a Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Tue, 26 Mar 2019 07:51:53 +0100 Subject: [PATCH 14/20] Split totest manager into multiple files --- totest-manager.py | 1173 +---------------- ttm/__init__.py | 0 ttm/cli.py | 51 + ...12-SP4:GA.yaml => SUSE:SLE-12-SP5:GA.yaml} | 2 +- ttm/config/SUSE:SLE-15-SP1:GA.yaml | 2 +- ttm/config/SUSE:SLE-15:GA.yaml | 19 - ttm/manager.py | 658 +++++++++ ttm/totest.py | 47 + 8 files changed, 762 insertions(+), 1190 deletions(-) create mode 100644 ttm/__init__.py create mode 100755 ttm/cli.py rename ttm/config/{SUSE:SLE-12-SP4:GA.yaml => SUSE:SLE-12-SP5:GA.yaml} (95%) delete mode 100644 ttm/config/SUSE:SLE-15:GA.yaml create mode 100644 ttm/manager.py create mode 100755 ttm/totest.py diff --git a/totest-manager.py b/totest-manager.py index d046f22f..3086465b 100755 --- a/totest-manager.py +++ b/totest-manager.py @@ -1,1173 +1,8 @@ -#!/usr/bin/python2 -# -*- coding: utf-8 -*- -# -# (C) 2014 mhrusecky@suse.cz, openSUSE.org -# (C) 2014 tchvatal@suse.cz, openSUSE.org -# (C) 2014 aplanas@suse.de, openSUSE.org -# (C) 2014 coolo@suse.de, openSUSE.org -# (C) 2017 okurz@suse.de, openSUSE.org -# (C) 2018 dheidler@suse.de, openSUSE.org -# Distribute under GPLv2 or GPLv3 +#!/usr/bin/python -from __future__ import print_function +from ttm.cli import CommandLineInterface -import datetime -import json -import logging -import os -import re -import signal import sys -import time -from xml.etree import cElementTree as ET -import cmdln - -from openqa_client.client import OpenQA_Client - -import osc -from osc.core import makeurl - -from osclib.conf import Config -from osclib.stagingapi import StagingAPI - -import pika - -import yaml - -try: - from urllib.error import HTTPError -except ImportError: - # python 2.x - from urllib2 import HTTPError - -logger = logging.getLogger() - -# QA Results -QA_INPROGRESS = 1 -QA_FAILED = 2 -QA_PASSED = 3 - - -class NotFoundException(Exception): - pass - - -class ImageProduct(object): - def __init__(self, package, archs): - self.package = package - self.archs = archs - - -class ToTestBase(object): - - """Base class to store the basic interface""" - - need_same_build_number = False - set_snapshot_number = False - is_image_product = False - - product_repo = 'images' - product_arch = 'local' - livecd_repo = 'images' - totest_container_repo = 'containers' - - main_products = [] - ftp_products = [] - container_products = [] - livecd_products = [] - image_products = [] - - def __init__(self, project, dryrun=False, norelease=False, api_url=None, openqa_server='https://openqa.opensuse.org', test_subproject=None): - self.project = project - self.dryrun = dryrun - self.norelease = norelease - if not api_url: - api_url = osc.conf.config['apiurl'] - self.api = StagingAPI(api_url, project=project) - self.openqa_server = openqa_server - self.test_subproject = test_subproject - if not test_subproject: - self.test_subproject = 'ToTest' - self.test_project = '%s:%s' % (self.project, self.test_subproject) - self.openqa = OpenQA_Client(server=openqa_server) - self.load_issues_to_ignore() - self.project_base = project.split(':')[0] - self.update_pinned_descr = False - self.amqp_url = osc.conf.config.get('ttm_amqp_url') - - def load_issues_to_ignore(self): - text = self.api.attribute_value_load('IgnoredIssues') - if text: - root = yaml.safe_load(text) - self.issues_to_ignore = root.get('last_seen') - else: - self.issues_to_ignore = dict() - - def save_issues_to_ignore(self): - if self.dryrun: - return - text = yaml.dump({'last_seen': self.issues_to_ignore}, default_flow_style=False) - self.api.attribute_value_save('IgnoredIssues', text) - - def openqa_group(self): - return self.project - - def jobs_num(self): - return 70 - - def release_version(self): - url = self.api.makeurl(['build', self.project, 'standard', self.arch(), - '000release-packages:%s-release' % self.project_base]) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - for binary in root.findall('binary'): - binary = binary.get('filename', '') - result = re.match(r'.*-([^-]*)-[^-]*.src.rpm', binary) - if result: - return result.group(1) - - raise NotFoundException("can't find %s version" % self.project) - - def arch(self): - return None - - def current_sources(self): - if self.take_source_from_product is None: - raise Exception('No idea where to take the source version from') - - if self.take_source_from_product: - if self.is_image_product: - return self.iso_build_version(self.project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - return self.iso_build_version(self.project, self.main_products[0]) - else: - return self.release_version() - - def binaries_of_product(self, project, product, repo=None, arch=None): - if repo is None: - repo = self.product_repo - if arch is None: - arch = self.product_arch - - url = self.api.makeurl(['build', project, repo, arch, product]) - try: - f = self.api.retried_GET(url) - except HTTPError: - return [] - - ret = [] - root = ET.parse(f).getroot() - for binary in root.findall('binary'): - ret.append(binary.get('filename')) - - return ret - - def get_current_snapshot(self): - if self.is_image_product: - return self.iso_build_version(self.test_project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - return self.iso_build_version(self.test_project, self.main_products[0]) - - def ftp_build_version(self, project, tree): - for binary in self.binaries_of_product(project, tree): - result = re.match(r'.*-Build(.*)-Media1.report', binary) - if result: - return result.group(1) - raise NotFoundException("can't find %s ftp version" % project) - - def iso_build_version(self, project, tree, repo=None, arch=None): - for binary in self.binaries_of_product(project, tree, repo=repo, arch=arch): - result = re.match(r'.*-(?:Build|Snapshot)([0-9.]+)(?:-Media.*\.iso|\.docker\.tar\.xz|\.raw\.xz)', binary) - if result: - return result.group(1) - raise NotFoundException("can't find %s iso version" % project) - - def current_qa_version(self): - version_file = 'version_totest' - if self.is_image_product: - version_file = 'version_totest_images' - - return self.api.pseudometa_file_load(version_file) - - def find_openqa_results(self, snapshot): - """Return the openqa jobs of a given snapshot and filter out the - cloned jobs - - """ - - url = makeurl(self.openqa_server, - ['api', 'v1', 'jobs'], {'group': self.openqa_group(), 'build': snapshot, 'latest': 1}) - f = self.api.retried_GET(url) - jobs = [] - for job in json.load(f)['jobs']: - if job['clone_id'] or job['result'] == 'obsoleted': - continue - job['name'] = job['name'].replace(snapshot, '') - jobs.append(job) - return jobs - - def _result2str(self, result): - if result == QA_INPROGRESS: - return 'inprogress' - elif result == QA_FAILED: - return 'failed' - else: - return 'passed' - - def find_failed_module(self, testmodules): - # print json.dumps(testmodules, sort_keys=True, indent=4) - for module in testmodules: - if module['result'] != 'failed': - continue - flags = module['flags'] - if 'fatal' in flags or 'important' in flags: - return module['name'] - break - logger.info('%s %s %s' % - (module['name'], module['result'], module['flags'])) - - def update_openqa_status_message(self): - url = makeurl(self.openqa_server, - ['api', 'v1', 'job_groups']) - f = self.api.retried_GET(url) - job_groups = json.load(f) - group_id = 0 - for jg in job_groups: - if jg['name'] == self.openqa_group(): - group_id = jg['id'] - break - - if not group_id: - logger.debug('No openQA group id found for status comment update, ignoring') - return - - pinned_ignored_issue = 0 - issues = ' , '.join(self.issues_to_ignore.keys()) - status_flag = 'publishing' if self.status_for_openqa['is_publishing'] else \ - 'preparing' if self.status_for_openqa['can_release'] else \ - 'testing' if self.status_for_openqa['snapshotable'] else \ - 'building' - status_msg = 'tag:{}:{}:{}'.format(self.status_for_openqa['new_snapshot'], status_flag, status_flag) - msg = 'pinned-description: Ignored issues\r\n\r\n{}\r\n\r\n{}'.format(issues, status_msg) - data = {'text': msg} - - url = makeurl(self.openqa_server, - ['api', 'v1', 'groups', str(group_id), 'comments']) - f = self.api.retried_GET(url) - comments = json.load(f) - for comment in comments: - if comment['userName'] == 'ttm' and \ - comment['text'].startswith('pinned-description: Ignored issues'): - pinned_ignored_issue = comment['id'] - - logger.debug('Writing openQA status message: {}'.format(data)) - if not self.dryrun: - if pinned_ignored_issue: - self.openqa.openqa_request( - 'PUT', 'groups/%s/comments/%d' % (group_id, pinned_ignored_issue), data=data) - else: - self.openqa.openqa_request( - 'POST', 'groups/%s/comments' % group_id, data=data) - - def overall_result(self, snapshot): - """Analyze the openQA jobs of a given snapshot Returns a QAResult""" - - if snapshot is None: - return QA_FAILED - - jobs = self.find_openqa_results(snapshot) - - self.failed_relevant_jobs = [] - self.failed_ignored_jobs = [] - - if len(jobs) < self.jobs_num(): # not yet scheduled - logger.warning('we have only %s jobs' % len(jobs)) - return QA_INPROGRESS - - in_progress = False - for job in jobs: - # print json.dumps(job, sort_keys=True, indent=4) - if job['result'] in ('failed', 'incomplete', 'skipped', 'user_cancelled', 'obsoleted', 'parallel_failed'): - # print json.dumps(job, sort_keys=True, indent=4), jobname - url = makeurl(self.openqa_server, - ['api', 'v1', 'jobs', str(job['id']), 'comments']) - f = self.api.retried_GET(url) - comments = json.load(f) - refs = set() - labeled = 0 - to_ignore = False - for comment in comments: - for ref in comment['bugrefs']: - refs.add(str(ref)) - if comment['userName'] == 'ttm' and comment['text'] == 'label:unknown_failure': - labeled = comment['id'] - if re.search(r'@ttm:? ignore', comment['text']): - to_ignore = True - # to_ignore can happen with or without refs - ignored = True if to_ignore else len(refs) > 0 - build_nr = str(job['settings']['BUILD']) - for ref in refs: - if ref not in self.issues_to_ignore: - if to_ignore: - self.issues_to_ignore[ref] = build_nr - self.update_pinned_descr = True - else: - ignored = False - else: - # update reference - self.issues_to_ignore[ref] = build_nr - - if ignored: - self.failed_ignored_jobs.append(job['id']) - if labeled: - text = 'Ignored issue' if len(refs) > 0 else 'Ignored failure' - # remove flag - unfortunately can't delete comment unless admin - data = {'text': text} - if self.dryrun: - logger.info('Would label {} with: {}'.format(job['id'], text)) - else: - self.openqa.openqa_request( - 'PUT', 'jobs/%s/comments/%d' % (job['id'], labeled), data=data) - - logger.info('job %s failed, but was ignored', job['name']) - else: - self.failed_relevant_jobs.append(job['id']) - if not labeled and len(refs) > 0: - data = {'text': 'label:unknown_failure'} - if self.dryrun: - logger.info('Would label {} as unknown'.format(job['id'])) - else: - self.openqa.openqa_request( - 'POST', 'jobs/%s/comments' % job['id'], data=data) - - joburl = '%s/tests/%s' % (self.openqa_server, job['id']) - logger.info('job %s failed, see %s', job['name'], joburl) - - elif job['result'] == 'passed' or job['result'] == 'softfailed': - continue - elif job['result'] == 'none': - if job['state'] != 'cancelled': - in_progress = True - else: - raise Exception(job['result']) - - self.save_issues_to_ignore() - - if len(self.failed_relevant_jobs) > 0: - return QA_FAILED - - if in_progress: - return QA_INPROGRESS - - return QA_PASSED - - def all_repos_done(self, project, codes=None): - """Check the build result of the project and only return True if all - repos of that project are either published or unpublished - - """ - - # coolo's experience says that 'finished' won't be - # sufficient here, so don't try to add it :-) - codes = ['published', 'unpublished'] if not codes else codes - - url = self.api.makeurl( - ['build', project, '_result'], {'code': 'failed'}) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - ready = True - for repo in root.findall('result'): - # ignore ports. 'factory' is used by arm for repos that are not - # meant to use the totest manager. - if repo.get('repository') in ('ports', 'factory', 'images_staging'): - continue - if repo.get('dirty', '') == 'true': - logger.info('%s %s %s -> %s' % (repo.get('project'), - repo.get('repository'), repo.get('arch'), 'dirty')) - ready = False - if repo.get('code') not in codes: - logger.info('%s %s %s -> %s' % (repo.get('project'), - repo.get('repository'), repo.get('arch'), repo.get('code'))) - ready = False - return ready - - def maxsize_for_package(self, package): - if re.match(r'.*-mini-.*', package): - return 737280000 # a CD needs to match - - if re.match(r'.*-dvd5-.*', package): - return 4700372992 # a DVD needs to match - - if re.match(r'livecd-x11', package): - return 681574400 # not a full CD - - if re.match(r'livecd-.*', package): - return 999999999 # a GB stick - - if re.match(r'.*-(dvd9-dvd|cd-DVD)-.*', package): - return 8539996159 - - if re.match(r'.*-ftp-(ftp|POOL)-', package): - return None - - # containers have no size limit - if re.match(r'(opensuse|kubic)-.*-image.*', package): - return None - - if '-Addon-NonOss-ftp-ftp' in package: - return None - - if 'JeOS' in package or 'Kubic' in package: - return 4700372992 - - raise Exception('No maxsize for {}'.format(package)) - - def package_ok(self, project, package, repository, arch): - """Checks one package in a project and returns True if it's succeeded - - """ - - query = {'package': package, 'repository': repository, 'arch': arch} - - url = self.api.makeurl(['build', project, '_result'], query) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - # [@code!='succeeded'] is not supported by ET - failed = [status for status in root.findall('result/status') if status.get('code') != 'succeeded'] - - if any(failed): - logger.info( - '%s %s %s %s -> %s' % (project, package, repository, arch, failed[0].get('code'))) - return False - - if not len(root.findall('result/status[@code="succeeded"]')): - logger.info('No "succeeded" for %s %s %s %s' % (project, package, repository, arch)) - return False - - maxsize = self.maxsize_for_package(package) - if not maxsize: - return True - - url = self.api.makeurl(['build', project, repository, arch, package]) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - for binary in root.findall('binary'): - if not binary.get('filename', '').endswith('.iso'): - continue - isosize = int(binary.get('size', 0)) - if isosize > maxsize: - logger.error('%s %s %s %s: %s' % ( - project, package, repository, arch, 'too large by %s bytes' % (isosize - maxsize))) - return False - - return True - - def is_snapshottable(self): - """Check various conditions required for factory to be snapshotable - - """ - - if not self.all_repos_done(self.project): - return False - - for product in self.ftp_products + self.main_products: - if not self.package_ok(self.project, product, self.product_repo, self.product_arch): - return False - - for product in self.image_products + self.container_products: - for arch in product.archs: - if not self.package_ok(self.project, product.package, self.product_repo, arch): - return False - - if len(self.livecd_products): - if not self.all_repos_done('%s:Live' % self.project): - return False - - for product in self.livecd_products: - for arch in product.archs: - if not self.package_ok('%s:Live' % self.project, product.package, - self.product_repo, arch): - return False - - if self.need_same_build_number: - # make sure all medias have the same build number - builds = set() - for p in self.ftp_products: - if 'Addon-NonOss' in p: - # XXX: don't care about nonoss atm. - continue - builds.add(self.ftp_build_version(self.project, p)) - for p in self.main_products: - builds.add(self.iso_build_version(self.project, p)) - for p in self.livecd_products + self.image_products: - for arch in p.archs: - builds.add(self.iso_build_version(self.project, p.package, - arch=arch)) - if len(builds) != 1: - logger.debug('not all medias have the same build number') - return False - - return True - - def _release_package(self, project, package, set_release=None, repository=None, - target_project=None, target_repository=None): - if package.startswith('000product:'): - logger.debug('Ignoring to release {}'.format(package)) - return - - query = {'cmd': 'release'} - - if set_release: - query['setrelease'] = set_release - - if repository is not None: - query['repository'] = repository - - if target_project is not None: - # Both need to be set - query['target_project'] = target_project - query['target_repository'] = target_repository - - baseurl = ['source', project, package] - - url = self.api.makeurl(baseurl, query=query) - if self.dryrun or self.norelease: - logger.info('release %s/%s (%s)' % (project, package, query)) - else: - self.api.retried_POST(url) - - def _release(self, set_release=None): - # release 000product as a whole - if self.main_products[0].startswith('000product'): - self._release_package(self.project, '000product', set_release=set_release) - - for product in self.ftp_products: - self._release_package(self.project, product, repository=self.product_repo) - - for cd in self.livecd_products: - self._release_package('%s:Live' % - self.project, cd.package, set_release=set_release, - repository=self.livecd_repo) - - for image in self.image_products: - self._release_package(self.project, image.package, set_release=set_release, - repository=self.product_repo) - - for cd in self.main_products: - self._release_package(self.project, cd, set_release=set_release, - repository=self.product_repo) - - for container in self.container_products: - # Containers are built in the same repo as other image products, - # but released into a different repo in :ToTest - self._release_package(self.project, container.package, repository=self.product_repo, - target_project=self.test_project, - target_repository=self.totest_container_repo) - - def update_totest(self, snapshot=None): - # omit snapshot, we don't want to rename on release - if not self.set_snapshot_number: - snapshot = None - release = 'Snapshot%s' % snapshot if snapshot else None - logger.info('Updating snapshot %s' % snapshot) - if not (self.dryrun or self.norelease): - self.api.switch_flag_in_prj(self.test_project, flag='publish', state='disable', - repository=self.product_repo) - - self._release(set_release=release) - - def publish_factory_totest(self): - logger.info('Publish test project content') - if not (self.dryrun or self.norelease): - self.api.switch_flag_in_prj( - self.test_project, flag='publish', state='enable', - repository=self.product_repo) - if self.container_products: - logger.info('Releasing container products from ToTest') - for container in self.container_products: - self._release_package(self.test_project, container.package, - repository=self.totest_container_repo) - - def totest_is_publishing(self): - """Find out if the publishing flag is set in totest's _meta""" - - url = self.api.makeurl( - ['source', self.test_project, '_meta']) - f = self.api.retried_GET(url) - root = ET.parse(f).getroot() - if not root.find('publish'): # default true - return True - - for flag in root.find('publish'): - if flag.get('repository', None) not in [None, self.product_repo]: - continue - if flag.get('arch', None): - continue - if flag.tag == 'enable': - return True - return False - - def totest(self): - try: - current_snapshot = self.get_current_snapshot() - except NotFoundException as e: - # nothing in test project (yet) - logger.warn(e) - current_snapshot = None - new_snapshot = self.current_sources() - self.update_pinned_descr = False - current_result = self.overall_result(current_snapshot) - current_qa_version = self.current_qa_version() - - logger.info('current_snapshot %s: %s' % - (current_snapshot, self._result2str(current_result))) - logger.debug('new_snapshot %s', new_snapshot) - logger.debug('current_qa_version %s', current_qa_version) - - snapshotable = self.is_snapshottable() - logger.debug('snapshotable: %s', snapshotable) - can_release = ((current_snapshot is None or current_result != QA_INPROGRESS) and snapshotable) - - # not overwriting - if new_snapshot == current_qa_version: - logger.debug('no change in snapshot version') - can_release = False - elif not self.all_repos_done(self.test_project): - logger.debug("not all repos done, can't release") - # the repos have to be done, otherwise we better not touch them - # with a new release - can_release = False - - self.send_amqp_event(current_snapshot, current_result) - - can_publish = (current_result == QA_PASSED) - - # already published - totest_is_publishing = self.totest_is_publishing() - if totest_is_publishing: - logger.debug('totest already publishing') - can_publish = False - - if self.update_pinned_descr: - self.status_for_openqa = { - 'current_snapshot': current_snapshot, - 'new_snapshot': new_snapshot, - 'snapshotable': snapshotable, - 'can_release': can_release, - 'is_publishing': totest_is_publishing, - } - self.update_openqa_status_message() - - if can_publish: - if current_qa_version == current_snapshot: - self.publish_factory_totest() - self.write_version_to_dashboard('snapshot', current_snapshot) - can_release = False # we have to wait - else: - # We reached a very bad status: openQA testing is 'done', but not of the same version - # currently in test project. This can happen when 'releasing' the - # product failed - raise Exception('Publishing stopped: tested version (%s) does not match version in test project (%s)' - % (current_qa_version, current_snapshot)) - - if can_release: - self.update_totest(new_snapshot) - self.write_version_to_dashboard('totest', new_snapshot) - - def send_amqp_event(self, current_snapshot, current_result): - if not self.amqp_url: - logger.debug('No ttm_amqp_url configured in oscrc - skipping amqp event emission') - return - - logger.debug('Sending AMQP message') - inf = re.sub(r'ed$', '', self._result2str(current_result)) - msg_topic = '%s.ttm.build.%s' % (self.project_base.lower(), inf) - msg_body = json.dumps({ - 'build': current_snapshot, - 'project': self.project, - 'failed_jobs': { - 'relevant': self.failed_relevant_jobs, - 'ignored': self.failed_ignored_jobs, - } - }) - - # send amqp event - tries = 7 # arbitrary - for t in range(tries): - try: - notify_connection = pika.BlockingConnection(pika.URLParameters(self.amqp_url)) - notify_channel = notify_connection.channel() - notify_channel.exchange_declare(exchange='pubsub', exchange_type='topic', passive=True, durable=True) - notify_channel.basic_publish(exchange='pubsub', routing_key=msg_topic, body=msg_body) - notify_connection.close() - break - except pika.exceptions.ConnectionClosed as e: - logger.warn('Sending AMQP event did not work: %s. Retrying try %s out of %s' % (e, t, tries)) - else: - logger.error('Could not send out AMQP event for %s tries, aborting.' % tries) - - def release(self): - new_snapshot = self.current_sources() - self.update_totest(new_snapshot) - - def write_version_to_dashboard(self, target, version): - version_file = 'version_%s' % target - if self.is_image_product: - version_file = version_file + '_images' - if not (self.dryrun or self.norelease): - self.api.pseudometa_file_ensure(version_file, version, comment='Update version') - -class ToTestFactory(ToTestBase): - main_products = ['000product:openSUSE-dvd5-dvd-i586', - '000product:openSUSE-dvd5-dvd-x86_64', - '000product:openSUSE-cd-mini-i586', - '000product:openSUSE-cd-mini-x86_64', - '000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-x86_64'] - - ftp_products = ['000product:openSUSE-ftp-ftp-i586_x86_64', - '000product:openSUSE-Addon-NonOss-ftp-ftp-i586_x86_64'] - - livecd_products = [ImageProduct('livecd-tumbleweed-kde', ['i586', 'x86_64']), - ImageProduct('livecd-tumbleweed-gnome', ['i586', 'x86_64']), - ImageProduct('livecd-tumbleweed-x11', ['i586', 'x86_64']), - ImageProduct('livecd-tumbleweed-xfce', ['i586', 'x86_64'])] - - container_products = [ImageProduct('opensuse-tumbleweed-image:docker', ['i586', 'x86_64']), - ImageProduct('kubic-kured-image', ['x86_64']), - ImageProduct('kubic-pause-image', ['i586', 'x86_64'])] - - image_products = [ - ImageProduct('opensuse-tumbleweed-image:lxc', ['i586', 'x86_64']), - ImageProduct('openSUSE-Tumbleweed-JeOS:MS-HyperV', ['x86_64']), - ImageProduct('openSUSE-Tumbleweed-JeOS:OpenStack-Cloud', ['x86_64']), - ImageProduct('openSUSE-Tumbleweed-JeOS:VMware', ['x86_64']), - ImageProduct('openSUSE-Tumbleweed-JeOS:XEN', ['x86_64']), - ImageProduct('openSUSE-Tumbleweed-JeOS:kvm-and-xen', ['x86_64']), - ] + [ - ImageProduct('openSUSE-Tumbleweed-Kubic:' + flavor + '-' + platform, ['x86_64']) - for platform in - ['MS-HyperV', 'OpenStack-Cloud', 'VMware', 'Vagrant-x86_64', 'XEN', 'hardware-x86_64', 'kvm-and-xen'] - for flavor in ['MicroOS-podman', 'kubeadm-cri-o'] - ] - - take_source_from_product = False - - def __init__(self, *args, **kwargs): - ToTestBase.__init__(self, *args, **kwargs) - - def openqa_group(self): - return 'openSUSE Tumbleweed' - - def arch(self): - return 'x86_64' - - -class ToTestFactoryPowerPC(ToTestBase): - main_products = ['000product:openSUSE-dvd5-dvd-ppc64le', - '000product:openSUSE-cd-mini-ppc64le'] - - ftp_products = ['000product:openSUSE-ftp-ftp-ppc64_ppc64le'] - - image_products = [ImageProduct('opensuse-tumbleweed-image:lxc', ['ppc64le'])] - - container_products = [ImageProduct('opensuse-tumbleweed-image:docker', ['ppc64le']), - ImageProduct('kubic-kured-image', ['ppc64le']), - ImageProduct('kubic-pause-image', ['ppc64le'])] - - take_source_from_product = False - - def __init__(self, *args, **kwargs): - ToTestBase.__init__(self, *args, **kwargs) - - def openqa_group(self): - return 'openSUSE Tumbleweed PowerPC' - - def arch(self): - return 'ppc64le' - - def jobs_num(self): - return 4 - - -class ToTestFactoryzSystems(ToTestBase): - main_products = ['000product:openSUSE-dvd5-dvd-s390x', - '000product:openSUSE-cd-mini-s390x'] - - ftp_products = ['000product:openSUSE-ftp-ftp-s390x'] - - take_source_from_product = False - - def __init__(self, *args, **kwargs): - ToTestBase.__init__(self, *args, **kwargs) - - def openqa_group(self): - return 'openSUSE Tumbleweed s390x' - - def arch(self): - return 's390x' - - def jobs_num(self): - return 1 - - -class ToTestFactoryARM(ToTestFactory): - main_products = ['000product:openSUSE-cd-mini-aarch64', - '000product:openSUSE-dvd5-dvd-aarch64', - '000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-aarch64'] - - ftp_products = ['000product:openSUSE-ftp-ftp-aarch64', - '000product:openSUSE-ftp-ftp-armv7hl', - '000product:openSUSE-ftp-ftp-armv6hl'] - - livecd_products = [ImageProduct('JeOS', ['armv7l'])] - - image_products = [ImageProduct('opensuse-tumbleweed-image:lxc', ['armv6l', 'armv7l', 'aarch64'])] - - container_products = [ImageProduct('opensuse-tumbleweed-image:docker', ['aarch64']), - ImageProduct('kubic-kured-image', ['aarch64']), - ImageProduct('kubic-pause-image', ['aarch64'])] - - # JeOS doesn't follow build numbers of main isos - need_same_build_number = False - - take_source_from_product = False - - def __init__(self, *args, **kwargs): - ToTestFactory.__init__(self, *args, **kwargs) - - def openqa_group(self): - return 'openSUSE Tumbleweed AArch64' - - def arch(self): - return 'aarch64' - - def jobs_num(self): - return 2 - - -class ToTest151(ToTestBase): - - # whether all medias need to have the same build number - need_same_build_number = True - take_source_from_product = True - - # whether to set a snapshot number on release - set_snapshot_number = False - - main_products = [ - '000product:openSUSE-cd-mini-x86_64', - '000product:openSUSE-dvd5-dvd-x86_64', - ] - - ftp_products = ['000product:openSUSE-ftp-ftp-x86_64', - '000product:openSUSE-Addon-NonOss-ftp-ftp-x86_64' - ] - - def openqa_group(self): - return 'openSUSE Leap 15' - - -class ToTest151ARM(ToTest151): - main_products = [ - '000product:openSUSE-cd-mini-aarch64', - '000product:openSUSE-dvd5-dvd-aarch64', - ] - - ftp_products = ['000product:openSUSE-ftp-ftp-aarch64', - '000product:openSUSE-ftp-ftp-armv7hl', - ] - - def openqa_group(self): - return 'openSUSE Leap 15 AArch64' - - def jobs_num(self): - return 10 - - -class ToTest151PowerPC(ToTest151): - main_products = [ - '000product:openSUSE-cd-mini-ppc64le', - '000product:openSUSE-dvd5-dvd-ppc64le', - ] - - ftp_products = ['000product:openSUSE-ftp-ftp-ppc64le', - ] - - def openqa_group(self): - return 'openSUSE Leap 15 PowerPC' - - def jobs_num(self): - return 10 - -class ToTest150Ports(ToTestBase): - main_products = [ - '000product:openSUSE-cd-mini-aarch64', - '000product:openSUSE-dvd5-dvd-aarch64', - ] - - ftp_products = ['000product:openSUSE-ftp-ftp-aarch64', - '000product:openSUSE-ftp-ftp-armv7hl', - ] - - - # whether all medias need to have the same build number - need_same_build_number = True - take_source_from_product = True - - # Leap 15.0 Ports still need to update snapshot - set_snapshot_number = True - - # product_repo openqa_group jobs_num values are specific to aarch64 - # TODO: How to handle the other entries of main_products ? - - product_repo = 'images_arm' - - def openqa_group(self): - return 'openSUSE Leap 15.0 AArch64' - - def jobs_num(self): - return 10 - -class ToTest150Images(ToTestBase): - image_products = [ - ImageProduct('livecd-leap-gnome', ['x86_64']), - ImageProduct('livecd-leap-kde', ['x86_64']), - ImageProduct('livecd-leap-x11', ['x86_64']), - ImageProduct('opensuse-leap-image:docker', ['x86_64']), - ImageProduct('opensuse-leap-image:lxc', ['x86_64']), - ImageProduct('kiwi-templates-Leap15-JeOS:MS-HyperV', ['x86_64']), - ImageProduct('kiwi-templates-Leap15-JeOS:OpenStack-Cloud', ['x86_64']), - ImageProduct('kiwi-templates-Leap15-JeOS:VMware', ['x86_64']), - ImageProduct('kiwi-templates-Leap15-JeOS:XEN', ['x86_64']), - ImageProduct('kiwi-templates-Leap15-JeOS:kvm-and-xen', ['x86_64']), - ] - - # docker image has a different number - need_same_build_number = False - set_snapshot_number = True - take_source_from_product = True - - is_image_product = True - - def openqa_group(self): - return 'openSUSE Leap 15.0 Images' - - def jobs_num(self): - return 13 - - -class ToTest151Images(ToTest150Images): - image_products = [ - ImageProduct('livecd-leap-gnome', ['x86_64']), - ImageProduct('livecd-leap-kde', ['x86_64']), - ImageProduct('livecd-leap-x11', ['x86_64']), - ImageProduct('opensuse-leap-image:lxc', ['x86_64']), - ImageProduct('openSUSE-Leap-15.1-JeOS:MS-HyperV', ['x86_64']), - ImageProduct('openSUSE-Leap-15.1-JeOS:OpenStack-Cloud', ['x86_64']), - ImageProduct('openSUSE-Leap-15.1-JeOS:VMware', ['x86_64']), - ImageProduct('openSUSE-Leap-15.1-JeOS:XEN', ['x86_64']), - ImageProduct('openSUSE-Leap-15.1-JeOS:kvm-and-xen', ['x86_64']), - ] - - container_products = [ImageProduct('opensuse-leap-image:docker', ['x86_64'])] - - def openqa_group(self): - return 'openSUSE Leap 15.1 Images' - -class ToTest151ARMImages(ToTest151Images): - # JeOS uses multibuild, but listing all flavors here would be too much. Instead, list - # the multibuild container itself, which releases all binaries. - image_products = [ImageProduct('JeOS:JeOS-efi.aarch64', ['aarch64']), - ImageProduct('JeOS', ['armv7l'])] - - container_products = [ImageProduct('opensuse-leap-image:docker', ['aarch64'])] - - def openqa_group(self): - return 'openSUSE Leap 15.1 AArch64 Images' - - def jobs_num(self): - return 2 - - -class ToTestSLE(ToTestBase): - # whether to set a snapshot number on release - set_snapshot_number = False - - # whether all medias need to have the same build number - need_same_build_number = True - - take_source_from_product = True - - def __init__(self, *args, **kwargs): - ToTestBase.__init__(self, test_subproject='TEST', *args, **kwargs) - - def openqa_group(self): - return 'Functional' - -class ToTestSLE12(ToTestSLE): - main_products = [ - '_product:SLES-dvd5-DVD-aarch64', - '_product:SLES-dvd5-DVD-ppc64le', - '_product:SLES-dvd5-DVD-s390x', - '_product:SLES-dvd5-DVD-x86_64', - ] - - ftp_products = [ - '_product:SLES-ftp-POOL-aarch64', - '_product:SLES-ftp-POOL-ppc64le', - '_product:SLES-ftp-POOL-s390x', - '_product:SLES-ftp-POOL-x86_64', - ] - -class ToTestSLE15(ToTestSLE): - main_products = [ - '000product:SLES-cd-DVD-aarch64', - '000product:SLES-cd-DVD-ppc64le', - '000product:SLES-cd-DVD-s390x', - '000product:SLES-cd-DVD-x86_64', - ] - - ftp_products = [ - '000product:SLES-ftp-POOL-aarch64', - '000product:SLES-ftp-POOL-ppc64le', - '000product:SLES-ftp-POOL-s390x', - '000product:SLES-ftp-POOL-x86_64', - ] - - -class CommandlineInterface(cmdln.Cmdln): - - def __init__(self, *args, **kwargs): - cmdln.Cmdln.__init__(self, args, kwargs) - - self.totest_class = { - 'openSUSE:Factory': ToTestFactory, - 'openSUSE:Factory:PowerPC': ToTestFactoryPowerPC, - 'openSUSE:Factory:ARM': ToTestFactoryARM, - 'openSUSE:Factory:zSystems': ToTestFactoryzSystems, - 'openSUSE:Leap:15.1': ToTest151, - 'openSUSE:Leap:15.1:ARM': ToTest151ARM, - 'openSUSE:Leap:15.1:PowerPC': ToTest151PowerPC, - 'openSUSE:Leap:15.0:Ports': ToTest150Ports, - 'openSUSE:Leap:15.0:Images': ToTest150Images, - 'openSUSE:Leap:15.1:Images': ToTest151Images, - 'openSUSE:Leap:15.1:ARM:Images': ToTest151ARMImages, - 'SUSE:SLE-12-SP4:GA': ToTestSLE12, - 'SUSE:SLE-15:GA': ToTestSLE15, - 'SUSE:SLE-15-SP1:GA': ToTestSLE15, - } - self.openqa_server = { - 'openSUSE': 'https://openqa.opensuse.org', - 'SUSE': 'https://openqa.suse.de', - } - self.api_url = { - 'openSUSE': 'https://api.opensuse.org', - 'SUSE': 'https://api.suse.de', - } - - def get_optparser(self): - parser = cmdln.CmdlnOptionParser(self) - parser.add_option('--dry', action='store_true', help='dry run') - parser.add_option('--debug', action='store_true', help='debug output') - parser.add_option('--release', action='store_true', help='trigger release in build service (default for openSUSE)') - parser.add_option('--norelease', action='store_true', help='do not trigger release in build service (default for SLE)') - parser.add_option('--verbose', action='store_true', help='verbose') - parser.add_option( - '--osc-debug', action='store_true', help='osc debug output') - parser.add_option( - '--openqa-server', help="""Full URL to the openQA server that should be queried, default based on project selection, e.g. - 'https://openqa.opensuse.org' for 'openSUSE'""") - parser.add_option( - '--obs-api-url', help="""Full URL to OBS instance to be queried, default based on project selection, e.g. - 'https://api.opensuse.org' for 'openSUSE'""") - return parser - - def postoptparse(self): - level = None - if (self.options.debug): - level = logging.DEBUG - elif (self.options.verbose): - level = logging.INFO - - fmt = '%(module)s:%(lineno)d %(levelname)s %(message)s' - if os.isatty(0): - fmt = '%(asctime)s - ' + fmt - - logging.basicConfig(level=level, format=fmt) - - osc.conf.get_config() - if (self.options.osc_debug): - osc.conf.config['debug'] = True - - def _setup_totest(self, project): - project_base = project.split(':')[0] - if not self.options.openqa_server: - self.options.openqa_server = self.openqa_server[project_base] - if not self.options.obs_api_url: - self.options.obs_api_url = self.api_url[project_base] - - Config(self.options.obs_api_url, project) - if project not in self.totest_class: - msg = 'Project %s not recognized. Possible values [%s]' % ( - project, ', '.join(self.totest_class)) - raise cmdln.CmdlnUserError(msg) - - if self.options.release: - release = True - elif self.options.norelease: - release = False - else: - release = (project_base == 'openSUSE') - - return self.totest_class[project](project, self.options.dry, not release, self.options.obs_api_url, self.options.openqa_server) - - def convert_image_products(self, arr): - ret = [] - for product in arr: - ret.append({product.package: product.archs}) - return ret - - def do_run(self, subcmd, opts, project='openSUSE:Factory'): - """${cmd_name}: run the ToTest Manager - - ${cmd_usage} - ${cmd_option_list} - """ - - totest = self._setup_totest(project) - products = {'main': totest.main_products} - products['ftp'] = totest.ftp_products - products['livecds'] = self.convert_image_products(totest.livecd_products) - products['images'] = self.convert_image_products(totest.image_products) - products['container'] = self.convert_image_products(totest.container_products) - - hash = { 'products': products } - hash['openqa_group'] = totest.openqa_group() - hash['take_source_from_product'] = totest.take_source_from_product - hash['arch'] = totest.arch() - hash['jobs_num'] = totest.jobs_num() - hash['need_same_build_number'] = totest.need_same_build_number - hash['set_snapshot_number'] = totest.set_snapshot_number - hash['product_repo'] = totest.product_repo - hash['is_image_product'] = totest.is_image_product - hash['test_subproject'] = totest.test_subproject - hash['openqa_server'] = totest.openqa_server - - print(yaml.dump(hash, default_flow_style=False)) - #totest.totest() - - def do_release(self, subcmd, opts, project='openSUSE:Factory'): - """${cmd_name}: manually release all media. Use with caution! - - ${cmd_usage} - ${cmd_option_list} - """ - - totest = self._setup_totest(project) - totest.release() - - -if __name__ == '__main__': - app = CommandlineInterface() - sys.exit(app.main()) +app = CommandLineInterface() +sys.exit(app.main()) diff --git a/ttm/__init__.py b/ttm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ttm/cli.py b/ttm/cli.py new file mode 100755 index 00000000..e1994842 --- /dev/null +++ b/ttm/cli.py @@ -0,0 +1,51 @@ +#!/usr/bin/python2 +# -*- coding: utf-8 -*- +# +# (C) 2014 mhrusecky@suse.cz, openSUSE.org +# (C) 2014 tchvatal@suse.cz, openSUSE.org +# (C) 2014 aplanas@suse.de, openSUSE.org +# (C) 2014 coolo@suse.de, openSUSE.org +# (C) 2017 okurz@suse.de, openSUSE.org +# (C) 2018 dheidler@suse.de, openSUSE.org +# Distribute under GPLv2 or GPLv3 + +from __future__ import print_function + +import logging +import ToolBase + +from ttm.manager import ToTestManager + +logger = logging.getLogger() + +class CommandLineInterface(ToolBase.CommandLineInterface): + + def __init__(self, *args, **kwargs): + ToolBase.CommandLineInterface.__init__(self, args, kwargs) + + def setup_tool(self): + tool = ToTestManager() + if self.options.debug: + logging.basicConfig(level=logging.DEBUG) + elif self.options.verbose: + logging.basicConfig(level=logging.INFO) + + return tool + + def do_run(self, subcmd, opts, project): + """${cmd_name}: run the ToTest Manager + + ${cmd_usage} + ${cmd_option_list} + """ + + self.tool.totest(project) + + def do_release(self, subcmd, opts, project='openSUSE:Factory'): + """${cmd_name}: manually release all media. Use with caution! + + ${cmd_usage} + ${cmd_option_list} + """ + + self.tool.release(project) diff --git a/ttm/config/SUSE:SLE-12-SP4:GA.yaml b/ttm/config/SUSE:SLE-12-SP5:GA.yaml similarity index 95% rename from ttm/config/SUSE:SLE-12-SP4:GA.yaml rename to ttm/config/SUSE:SLE-12-SP5:GA.yaml index cf1a0cdd..abc330c0 100644 --- a/ttm/config/SUSE:SLE-12-SP4:GA.yaml +++ b/ttm/config/SUSE:SLE-12-SP5:GA.yaml @@ -16,4 +16,4 @@ products: - _product:SLES-dvd5-DVD-x86_64 take_source_from_product: true test_subproject: TEST - +do_not_release: true diff --git a/ttm/config/SUSE:SLE-15-SP1:GA.yaml b/ttm/config/SUSE:SLE-15-SP1:GA.yaml index 08f86c73..f66adaa1 100644 --- a/ttm/config/SUSE:SLE-15-SP1:GA.yaml +++ b/ttm/config/SUSE:SLE-15-SP1:GA.yaml @@ -16,4 +16,4 @@ products: - 000product:SLES-cd-DVD-x86_64 take_source_from_product: true test_subproject: TEST - +do_not_release: true diff --git a/ttm/config/SUSE:SLE-15:GA.yaml b/ttm/config/SUSE:SLE-15:GA.yaml deleted file mode 100644 index 08f86c73..00000000 --- a/ttm/config/SUSE:SLE-15:GA.yaml +++ /dev/null @@ -1,19 +0,0 @@ -jobs_num: 70 -need_same_build_number: true -openqa_group: Functional -openqa_server: https://openqa.suse.de -product_repo: images -products: - ftp: - - 000product:SLES-ftp-POOL-aarch64 - - 000product:SLES-ftp-POOL-ppc64le - - 000product:SLES-ftp-POOL-s390x - - 000product:SLES-ftp-POOL-x86_64 - main: - - 000product:SLES-cd-DVD-aarch64 - - 000product:SLES-cd-DVD-ppc64le - - 000product:SLES-cd-DVD-s390x - - 000product:SLES-cd-DVD-x86_64 -take_source_from_product: true -test_subproject: TEST - diff --git a/ttm/manager.py b/ttm/manager.py new file mode 100644 index 00000000..b6eb23df --- /dev/null +++ b/ttm/manager.py @@ -0,0 +1,658 @@ +#! /usr/bin/python +# -*- coding: utf-8 -*- +# +# (C) 2014 mhrusecky@suse.cz, openSUSE.org +# (C) 2014 tchvatal@suse.cz, openSUSE.org +# (C) 2014 aplanas@suse.de, openSUSE.org +# (C) 2014 coolo@suse.de, openSUSE.org +# (C) 2017 okurz@suse.de, openSUSE.org +# (C) 2018 dheidler@suse.de, openSUSE.org +# Distribute under GPLv2 or GPLv3 + +from __future__ import print_function + +import ToolBase +import logging +import json +import re +import pika +import yaml +import osc.conf +from osc.core import makeurl +from osclib.stagingapi import StagingAPI +from xml.etree import cElementTree as ET +try: + from urllib.error import HTTPError +except ImportError: + # python 2.x + from urllib2 import HTTPError + +from openqa_client.client import OpenQA_Client + +from ttm.totest import ToTest + +# QA Results +QA_INPROGRESS = 1 +QA_FAILED = 2 +QA_PASSED = 3 + +class NotFoundException(Exception): + pass + +class ToTestManager(ToolBase.ToolBase): + + def __init__(self): + ToolBase.ToolBase.__init__(self) + self.logger = logging.getLogger(__name__) + + def setup(self, project): + self.project = ToTest(project) + apiurl = osc.conf.config['apiurl'] + self.api = StagingAPI(apiurl, project=project.name) + self.openqa = OpenQA_Client(server=self.project.openqa_server) + self.update_pinned_descr = False + + def send_amqp_event(self, current_snapshot, current_result): + amqp_url = osc.conf.config.get('ttm_amqp_url') + if not amqp_url: + self.logger.debug('No ttm_amqp_url configured in oscrc - skipping amqp event emission') + return + + self.logger.debug('Sending AMQP message') + inf = re.sub(r'ed$', '', self._result2str(current_result)) + msg_topic = '%s.ttm.build.%s' % (self.project_base.lower(), inf) + msg_body = json.dumps({ + 'build': current_snapshot, + 'project': self.project, + 'failed_jobs': { + 'relevant': self.failed_relevant_jobs, + 'ignored': self.failed_ignored_jobs, + } + }) + + # send amqp event + tries = 7 # arbitrary + for t in range(tries): + try: + notify_connection = pika.BlockingConnection(pika.URLParameters(amqp_url)) + notify_channel = notify_connection.channel() + notify_channel.exchange_declare(exchange='pubsub', exchange_type='topic', passive=True, durable=True) + notify_channel.basic_publish(exchange='pubsub', routing_key=msg_topic, body=msg_body) + notify_connection.close() + break + except pika.exceptions.ConnectionClosed as e: + self.logger.warn('Sending AMQP event did not work: %s. Retrying try %s out of %s' % (e, t, tries)) + else: + self.logger.error('Could not send out AMQP event for %s tries, aborting.' % tries) + + def totest(self, project): + self.setup(project) + try: + current_snapshot = self.get_current_snapshot() + except NotFoundException as e: + # nothing in test project (yet) + self.logger.warn(e) + current_snapshot = None + new_snapshot = self.current_sources() + self.update_pinned_descr = False + current_result = self.overall_result(current_snapshot) + current_qa_version = self.current_qa_version() + + self.logger.info('current_snapshot %s: %s' % + (current_snapshot, self._result2str(current_result))) + self.logger.debug('new_snapshot %s', new_snapshot) + self.logger.debug('current_qa_version %s', current_qa_version) + + snapshotable = self.is_snapshottable() + self.logger.debug('snapshotable: %s', snapshotable) + can_release = ((current_snapshot is None or current_result != QA_INPROGRESS) and snapshotable) + + # not overwriting + if new_snapshot == current_qa_version: + self.logger.debug('no change in snapshot version') + can_release = False + elif not self.all_repos_done(self.test_project): + self.logger.debug("not all repos done, can't release") + # the repos have to be done, otherwise we better not touch them + # with a new release + can_release = False + + self.send_amqp_event(current_snapshot, current_result) + + can_publish = (current_result == QA_PASSED) + + # already published + totest_is_publishing = self.totest_is_publishing() + if totest_is_publishing: + self.logger.debug('totest already publishing') + can_publish = False + + if self.update_pinned_descr: + self.status_for_openqa = { + 'current_snapshot': current_snapshot, + 'new_snapshot': new_snapshot, + 'snapshotable': snapshotable, + 'can_release': can_release, + 'is_publishing': totest_is_publishing, + } + self.update_openqa_status_message() + + if can_publish: + if current_qa_version == current_snapshot: + self.publish_factory_totest() + self.write_version_to_dashboard('snapshot', current_snapshot) + can_release = False # we have to wait + else: + # We reached a very bad status: openQA testing is 'done', but not of the same version + # currently in test project. This can happen when 'releasing' the + # product failed + raise Exception('Publishing stopped: tested version (%s) does not match version in test project (%s)' + % (current_qa_version, current_snapshot)) + + if can_release: + self.update_totest(new_snapshot) + self.write_version_to_dashboard('totest', new_snapshot) + + + def release(self, project): + self.setup(project) + new_snapshot = self.current_sources() + self.update_totest(new_snapshot) + + def write_version_to_dashboard(self, target, version): + version_file = 'version_%s' % target + if self.is_image_product: + version_file = version_file + '_images' + if not (self.dryrun or self.norelease): + self.api.pseudometa_file_ensure(version_file, version, comment='Update version') + + def load_issues_to_ignore(self): + text = self.api.attribute_value_load('IgnoredIssues') + if text: + root = yaml.safe_load(text) + self.issues_to_ignore = root.get('last_seen') + else: + self.issues_to_ignore = dict() + + def save_issues_to_ignore(self): + if self.dryrun: + return + text = yaml.dump({'last_seen': self.issues_to_ignore}, default_flow_style=False) + self.api.attribute_value_save('IgnoredIssues', text) + + def release_version(self): + url = self.api.makeurl(['build', self.project, 'standard', self.arch(), + '000release-packages:%s-release' % self.project_base]) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + for binary in root.findall('binary'): + binary = binary.get('filename', '') + result = re.match(r'.*-([^-]*)-[^-]*.src.rpm', binary) + if result: + return result.group(1) + + raise NotFoundException("can't find %s version" % self.project) + + def current_sources(self): + if self.take_source_from_product is None: + raise Exception('No idea where to take the source version from') + + if self.take_source_from_product: + if self.is_image_product: + return self.iso_build_version(self.project, self.image_products[0].package, + arch=self.image_products[0].archs[0]) + return self.iso_build_version(self.project, self.main_products[0]) + else: + return self.release_version() + + def binaries_of_product(self, project, product, repo=None, arch=None): + if repo is None: + repo = self.product_repo + if arch is None: + arch = self.product_arch + + url = self.api.makeurl(['build', project, repo, arch, product]) + try: + f = self.api.retried_GET(url) + except HTTPError: + return [] + + ret = [] + root = ET.parse(f).getroot() + for binary in root.findall('binary'): + ret.append(binary.get('filename')) + + return ret + + def get_current_snapshot(self): + if self.is_image_product: + return self.iso_build_version(self.test_project, self.image_products[0].package, + arch=self.image_products[0].archs[0]) + return self.iso_build_version(self.test_project, self.main_products[0]) + + def ftp_build_version(self, project, tree): + for binary in self.binaries_of_product(project, tree): + result = re.match(r'.*-Build(.*)-Media1.report', binary) + if result: + return result.group(1) + raise NotFoundException("can't find %s ftp version" % project) + + def iso_build_version(self, project, tree, repo=None, arch=None): + for binary in self.binaries_of_product(project, tree, repo=repo, arch=arch): + result = re.match(r'.*-(?:Build|Snapshot)([0-9.]+)(?:-Media.*\.iso|\.docker\.tar\.xz|\.raw\.xz)', binary) + if result: + return result.group(1) + raise NotFoundException("can't find %s iso version" % project) + + def current_qa_version(self): + version_file = 'version_totest' + if self.is_image_product: + version_file = 'version_totest_images' + + return self.api.pseudometa_file_load(version_file) + + def find_openqa_results(self, snapshot): + """Return the openqa jobs of a given snapshot and filter out the + cloned jobs + + """ + + url = makeurl(self.openqa_server, + ['api', 'v1', 'jobs'], {'group': self.openqa_group(), 'build': snapshot, 'latest': 1}) + f = self.api.retried_GET(url) + jobs = [] + for job in json.load(f)['jobs']: + if job['clone_id'] or job['result'] == 'obsoleted': + continue + job['name'] = job['name'].replace(snapshot, '') + jobs.append(job) + return jobs + + def _result2str(self, result): + if result == QA_INPROGRESS: + return 'inprogress' + elif result == QA_FAILED: + return 'failed' + else: + return 'passed' + + def update_openqa_status_message(self): + url = makeurl(self.openqa_server, + ['api', 'v1', 'job_groups']) + f = self.api.retried_GET(url) + job_groups = json.load(f) + group_id = 0 + for jg in job_groups: + if jg['name'] == self.openqa_group(): + group_id = jg['id'] + break + + if not group_id: + self.logger.debug('No openQA group id found for status comment update, ignoring') + return + + pinned_ignored_issue = 0 + issues = ' , '.join(self.issues_to_ignore.keys()) + status_flag = 'publishing' if self.status_for_openqa['is_publishing'] else \ + 'preparing' if self.status_for_openqa['can_release'] else \ + 'testing' if self.status_for_openqa['snapshotable'] else \ + 'building' + status_msg = 'tag:{}:{}:{}'.format(self.status_for_openqa['new_snapshot'], status_flag, status_flag) + msg = 'pinned-description: Ignored issues\r\n\r\n{}\r\n\r\n{}'.format(issues, status_msg) + data = {'text': msg} + + url = makeurl(self.openqa_server, + ['api', 'v1', 'groups', str(group_id), 'comments']) + f = self.api.retried_GET(url) + comments = json.load(f) + for comment in comments: + if comment['userName'] == 'ttm' and \ + comment['text'].startswith('pinned-description: Ignored issues'): + pinned_ignored_issue = comment['id'] + + self.logger.debug('Writing openQA status message: {}'.format(data)) + if not self.dryrun: + if pinned_ignored_issue: + self.openqa.openqa_request( + 'PUT', 'groups/%s/comments/%d' % (group_id, pinned_ignored_issue), data=data) + else: + self.openqa.openqa_request( + 'POST', 'groups/%s/comments' % group_id, data=data) + + def overall_result(self, snapshot): + """Analyze the openQA jobs of a given snapshot Returns a QAResult""" + + if snapshot is None: + return QA_FAILED + + jobs = self.find_openqa_results(snapshot) + + self.failed_relevant_jobs = [] + self.failed_ignored_jobs = [] + + if len(jobs) < self.jobs_num(): # not yet scheduled + self.logger.warning('we have only %s jobs' % len(jobs)) + return QA_INPROGRESS + + in_progress = False + for job in jobs: + # print json.dumps(job, sort_keys=True, indent=4) + if job['result'] in ('failed', 'incomplete', 'skipped', 'user_cancelled', 'obsoleted', 'parallel_failed'): + # print json.dumps(job, sort_keys=True, indent=4), jobname + url = makeurl(self.openqa_server, + ['api', 'v1', 'jobs', str(job['id']), 'comments']) + f = self.api.retried_GET(url) + comments = json.load(f) + refs = set() + labeled = 0 + to_ignore = False + for comment in comments: + for ref in comment['bugrefs']: + refs.add(str(ref)) + if comment['userName'] == 'ttm' and comment['text'] == 'label:unknown_failure': + labeled = comment['id'] + if re.search(r'@ttm:? ignore', comment['text']): + to_ignore = True + # to_ignore can happen with or without refs + ignored = True if to_ignore else len(refs) > 0 + build_nr = str(job['settings']['BUILD']) + for ref in refs: + if ref not in self.issues_to_ignore: + if to_ignore: + self.issues_to_ignore[ref] = build_nr + self.update_pinned_descr = True + else: + ignored = False + else: + # update reference + self.issues_to_ignore[ref] = build_nr + + if ignored: + self.failed_ignored_jobs.append(job['id']) + if labeled: + text = 'Ignored issue' if len(refs) > 0 else 'Ignored failure' + # remove flag - unfortunately can't delete comment unless admin + data = {'text': text} + if self.dryrun: + self.logger.info('Would label {} with: {}'.format(job['id'], text)) + else: + self.openqa.openqa_request( + 'PUT', 'jobs/%s/comments/%d' % (job['id'], labeled), data=data) + + self.logger.info('job %s failed, but was ignored', job['name']) + else: + self.failed_relevant_jobs.append(job['id']) + if not labeled and len(refs) > 0: + data = {'text': 'label:unknown_failure'} + if self.dryrun: + self.logger.info('Would label {} as unknown'.format(job['id'])) + else: + self.openqa.openqa_request( + 'POST', 'jobs/%s/comments' % job['id'], data=data) + + joburl = '%s/tests/%s' % (self.openqa_server, job['id']) + self.logger.info('job %s failed, see %s', job['name'], joburl) + + elif job['result'] == 'passed' or job['result'] == 'softfailed': + continue + elif job['result'] == 'none': + if job['state'] != 'cancelled': + in_progress = True + else: + raise Exception(job['result']) + + self.save_issues_to_ignore() + + if len(self.failed_relevant_jobs) > 0: + return QA_FAILED + + if in_progress: + return QA_INPROGRESS + + return QA_PASSED + + def all_repos_done(self, project, codes=None): + """Check the build result of the project and only return True if all + repos of that project are either published or unpublished + + """ + + # coolo's experience says that 'finished' won't be + # sufficient here, so don't try to add it :-) + codes = ['published', 'unpublished'] if not codes else codes + + url = self.api.makeurl( + ['build', project, '_result'], {'code': 'failed'}) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + ready = True + for repo in root.findall('result'): + # ignore ports. 'factory' is used by arm for repos that are not + # meant to use the totest manager. + if repo.get('repository') in ('ports', 'factory', 'images_staging'): + continue + if repo.get('dirty', '') == 'true': + self.logger.info('%s %s %s -> %s' % (repo.get('project'), + repo.get('repository'), repo.get('arch'), 'dirty')) + ready = False + if repo.get('code') not in codes: + self.logger.info('%s %s %s -> %s' % (repo.get('project'), + repo.get('repository'), repo.get('arch'), repo.get('code'))) + ready = False + return ready + + def maxsize_for_package(self, package): + if re.match(r'.*-mini-.*', package): + return 737280000 # a CD needs to match + + if re.match(r'.*-dvd5-.*', package): + return 4700372992 # a DVD needs to match + + if re.match(r'livecd-x11', package): + return 681574400 # not a full CD + + if re.match(r'livecd-.*', package): + return 999999999 # a GB stick + + if re.match(r'.*-(dvd9-dvd|cd-DVD)-.*', package): + return 8539996159 + + if re.match(r'.*-ftp-(ftp|POOL)-', package): + return None + + # containers have no size limit + if re.match(r'(opensuse|kubic)-.*-image.*', package): + return None + + if '-Addon-NonOss-ftp-ftp' in package: + return None + + if 'JeOS' in package or 'Kubic' in package: + return 4700372992 + + raise Exception('No maxsize for {}'.format(package)) + + def package_ok(self, project, package, repository, arch): + """Checks one package in a project and returns True if it's succeeded + + """ + + query = {'package': package, 'repository': repository, 'arch': arch} + + url = self.api.makeurl(['build', project, '_result'], query) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + # [@code!='succeeded'] is not supported by ET + failed = [status for status in root.findall('result/status') if status.get('code') != 'succeeded'] + + if any(failed): + self.logger.info( + '%s %s %s %s -> %s' % (project, package, repository, arch, failed[0].get('code'))) + return False + + if not len(root.findall('result/status[@code="succeeded"]')): + self.logger.info('No "succeeded" for %s %s %s %s' % (project, package, repository, arch)) + return False + + maxsize = self.maxsize_for_package(package) + if not maxsize: + return True + + url = self.api.makeurl(['build', project, repository, arch, package]) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + for binary in root.findall('binary'): + if not binary.get('filename', '').endswith('.iso'): + continue + isosize = int(binary.get('size', 0)) + if isosize > maxsize: + self.logger.error('%s %s %s %s: %s' % ( + project, package, repository, arch, 'too large by %s bytes' % (isosize - maxsize))) + return False + + return True + + def is_snapshottable(self): + """Check various conditions required for factory to be snapshotable + + """ + + if not self.all_repos_done(self.project): + return False + + for product in self.ftp_products + self.main_products: + if not self.package_ok(self.project, product, self.product_repo, self.product_arch): + return False + + for product in self.image_products + self.container_products: + for arch in product.archs: + if not self.package_ok(self.project, product.package, self.product_repo, arch): + return False + + if len(self.livecd_products): + if not self.all_repos_done('%s:Live' % self.project): + return False + + for product in self.livecd_products: + for arch in product.archs: + if not self.package_ok('%s:Live' % self.project, product.package, + self.product_repo, arch): + return False + + if self.need_same_build_number: + # make sure all medias have the same build number + builds = set() + for p in self.ftp_products: + if 'Addon-NonOss' in p: + # XXX: don't care about nonoss atm. + continue + builds.add(self.ftp_build_version(self.project, p)) + for p in self.main_products: + builds.add(self.iso_build_version(self.project, p)) + for p in self.livecd_products + self.image_products: + for arch in p.archs: + builds.add(self.iso_build_version(self.project, p.package, + arch=arch)) + if len(builds) != 1: + self.logger.debug('not all medias have the same build number') + return False + + return True + + def _release_package(self, project, package, set_release=None, repository=None, + target_project=None, target_repository=None): + if package.startswith('000product:'): + self.logger.debug('Ignoring to release {}'.format(package)) + return + + query = {'cmd': 'release'} + + if set_release: + query['setrelease'] = set_release + + if repository is not None: + query['repository'] = repository + + if target_project is not None: + # Both need to be set + query['target_project'] = target_project + query['target_repository'] = target_repository + + baseurl = ['source', project, package] + + url = self.api.makeurl(baseurl, query=query) + if self.dryrun or self.norelease: + self.logger.info('release %s/%s (%s)' % (project, package, query)) + else: + self.api.retried_POST(url) + + def _release(self, set_release=None): + # release 000product as a whole + if self.main_products[0].startswith('000product'): + self._release_package(self.project, '000product', set_release=set_release) + + for product in self.ftp_products: + self._release_package(self.project, product, repository=self.product_repo) + + for cd in self.livecd_products: + self._release_package('%s:Live' % + self.project, cd.package, set_release=set_release, + repository=self.livecd_repo) + + for image in self.image_products: + self._release_package(self.project, image.package, set_release=set_release, + repository=self.product_repo) + + for cd in self.main_products: + self._release_package(self.project, cd, set_release=set_release, + repository=self.product_repo) + + for container in self.container_products: + # Containers are built in the same repo as other image products, + # but released into a different repo in :ToTest + self._release_package(self.project, container.package, repository=self.product_repo, + target_project=self.test_project, + target_repository=self.totest_container_repo) + + def update_totest(self, snapshot=None): + # omit snapshot, we don't want to rename on release + if not self.set_snapshot_number: + snapshot = None + release = 'Snapshot%s' % snapshot if snapshot else None + self.logger.info('Updating snapshot %s' % snapshot) + if not (self.dryrun or self.norelease): + self.api.switch_flag_in_prj(self.test_project, flag='publish', state='disable', + repository=self.product_repo) + + self._release(set_release=release) + + def publish_factory_totest(self): + self.logger.info('Publish test project content') + if not (self.dryrun or self.norelease): + self.api.switch_flag_in_prj( + self.test_project, flag='publish', state='enable', + repository=self.product_repo) + if self.container_products: + self.logger.info('Releasing container products from ToTest') + for container in self.container_products: + self._release_package(self.test_project, container.package, + repository=self.totest_container_repo) + + def totest_is_publishing(self): + """Find out if the publishing flag is set in totest's _meta""" + + url = self.api.makeurl( + ['source', self.test_project, '_meta']) + f = self.api.retried_GET(url) + root = ET.parse(f).getroot() + if not root.find('publish'): # default true + return True + + for flag in root.find('publish'): + if flag.get('repository', None) not in [None, self.product_repo]: + continue + if flag.get('arch', None): + continue + if flag.tag == 'enable': + return True + return False diff --git a/ttm/totest.py b/ttm/totest.py new file mode 100755 index 00000000..07402ccd --- /dev/null +++ b/ttm/totest.py @@ -0,0 +1,47 @@ +#!/usr/bin/python2 +# -*- coding: utf-8 -*- +# +# (C) 2014 mhrusecky@suse.cz, openSUSE.org +# (C) 2014 tchvatal@suse.cz, openSUSE.org +# (C) 2014 aplanas@suse.de, openSUSE.org +# (C) 2014 coolo@suse.de, openSUSE.org +# (C) 2017 okurz@suse.de, openSUSE.org +# (C) 2018 dheidler@suse.de, openSUSE.org +# Distribute under GPLv2 or GPLv3 + +from __future__ import print_function + +class ImageProduct(object): + def __init__(self, package, archs): + self.package = package + self.archs = archs + +class ToTest(object): + + """Base class to store the basic interface""" + + def __init__(self, project): + self.name = project + + # set the defaults + self.do_not_release = False + self.need_same_build_number = False + self.set_snapshot_number = False + self.is_image_product = False + + self.product_repo = 'images' + self.product_arch = 'local' + self.livecd_repo = 'images' + self.totest_container_repo = 'containers' + + self.main_products = [] + self.ftp_products = [] + self.container_products = [] + self.livecd_products = [] + self.image_products = [] + + self.test_subproject = 'ToTest' + + self.test_project = '%s:%s' % (self.project, self.test_subproject) + self.project_base = project.split(':')[0] + From 86c507d668925162bec50501005290355b809afc Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Tue, 26 Mar 2019 08:21:47 +0100 Subject: [PATCH 15/20] Parse the config from yaml --- ttm/manager.py | 135 +++++++++++++++++++++++++------------------------ ttm/totest.py | 36 ++++++++++++- 2 files changed, 102 insertions(+), 69 deletions(-) diff --git a/ttm/manager.py b/ttm/manager.py index b6eb23df..725ea0d2 100644 --- a/ttm/manager.py +++ b/ttm/manager.py @@ -48,9 +48,10 @@ class ToTestManager(ToolBase.ToolBase): def setup(self, project): self.project = ToTest(project) apiurl = osc.conf.config['apiurl'] - self.api = StagingAPI(apiurl, project=project.name) + self.api = StagingAPI(apiurl, project=project) self.openqa = OpenQA_Client(server=self.project.openqa_server) self.update_pinned_descr = False + self.load_issues_to_ignore() def send_amqp_event(self, current_snapshot, current_result): amqp_url = osc.conf.config.get('ttm_amqp_url') @@ -60,7 +61,7 @@ class ToTestManager(ToolBase.ToolBase): self.logger.debug('Sending AMQP message') inf = re.sub(r'ed$', '', self._result2str(current_result)) - msg_topic = '%s.ttm.build.%s' % (self.project_base.lower(), inf) + msg_topic = '%s.ttm.build.%s' % (self.project.base.lower(), inf) msg_body = json.dumps({ 'build': current_snapshot, 'project': self.project, @@ -111,7 +112,7 @@ class ToTestManager(ToolBase.ToolBase): if new_snapshot == current_qa_version: self.logger.debug('no change in snapshot version') can_release = False - elif not self.all_repos_done(self.test_project): + elif not self.all_repos_done(self.project.test_project): self.logger.debug("not all repos done, can't release") # the repos have to be done, otherwise we better not touch them # with a new release @@ -161,7 +162,7 @@ class ToTestManager(ToolBase.ToolBase): def write_version_to_dashboard(self, target, version): version_file = 'version_%s' % target - if self.is_image_product: + if self.project.is_image_product: version_file = version_file + '_images' if not (self.dryrun or self.norelease): self.api.pseudometa_file_ensure(version_file, version, comment='Update version') @@ -181,8 +182,8 @@ class ToTestManager(ToolBase.ToolBase): self.api.attribute_value_save('IgnoredIssues', text) def release_version(self): - url = self.api.makeurl(['build', self.project, 'standard', self.arch(), - '000release-packages:%s-release' % self.project_base]) + url = self.api.makeurl(['build', self.project.name, 'standard', self.project.arch, + '000release-packages:%s-release' % self.project.base]) f = self.api.retried_GET(url) root = ET.parse(f).getroot() for binary in root.findall('binary'): @@ -194,22 +195,22 @@ class ToTestManager(ToolBase.ToolBase): raise NotFoundException("can't find %s version" % self.project) def current_sources(self): - if self.take_source_from_product is None: + if self.project.take_source_from_product is None: raise Exception('No idea where to take the source version from') - if self.take_source_from_product: - if self.is_image_product: - return self.iso_build_version(self.project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - return self.iso_build_version(self.project, self.main_products[0]) + if self.project.take_source_from_product: + if self.project.is_image_product: + return self.iso_build_version(self.project, self.project.image_products[0].package, + arch=self.project.image_products[0].archs[0]) + return self.iso_build_version(self.project, self.project.main_products[0]) else: return self.release_version() def binaries_of_product(self, project, product, repo=None, arch=None): if repo is None: - repo = self.product_repo + repo = self.project.product_repo if arch is None: - arch = self.product_arch + arch = self.project.product_arch url = self.api.makeurl(['build', project, repo, arch, product]) try: @@ -225,10 +226,10 @@ class ToTestManager(ToolBase.ToolBase): return ret def get_current_snapshot(self): - if self.is_image_product: - return self.iso_build_version(self.test_project, self.image_products[0].package, - arch=self.image_products[0].archs[0]) - return self.iso_build_version(self.test_project, self.main_products[0]) + if self.project.is_image_product: + return self.iso_build_version(self.project.test_project, self.project.image_products[0].package, + arch=self.project.image_products[0].archs[0]) + return self.iso_build_version(self.project.test_project, self.project.main_products[0]) def ftp_build_version(self, project, tree): for binary in self.binaries_of_product(project, tree): @@ -246,7 +247,7 @@ class ToTestManager(ToolBase.ToolBase): def current_qa_version(self): version_file = 'version_totest' - if self.is_image_product: + if self.project.is_image_product: version_file = 'version_totest_images' return self.api.pseudometa_file_load(version_file) @@ -257,8 +258,8 @@ class ToTestManager(ToolBase.ToolBase): """ - url = makeurl(self.openqa_server, - ['api', 'v1', 'jobs'], {'group': self.openqa_group(), 'build': snapshot, 'latest': 1}) + url = makeurl(self.project.openqa_server, + ['api', 'v1', 'jobs'], {'group': self.project.openqa_group, 'build': snapshot, 'latest': 1}) f = self.api.retried_GET(url) jobs = [] for job in json.load(f)['jobs']: @@ -277,13 +278,13 @@ class ToTestManager(ToolBase.ToolBase): return 'passed' def update_openqa_status_message(self): - url = makeurl(self.openqa_server, + url = makeurl(self.project.openqa_server, ['api', 'v1', 'job_groups']) f = self.api.retried_GET(url) job_groups = json.load(f) group_id = 0 for jg in job_groups: - if jg['name'] == self.openqa_group(): + if jg['name'] == self.project.openqa_group: group_id = jg['id'] break @@ -301,7 +302,7 @@ class ToTestManager(ToolBase.ToolBase): msg = 'pinned-description: Ignored issues\r\n\r\n{}\r\n\r\n{}'.format(issues, status_msg) data = {'text': msg} - url = makeurl(self.openqa_server, + url = makeurl(self.project.openqa_server, ['api', 'v1', 'groups', str(group_id), 'comments']) f = self.api.retried_GET(url) comments = json.load(f) @@ -330,7 +331,7 @@ class ToTestManager(ToolBase.ToolBase): self.failed_relevant_jobs = [] self.failed_ignored_jobs = [] - if len(jobs) < self.jobs_num(): # not yet scheduled + if len(jobs) < self.project.jobs_num: # not yet scheduled self.logger.warning('we have only %s jobs' % len(jobs)) return QA_INPROGRESS @@ -339,7 +340,7 @@ class ToTestManager(ToolBase.ToolBase): # print json.dumps(job, sort_keys=True, indent=4) if job['result'] in ('failed', 'incomplete', 'skipped', 'user_cancelled', 'obsoleted', 'parallel_failed'): # print json.dumps(job, sort_keys=True, indent=4), jobname - url = makeurl(self.openqa_server, + url = makeurl(self.project.openqa_server, ['api', 'v1', 'jobs', str(job['id']), 'comments']) f = self.api.retried_GET(url) comments = json.load(f) @@ -390,7 +391,7 @@ class ToTestManager(ToolBase.ToolBase): self.openqa.openqa_request( 'POST', 'jobs/%s/comments' % job['id'], data=data) - joburl = '%s/tests/%s' % (self.openqa_server, job['id']) + joburl = '%s/tests/%s' % (self.project.openqa_server, job['id']) self.logger.info('job %s failed, see %s', job['name'], joburl) elif job['result'] == 'passed' or job['result'] == 'softfailed': @@ -517,41 +518,41 @@ class ToTestManager(ToolBase.ToolBase): """ - if not self.all_repos_done(self.project): + if not self.all_repos_done(self.project.name): return False - for product in self.ftp_products + self.main_products: - if not self.package_ok(self.project, product, self.product_repo, self.product_arch): + for product in self.project.ftp_products + self.project.main_products: + if not self.package_ok(self.project.name, product, self.project.product_repo, self.project.product_arch): return False - for product in self.image_products + self.container_products: + for product in self.project.image_products + self.project.container_products: for arch in product.archs: - if not self.package_ok(self.project, product.package, self.product_repo, arch): + if not self.package_ok(self.project.name, product.package, self.project.product_repo, arch): return False - if len(self.livecd_products): - if not self.all_repos_done('%s:Live' % self.project): + if len(self.project.livecd_products): + if not self.all_repos_done('%s:Live' % self.project.name): return False - for product in self.livecd_products: + for product in self.project.livecd_products: for arch in product.archs: - if not self.package_ok('%s:Live' % self.project, product.package, - self.product_repo, arch): + if not self.package_ok('%s:Live' % self.project.name, product.package, + self.project.product_repo, arch): return False - if self.need_same_build_number: + if self.project.need_same_build_number: # make sure all medias have the same build number builds = set() - for p in self.ftp_products: + for p in self.project.ftp_products: if 'Addon-NonOss' in p: # XXX: don't care about nonoss atm. continue - builds.add(self.ftp_build_version(self.project, p)) - for p in self.main_products: - builds.add(self.iso_build_version(self.project, p)) - for p in self.livecd_products + self.image_products: + builds.add(self.ftp_build_version(self.project.name, p)) + for p in self.project.main_products: + builds.add(self.iso_build_version(self.project.name, p)) + for p in self.project.livecd_products + self.project.image_products: for arch in p.archs: - builds.add(self.iso_build_version(self.project, p.package, + builds.add(self.iso_build_version(self.project.name, p.package, arch=arch)) if len(builds) != 1: self.logger.debug('not all medias have the same build number') @@ -588,41 +589,41 @@ class ToTestManager(ToolBase.ToolBase): def _release(self, set_release=None): # release 000product as a whole - if self.main_products[0].startswith('000product'): + if self.project.main_products[0].startswith('000product'): self._release_package(self.project, '000product', set_release=set_release) - for product in self.ftp_products: - self._release_package(self.project, product, repository=self.product_repo) + for product in self.project.ftp_products: + self._release_package(self.project, product, repository=self.project.product_repo) - for cd in self.livecd_products: + for cd in self.project.livecd_products: self._release_package('%s:Live' % self.project, cd.package, set_release=set_release, repository=self.livecd_repo) - for image in self.image_products: + for image in self.project.image_products: self._release_package(self.project, image.package, set_release=set_release, - repository=self.product_repo) + repository=self.project.product_repo) - for cd in self.main_products: + for cd in self.project.main_products: self._release_package(self.project, cd, set_release=set_release, - repository=self.product_repo) + repository=self.project.product_repo) - for container in self.container_products: + for container in self.project.container_products: # Containers are built in the same repo as other image products, # but released into a different repo in :ToTest - self._release_package(self.project, container.package, repository=self.product_repo, - target_project=self.test_project, - target_repository=self.totest_container_repo) + self._release_package(self.project, container.package, repository=self.project.product_repo, + target_project=self.project.test_project, + target_repository=self.project.totest_container_repo) def update_totest(self, snapshot=None): # omit snapshot, we don't want to rename on release - if not self.set_snapshot_number: + if not self.project.set_snapshot_number: snapshot = None release = 'Snapshot%s' % snapshot if snapshot else None self.logger.info('Updating snapshot %s' % snapshot) if not (self.dryrun or self.norelease): - self.api.switch_flag_in_prj(self.test_project, flag='publish', state='disable', - repository=self.product_repo) + self.api.switch_flag_in_prj(self.project.test_project, flag='publish', state='disable', + repository=self.project.product_repo) self._release(set_release=release) @@ -630,26 +631,26 @@ class ToTestManager(ToolBase.ToolBase): self.logger.info('Publish test project content') if not (self.dryrun or self.norelease): self.api.switch_flag_in_prj( - self.test_project, flag='publish', state='enable', - repository=self.product_repo) - if self.container_products: + self.project.test_project, flag='publish', state='enable', + repository=self.project.product_repo) + if self.project.container_products: self.logger.info('Releasing container products from ToTest') - for container in self.container_products: - self._release_package(self.test_project, container.package, - repository=self.totest_container_repo) + for container in self.project.container_products: + self._release_package(self.project.test_project, container.package, + repository=self.project.totest_container_repo) def totest_is_publishing(self): """Find out if the publishing flag is set in totest's _meta""" url = self.api.makeurl( - ['source', self.test_project, '_meta']) + ['source', self.project.test_project, '_meta']) f = self.api.retried_GET(url) root = ET.parse(f).getroot() if not root.find('publish'): # default true return True for flag in root.find('publish'): - if flag.get('repository', None) not in [None, self.product_repo]: + if flag.get('repository', None) not in [None, self.project.product_repo]: continue if flag.get('arch', None): continue diff --git a/ttm/totest.py b/ttm/totest.py index 07402ccd..edea6321 100755 --- a/ttm/totest.py +++ b/ttm/totest.py @@ -10,6 +10,7 @@ # Distribute under GPLv2 or GPLv3 from __future__ import print_function +import yaml class ImageProduct(object): def __init__(self, package, archs): @@ -28,6 +29,9 @@ class ToTest(object): self.need_same_build_number = False self.set_snapshot_number = False self.is_image_product = False + self.take_source_from_product = False + self.arch = 'x86_64' + self.openqa_server = None self.product_repo = 'images' self.product_arch = 'local' @@ -41,7 +45,35 @@ class ToTest(object): self.image_products = [] self.test_subproject = 'ToTest' + self.base = project.split(':')[0] - self.test_project = '%s:%s' % (self.project, self.test_subproject) - self.project_base = project.split(':')[0] + self.jobs_num = 42 + self.load_config() + self.test_project = '%s:%s' % (project, self.test_subproject) + def load_config(self): + config = yaml.load(open('ttm/config/{}.yaml'.format(self.name))) + for key, value in config.items(): + if key == 'products': + self.set_products(value) + else: + setattr(self, key, value) + + def parse_images(self, products): + parsed = [] + for package in products: + # there is only one + for key, value in package.items(): + parsed.append(ImageProduct(key, value)) + + return parsed + + def set_products(self, products): + # plain arrays + setattr(self, 'main_products', products['main']) + setattr(self, 'ftp_products', products['ftp']) + + # image products + setattr(self, 'livecd_products', self.parse_images(products['livecds'])) + setattr(self, 'image_products', self.parse_images(products['images'])) + setattr(self, 'container_products', self.parse_images(products['container'])) From b35453b4bf7b2b66c1fd7b6193ec49626c7bcfd0 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Tue, 26 Mar 2019 11:25:38 +0100 Subject: [PATCH 16/20] Calculate is_image_product instead of configuring it --- ttm/config/openSUSE:Leap:15.0:Images.yaml | 1 - ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml | 1 - ttm/config/openSUSE:Leap:15.1:Images.yaml | 1 - ttm/manager.py | 4 ++-- ttm/totest.py | 12 ++++++------ 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/ttm/config/openSUSE:Leap:15.0:Images.yaml b/ttm/config/openSUSE:Leap:15.0:Images.yaml index cf82d70a..9630420b 100644 --- a/ttm/config/openSUSE:Leap:15.0:Images.yaml +++ b/ttm/config/openSUSE:Leap:15.0:Images.yaml @@ -1,4 +1,3 @@ -is_image_product: true jobs_num: 13 openqa_group: openSUSE Leap 15.0 Images openqa_server: https://openqa.opensuse.org diff --git a/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml b/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml index 49f741af..38bd638b 100644 --- a/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml +++ b/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml @@ -1,4 +1,3 @@ -is_image_product: true jobs_num: 2 openqa_group: openSUSE Leap 15.1 AArch64 Images openqa_server: https://openqa.opensuse.org diff --git a/ttm/config/openSUSE:Leap:15.1:Images.yaml b/ttm/config/openSUSE:Leap:15.1:Images.yaml index 89033e6c..52eb2827 100644 --- a/ttm/config/openSUSE:Leap:15.1:Images.yaml +++ b/ttm/config/openSUSE:Leap:15.1:Images.yaml @@ -1,4 +1,3 @@ -is_image_product: true jobs_num: 13 openqa_group: openSUSE Leap 15.1 Images openqa_server: https://openqa.opensuse.org diff --git a/ttm/manager.py b/ttm/manager.py index 725ea0d2..6e3c1380 100644 --- a/ttm/manager.py +++ b/ttm/manager.py @@ -200,9 +200,9 @@ class ToTestManager(ToolBase.ToolBase): if self.project.take_source_from_product: if self.project.is_image_product: - return self.iso_build_version(self.project, self.project.image_products[0].package, + return self.iso_build_version(self.project.name, self.project.image_products[0].package, arch=self.project.image_products[0].archs[0]) - return self.iso_build_version(self.project, self.project.main_products[0]) + return self.iso_build_version(self.project.name, self.project.main_products[0]) else: return self.release_version() diff --git a/ttm/totest.py b/ttm/totest.py index edea6321..eaff9b5a 100755 --- a/ttm/totest.py +++ b/ttm/totest.py @@ -28,7 +28,6 @@ class ToTest(object): self.do_not_release = False self.need_same_build_number = False self.set_snapshot_number = False - self.is_image_product = False self.take_source_from_product = False self.arch = 'x86_64' self.openqa_server = None @@ -50,6 +49,7 @@ class ToTest(object): self.jobs_num = 42 self.load_config() self.test_project = '%s:%s' % (project, self.test_subproject) + self.is_image_product = not len(self.main_products) def load_config(self): config = yaml.load(open('ttm/config/{}.yaml'.format(self.name))) @@ -70,10 +70,10 @@ class ToTest(object): def set_products(self, products): # plain arrays - setattr(self, 'main_products', products['main']) - setattr(self, 'ftp_products', products['ftp']) + setattr(self, 'main_products', products.get('main', [])) + setattr(self, 'ftp_products', products.get('ftp', [])) # image products - setattr(self, 'livecd_products', self.parse_images(products['livecds'])) - setattr(self, 'image_products', self.parse_images(products['images'])) - setattr(self, 'container_products', self.parse_images(products['container'])) + setattr(self, 'livecd_products', self.parse_images(products.get('livecds', []))) + setattr(self, 'image_products', self.parse_images(products.get('images', []))) + setattr(self, 'container_products', self.parse_images(products.get('container', []))) From 7932e111343e0d20b528064fd81b1c2f5136b29f Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Tue, 26 Mar 2019 16:37:12 +0100 Subject: [PATCH 17/20] Moved the config into OBS/IBS --- ttm/config/SUSE:SLE-12-SP5:GA.yaml | 19 ----- ttm/config/SUSE:SLE-15-SP1:GA.yaml | 19 ----- ttm/config/openSUSE:Factory.yaml | 81 ------------------- ttm/config/openSUSE:Factory:ARM.yaml | 31 ------- ttm/config/openSUSE:Factory:PowerPC.yaml | 23 ------ ttm/config/openSUSE:Factory:zSystems.yaml | 13 --- ttm/config/openSUSE:Leap:15.0:Images.yaml | 30 ------- ttm/config/openSUSE:Leap:15.0:Ports.yaml | 16 ---- ttm/config/openSUSE:Leap:15.1.yaml | 15 ---- ttm/config/openSUSE:Leap:15.1:ARM.yaml | 15 ---- ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml | 17 ---- ttm/config/openSUSE:Leap:15.1:Images.yaml | 31 ------- ttm/config/openSUSE:Leap:15.1:PowerPC.yaml | 14 ---- ttm/manager.py | 2 +- ttm/totest.py | 9 ++- 15 files changed, 6 insertions(+), 329 deletions(-) delete mode 100644 ttm/config/SUSE:SLE-12-SP5:GA.yaml delete mode 100644 ttm/config/SUSE:SLE-15-SP1:GA.yaml delete mode 100644 ttm/config/openSUSE:Factory.yaml delete mode 100644 ttm/config/openSUSE:Factory:ARM.yaml delete mode 100644 ttm/config/openSUSE:Factory:PowerPC.yaml delete mode 100644 ttm/config/openSUSE:Factory:zSystems.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.0:Images.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.0:Ports.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.1.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.1:ARM.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.1:Images.yaml delete mode 100644 ttm/config/openSUSE:Leap:15.1:PowerPC.yaml diff --git a/ttm/config/SUSE:SLE-12-SP5:GA.yaml b/ttm/config/SUSE:SLE-12-SP5:GA.yaml deleted file mode 100644 index abc330c0..00000000 --- a/ttm/config/SUSE:SLE-12-SP5:GA.yaml +++ /dev/null @@ -1,19 +0,0 @@ -jobs_num: 70 -need_same_build_number: true -openqa_group: Functional -openqa_server: https://openqa.suse.de -product_repo: images -products: - ftp: - - _product:SLES-ftp-POOL-aarch64 - - _product:SLES-ftp-POOL-ppc64le - - _product:SLES-ftp-POOL-s390x - - _product:SLES-ftp-POOL-x86_64 - main: - - _product:SLES-dvd5-DVD-aarch64 - - _product:SLES-dvd5-DVD-ppc64le - - _product:SLES-dvd5-DVD-s390x - - _product:SLES-dvd5-DVD-x86_64 -take_source_from_product: true -test_subproject: TEST -do_not_release: true diff --git a/ttm/config/SUSE:SLE-15-SP1:GA.yaml b/ttm/config/SUSE:SLE-15-SP1:GA.yaml deleted file mode 100644 index f66adaa1..00000000 --- a/ttm/config/SUSE:SLE-15-SP1:GA.yaml +++ /dev/null @@ -1,19 +0,0 @@ -jobs_num: 70 -need_same_build_number: true -openqa_group: Functional -openqa_server: https://openqa.suse.de -product_repo: images -products: - ftp: - - 000product:SLES-ftp-POOL-aarch64 - - 000product:SLES-ftp-POOL-ppc64le - - 000product:SLES-ftp-POOL-s390x - - 000product:SLES-ftp-POOL-x86_64 - main: - - 000product:SLES-cd-DVD-aarch64 - - 000product:SLES-cd-DVD-ppc64le - - 000product:SLES-cd-DVD-s390x - - 000product:SLES-cd-DVD-x86_64 -take_source_from_product: true -test_subproject: TEST -do_not_release: true diff --git a/ttm/config/openSUSE:Factory.yaml b/ttm/config/openSUSE:Factory.yaml deleted file mode 100644 index bbc4ddfb..00000000 --- a/ttm/config/openSUSE:Factory.yaml +++ /dev/null @@ -1,81 +0,0 @@ -arch: x86_64 -jobs_num: 70 -openqa_group: openSUSE Tumbleweed -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - container: - - opensuse-tumbleweed-image:docker: - - i586 - - x86_64 - - kubic-kured-image: - - x86_64 - - kubic-pause-image: - - i586 - - x86_64 - ftp: - - 000product:openSUSE-ftp-ftp-i586_x86_64 - - 000product:openSUSE-Addon-NonOss-ftp-ftp-i586_x86_64 - images: - - opensuse-tumbleweed-image:lxc: - - i586 - - x86_64 - - openSUSE-Tumbleweed-JeOS:MS-HyperV: - - x86_64 - - openSUSE-Tumbleweed-JeOS:OpenStack-Cloud: - - x86_64 - - openSUSE-Tumbleweed-JeOS:VMware: - - x86_64 - - openSUSE-Tumbleweed-JeOS:XEN: - - x86_64 - - openSUSE-Tumbleweed-JeOS:kvm-and-xen: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-MS-HyperV: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-MS-HyperV: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-OpenStack-Cloud: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-OpenStack-Cloud: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-VMware: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-VMware: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-Vagrant-x86_64: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-Vagrant-x86_64: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-XEN: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-XEN: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-hardware-x86_64: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-hardware-x86_64: - - x86_64 - - openSUSE-Tumbleweed-Kubic:MicroOS-podman-kvm-and-xen: - - x86_64 - - openSUSE-Tumbleweed-Kubic:kubeadm-cri-o-kvm-and-xen: - - x86_64 - livecds: - - livecd-tumbleweed-kde: - - i586 - - x86_64 - - livecd-tumbleweed-gnome: - - i586 - - x86_64 - - livecd-tumbleweed-x11: - - i586 - - x86_64 - - livecd-tumbleweed-xfce: - - i586 - - x86_64 - main: - - 000product:openSUSE-dvd5-dvd-i586 - - 000product:openSUSE-dvd5-dvd-x86_64 - - 000product:openSUSE-cd-mini-i586 - - 000product:openSUSE-cd-mini-x86_64 - - 000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-x86_64 -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Factory:ARM.yaml b/ttm/config/openSUSE:Factory:ARM.yaml deleted file mode 100644 index 10b3cabb..00000000 --- a/ttm/config/openSUSE:Factory:ARM.yaml +++ /dev/null @@ -1,31 +0,0 @@ -arch: aarch64 -jobs_num: 2 -openqa_group: openSUSE Tumbleweed AArch64 -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - container: - - opensuse-tumbleweed-image:docker: - - aarch64 - - kubic-kured-image: - - aarch64 - - kubic-pause-image: - - aarch64 - ftp: - - 000product:openSUSE-ftp-ftp-aarch64 - - 000product:openSUSE-ftp-ftp-armv7hl - - 000product:openSUSE-ftp-ftp-armv6hl - images: - - opensuse-tumbleweed-image:lxc: - - armv6l - - armv7l - - aarch64 - livecds: - - JeOS: - - armv7l - main: - - 000product:openSUSE-cd-mini-aarch64 - - 000product:openSUSE-dvd5-dvd-aarch64 - - 000product:openSUSE-Tumbleweed-Kubic-dvd5-dvd-aarch64 -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Factory:PowerPC.yaml b/ttm/config/openSUSE:Factory:PowerPC.yaml deleted file mode 100644 index ac5a54ea..00000000 --- a/ttm/config/openSUSE:Factory:PowerPC.yaml +++ /dev/null @@ -1,23 +0,0 @@ -arch: ppc64le -jobs_num: 4 -openqa_group: openSUSE Tumbleweed PowerPC -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - container: - - opensuse-tumbleweed-image:docker: - - ppc64le - - kubic-kured-image: - - ppc64le - - kubic-pause-image: - - ppc64le - ftp: - - 000product:openSUSE-ftp-ftp-ppc64_ppc64le - images: - - opensuse-tumbleweed-image:lxc: - - ppc64le - main: - - 000product:openSUSE-dvd5-dvd-ppc64le - - 000product:openSUSE-cd-mini-ppc64le -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Factory:zSystems.yaml b/ttm/config/openSUSE:Factory:zSystems.yaml deleted file mode 100644 index ef01212a..00000000 --- a/ttm/config/openSUSE:Factory:zSystems.yaml +++ /dev/null @@ -1,13 +0,0 @@ -arch: s390x -jobs_num: 1 -openqa_group: openSUSE Tumbleweed s390x -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - ftp: - - 000product:openSUSE-ftp-ftp-s390x - main: - - 000product:openSUSE-dvd5-dvd-s390x - - 000product:openSUSE-cd-mini-s390x -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.0:Images.yaml b/ttm/config/openSUSE:Leap:15.0:Images.yaml deleted file mode 100644 index 9630420b..00000000 --- a/ttm/config/openSUSE:Leap:15.0:Images.yaml +++ /dev/null @@ -1,30 +0,0 @@ -jobs_num: 13 -openqa_group: openSUSE Leap 15.0 Images -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - images: - - livecd-leap-gnome: - - x86_64 - - livecd-leap-kde: - - x86_64 - - livecd-leap-x11: - - x86_64 - - opensuse-leap-image:docker: - - x86_64 - - opensuse-leap-image:lxc: - - x86_64 - - kiwi-templates-Leap15-JeOS:MS-HyperV: - - x86_64 - - kiwi-templates-Leap15-JeOS:OpenStack-Cloud: - - x86_64 - - kiwi-templates-Leap15-JeOS:VMware: - - x86_64 - - kiwi-templates-Leap15-JeOS:XEN: - - x86_64 - - kiwi-templates-Leap15-JeOS:kvm-and-xen: - - x86_64 -set_snapshot_number: true -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.0:Ports.yaml b/ttm/config/openSUSE:Leap:15.0:Ports.yaml deleted file mode 100644 index 5912d0dd..00000000 --- a/ttm/config/openSUSE:Leap:15.0:Ports.yaml +++ /dev/null @@ -1,16 +0,0 @@ -jobs_num: 10 -need_same_build_number: true -openqa_group: openSUSE Leap 15.0 AArch64 -openqa_server: https://openqa.opensuse.org -product_repo: images_arm -products: - ftp: - - 000product:openSUSE-ftp-ftp-aarch64 - - 000product:openSUSE-ftp-ftp-armv7hl - main: - - 000product:openSUSE-cd-mini-aarch64 - - 000product:openSUSE-dvd5-dvd-aarch64 -set_snapshot_number: true -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.1.yaml b/ttm/config/openSUSE:Leap:15.1.yaml deleted file mode 100644 index b2185168..00000000 --- a/ttm/config/openSUSE:Leap:15.1.yaml +++ /dev/null @@ -1,15 +0,0 @@ -jobs_num: 70 -need_same_build_number: true -openqa_group: openSUSE Leap 15 -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - ftp: - - 000product:openSUSE-ftp-ftp-x86_64 - - 000product:openSUSE-Addon-NonOss-ftp-ftp-x86_64 - main: - - 000product:openSUSE-cd-mini-x86_64 - - 000product:openSUSE-dvd5-dvd-x86_64 -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.1:ARM.yaml b/ttm/config/openSUSE:Leap:15.1:ARM.yaml deleted file mode 100644 index ef769a7f..00000000 --- a/ttm/config/openSUSE:Leap:15.1:ARM.yaml +++ /dev/null @@ -1,15 +0,0 @@ -jobs_num: 10 -need_same_build_number: true -openqa_group: openSUSE Leap 15 AArch64 -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - ftp: - - 000product:openSUSE-ftp-ftp-aarch64 - - 000product:openSUSE-ftp-ftp-armv7hl - main: - - 000product:openSUSE-cd-mini-aarch64 - - 000product:openSUSE-dvd5-dvd-aarch64 -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml b/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml deleted file mode 100644 index 38bd638b..00000000 --- a/ttm/config/openSUSE:Leap:15.1:ARM:Images.yaml +++ /dev/null @@ -1,17 +0,0 @@ -jobs_num: 2 -openqa_group: openSUSE Leap 15.1 AArch64 Images -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - container: - - opensuse-leap-image:docker: - - aarch64 - images: - - JeOS:JeOS-efi.aarch64: - - aarch64 - - JeOS: - - armv7l -set_snapshot_number: true -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.1:Images.yaml b/ttm/config/openSUSE:Leap:15.1:Images.yaml deleted file mode 100644 index 52eb2827..00000000 --- a/ttm/config/openSUSE:Leap:15.1:Images.yaml +++ /dev/null @@ -1,31 +0,0 @@ -jobs_num: 13 -openqa_group: openSUSE Leap 15.1 Images -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - container: - - opensuse-leap-image:docker: - - x86_64 - images: - - livecd-leap-gnome: - - x86_64 - - livecd-leap-kde: - - x86_64 - - livecd-leap-x11: - - x86_64 - - opensuse-leap-image:lxc: - - x86_64 - - openSUSE-Leap-15.1-JeOS:MS-HyperV: - - x86_64 - - openSUSE-Leap-15.1-JeOS:OpenStack-Cloud: - - x86_64 - - openSUSE-Leap-15.1-JeOS:VMware: - - x86_64 - - openSUSE-Leap-15.1-JeOS:XEN: - - x86_64 - - openSUSE-Leap-15.1-JeOS:kvm-and-xen: - - x86_64 -set_snapshot_number: true -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml b/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml deleted file mode 100644 index ca8de86d..00000000 --- a/ttm/config/openSUSE:Leap:15.1:PowerPC.yaml +++ /dev/null @@ -1,14 +0,0 @@ -jobs_num: 10 -need_same_build_number: true -openqa_group: openSUSE Leap 15 PowerPC -openqa_server: https://openqa.opensuse.org -product_repo: images -products: - ftp: - - 000product:openSUSE-ftp-ftp-ppc64le - main: - - 000product:openSUSE-cd-mini-ppc64le - - 000product:openSUSE-dvd5-dvd-ppc64le -take_source_from_product: true -test_subproject: ToTest - diff --git a/ttm/manager.py b/ttm/manager.py index 6e3c1380..55d5555b 100644 --- a/ttm/manager.py +++ b/ttm/manager.py @@ -46,8 +46,8 @@ class ToTestManager(ToolBase.ToolBase): self.logger = logging.getLogger(__name__) def setup(self, project): - self.project = ToTest(project) apiurl = osc.conf.config['apiurl'] + self.project = ToTest(project, apiurl) self.api = StagingAPI(apiurl, project=project) self.openqa = OpenQA_Client(server=self.project.openqa_server) self.update_pinned_descr = False diff --git a/ttm/totest.py b/ttm/totest.py index eaff9b5a..abcfabee 100755 --- a/ttm/totest.py +++ b/ttm/totest.py @@ -11,6 +11,7 @@ from __future__ import print_function import yaml +from osclib.core import attribute_value_load class ImageProduct(object): def __init__(self, package, archs): @@ -21,7 +22,7 @@ class ToTest(object): """Base class to store the basic interface""" - def __init__(self, project): + def __init__(self, project, apiurl): self.name = project # set the defaults @@ -47,12 +48,12 @@ class ToTest(object): self.base = project.split(':')[0] self.jobs_num = 42 - self.load_config() + self.load_config(apiurl) self.test_project = '%s:%s' % (project, self.test_subproject) self.is_image_product = not len(self.main_products) - def load_config(self): - config = yaml.load(open('ttm/config/{}.yaml'.format(self.name))) + def load_config(self, apiurl): + config = yaml.safe_load(attribute_value_load(apiurl, self.name, 'ToTestManagerConfig')) for key, value in config.items(): if key == 'products': self.set_products(value) From f3b3549a35218d4ad3c48616064a77ec978e822c Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Wed, 27 Mar 2019 14:36:11 +0100 Subject: [PATCH 18/20] Rename the snapshot functions and add gocd config --- dist/package/openSUSE-release-tools.spec | 35 +--- gocd/generate.sh | 3 + gocd/totestmanager.gocd.yaml | 212 +++++++++++++++++++++++ gocd/totestmanager.gocd.yaml.erb | 27 +++ systemd/osrt-totest-manager@.service | 8 - systemd/osrt-totest-manager@.timer | 9 - ttm/manager.py | 37 ++-- 7 files changed, 262 insertions(+), 69 deletions(-) create mode 100755 gocd/generate.sh create mode 100644 gocd/totestmanager.gocd.yaml create mode 100644 gocd/totestmanager.gocd.yaml.erb delete mode 100644 systemd/osrt-totest-manager@.service delete mode 100644 systemd/osrt-totest-manager@.timer diff --git a/dist/package/openSUSE-release-tools.spec b/dist/package/openSUSE-release-tools.spec index 84126dd6..210c97a4 100644 --- a/dist/package/openSUSE-release-tools.spec +++ b/dist/package/openSUSE-release-tools.spec @@ -239,18 +239,6 @@ Requires(pre): shadow %description staging-bot Staging bot services and system user. -%package totest-manager -Summary: Manages product ToTest repository -Group: Development/Tools/Other -BuildArch: noarch -# TODO Update requirements. -Requires: osclib = %{version} -Requires: python2-openqa_client -Requires: python2-pika - -%description totest-manager -Manages product ToTest repository workflow and openQA interaction - %package pkglistgen Summary: Generates package lists in 000product Group: Development/Tools/Other @@ -424,20 +412,6 @@ exit 0 %postun staging-bot %systemd_postun -%pre totest-manager -getent passwd osrt-totest-manager > /dev/null || \ - useradd -r -m -s /sbin/nologin -c "user for openSUSE-release-tools-totest-manager" osrt-totest-manager -exit 0 - -%postun totest-manager -%systemd_postun -if [ -x /usr/bin/systemctl ] ; then - instances=($(systemctl list-units -t service --full | grep -oP osrt-totest-manager@[^.]+ || true)) - if [ ${#instances[@]} -gt 0 ] ; then - systemctl try-restart --no-block ${instances[@]} - fi -fi - %postun pkglistgen %systemd_postun @@ -466,6 +440,7 @@ fi %{_bindir}/osrt-sync-rebuild %{_bindir}/osrt-unmaintained %{_bindir}/osrt-staging-installcheck +%{_bindir}/osrt-totest-manager %{_datadir}/%{source_dir} %exclude %{_datadir}/%{source_dir}/abichecker %exclude %{_datadir}/%{source_dir}/%{announcer_filename} @@ -485,7 +460,6 @@ fi %exclude %{_datadir}/%{source_dir}/repo_checker.pl %exclude %{_datadir}/%{source_dir}/repo_checker.py %exclude %{_datadir}/%{source_dir}/suppkg_rebuild.py -%exclude %{_datadir}/%{source_dir}/totest-manager.py %exclude %{_datadir}/%{source_dir}/osclib %exclude %{_datadir}/%{source_dir}/osc-check_dups.py %exclude %{_datadir}/%{source_dir}/osc-cycle.py @@ -626,13 +600,6 @@ fi %{_unitdir}/osrt-staging-bot-support-rebuild@.service %{_unitdir}/osrt-staging-bot-support-rebuild@.timer -%files totest-manager -%defattr(-,root,root,-) -%{_bindir}/osrt-totest-manager -%{_datadir}/%{source_dir}/totest-manager.py -%{_unitdir}/osrt-totest-manager@.service -%{_unitdir}/osrt-totest-manager@.timer - %files pkglistgen %defattr(-,root,root,-) %{_bindir}/osrt-pkglistgen diff --git a/gocd/generate.sh b/gocd/generate.sh new file mode 100755 index 00000000..15f135a0 --- /dev/null +++ b/gocd/generate.sh @@ -0,0 +1,3 @@ +for file in *.erb; do + erb -T - $file > $(basename $file .erb) +done diff --git a/gocd/totestmanager.gocd.yaml b/gocd/totestmanager.gocd.yaml new file mode 100644 index 00000000..020049e9 --- /dev/null +++ b/gocd/totestmanager.gocd.yaml @@ -0,0 +1,212 @@ +format_version: 3 +pipelines: + TTM.Factory: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Factory + TTM.Factory_ARM: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Factory:ARM + TTM.Factory_PowerPC: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Factory:PowerPC + TTM.Factory_zSystems: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Factory:zSystems + TTM.Leap_15.0_Images: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.0:Images + TTM.Leap_15.1_Images: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.1:Images + TTM.Leap_15.1_ARM_Images: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.1:ARM:Images + TTM.Leap_15.1: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.1 + TTM.Leap_15.1_ARM: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.1:ARM + TTM.Leap_15.1_PowerPC: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run openSUSE:Leap:15.1:PowerPC diff --git a/gocd/totestmanager.gocd.yaml.erb b/gocd/totestmanager.gocd.yaml.erb new file mode 100644 index 00000000..00b565bc --- /dev/null +++ b/gocd/totestmanager.gocd.yaml.erb @@ -0,0 +1,27 @@ +format_version: 3 +pipelines: +<% for project in %w(openSUSE:Factory openSUSE:Factory:ARM openSUSE:Factory:PowerPC + openSUSE:Factory:zSystems openSUSE:Leap:15.0:Images openSUSE:Leap:15.1:Images + openSUSE:Leap:15.1:ARM:Images openSUSE:Leap:15.1 openSUSE:Leap:15.1:ARM openSUSE:Leap:15.1:PowerPC) -%> + TTM.<%= project.gsub('openSUSE:', '').gsub(':', '_') %>: + group: openSUSE.Checkers + lock_behavior: unlockWhenFinished + environment_variables: + OSC_CONFIG: /home/go/config/oscrc-totest-manager + materials: + script: + git: https://github.com/openSUSE/openSUSE-release-tools.git + destination: scripts + timer: + spec: 0 */15 * ? * * + only_on_changes: false + stages: + - Run: + approval: manual + resources: + - staging-bot + tasks: + - script: |- + install -D /home/go/config/openqa-client.conf /home/go/.config/openqa/client.conf + scripts/totest-manager.py -A https://api.opensuse.org --osc-debug --debug run <%= project %> +<% end -%> diff --git a/systemd/osrt-totest-manager@.service b/systemd/osrt-totest-manager@.service deleted file mode 100644 index b5bfa93e..00000000 --- a/systemd/osrt-totest-manager@.service +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=openSUSE Release Tools: ToTest Manager for %i - -[Service] -User=osrt-totest-manager -SyslogIdentifier=osrt-totest-manager -WorkingDirectory=~ -ExecStart=/usr/bin/osrt-totest-manager --verbose run "%i" diff --git a/systemd/osrt-totest-manager@.timer b/systemd/osrt-totest-manager@.timer deleted file mode 100644 index 62dd8e27..00000000 --- a/systemd/osrt-totest-manager@.timer +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=openSUSE Release Tools: ToTest Manager for %i - -[Timer] -OnBootSec=15min -OnUnitActiveSec=5m - -[Install] -WantedBy=timers.target diff --git a/ttm/manager.py b/ttm/manager.py index 55d5555b..b8cd2a33 100644 --- a/ttm/manager.py +++ b/ttm/manager.py @@ -89,12 +89,12 @@ class ToTestManager(ToolBase.ToolBase): def totest(self, project): self.setup(project) try: - current_snapshot = self.get_current_snapshot() + current_snapshot = self.version_from_totest_project() except NotFoundException as e: # nothing in test project (yet) self.logger.warn(e) current_snapshot = None - new_snapshot = self.current_sources() + new_snapshot = self.version_from_project() self.update_pinned_descr = False current_result = self.overall_result(current_snapshot) current_qa_version = self.current_qa_version() @@ -157,7 +157,7 @@ class ToTestManager(ToolBase.ToolBase): def release(self, project): self.setup(project) - new_snapshot = self.current_sources() + new_snapshot = self.version_from_project() self.update_totest(new_snapshot) def write_version_to_dashboard(self, target, version): @@ -194,18 +194,17 @@ class ToTestManager(ToolBase.ToolBase): raise NotFoundException("can't find %s version" % self.project) - def current_sources(self): - if self.project.take_source_from_product is None: - raise Exception('No idea where to take the source version from') - - if self.project.take_source_from_product: - if self.project.is_image_product: - return self.iso_build_version(self.project.name, self.project.image_products[0].package, - arch=self.project.image_products[0].archs[0]) - return self.iso_build_version(self.project.name, self.project.main_products[0]) - else: + def version_from_project(self): + if not self.project.take_source_from_product: return self.release_version() + if len(self.project.main_products): + return self.iso_build_version(self.project.name, self.project.main_products[0]) + + #assert(self.project.is_image_product) + return self.iso_build_version(self.project.name, self.project.image_products[0].package, + arch=self.project.image_products[0].archs[0]) + def binaries_of_product(self, project, product, repo=None, arch=None): if repo is None: repo = self.project.product_repo @@ -225,11 +224,13 @@ class ToTestManager(ToolBase.ToolBase): return ret - def get_current_snapshot(self): - if self.project.is_image_product: - return self.iso_build_version(self.project.test_project, self.project.image_products[0].package, - arch=self.project.image_products[0].archs[0]) - return self.iso_build_version(self.project.test_project, self.project.main_products[0]) + def version_from_totest_project(self): + if len(self.project.main_products): + return self.iso_build_version(self.project.test_project, self.project.main_products[0]) + + return self.iso_build_version(self.project.test_project, self.project.image_products[0].package, + arch=self.project.image_products[0].archs[0]) + def ftp_build_version(self, project, tree): for binary in self.binaries_of_product(project, tree): From 32afd61501c3267ce7207f73fab9c1db735a38d8 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Wed, 27 Mar 2019 17:23:59 +0100 Subject: [PATCH 19/20] Remove is_image_product all together --- ttm/manager.py | 20 ++++++++++---------- ttm/totest.py | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/ttm/manager.py b/ttm/manager.py index b8cd2a33..3adb2a78 100644 --- a/ttm/manager.py +++ b/ttm/manager.py @@ -160,12 +160,17 @@ class ToTestManager(ToolBase.ToolBase): new_snapshot = self.version_from_project() self.update_totest(new_snapshot) - def write_version_to_dashboard(self, target, version): + def version_file(self, target): version_file = 'version_%s' % target - if self.project.is_image_product: + if not len(self.project.main_products): version_file = version_file + '_images' - if not (self.dryrun or self.norelease): - self.api.pseudometa_file_ensure(version_file, version, comment='Update version') + return version_file + + def write_version_to_dashboard(self, target, version): + if self.dryrun or self.norelease: + return + self.api.pseudometa_file_ensure(self.version_file(target), version, + comment='Update version') def load_issues_to_ignore(self): text = self.api.attribute_value_load('IgnoredIssues') @@ -201,7 +206,6 @@ class ToTestManager(ToolBase.ToolBase): if len(self.project.main_products): return self.iso_build_version(self.project.name, self.project.main_products[0]) - #assert(self.project.is_image_product) return self.iso_build_version(self.project.name, self.project.image_products[0].package, arch=self.project.image_products[0].archs[0]) @@ -247,11 +251,7 @@ class ToTestManager(ToolBase.ToolBase): raise NotFoundException("can't find %s iso version" % project) def current_qa_version(self): - version_file = 'version_totest' - if self.project.is_image_product: - version_file = 'version_totest_images' - - return self.api.pseudometa_file_load(version_file) + return self.api.pseudometa_file_load(self.version_file('totest')) def find_openqa_results(self, snapshot): """Return the openqa jobs of a given snapshot and filter out the diff --git a/ttm/totest.py b/ttm/totest.py index abcfabee..cb9503ac 100755 --- a/ttm/totest.py +++ b/ttm/totest.py @@ -50,7 +50,6 @@ class ToTest(object): self.jobs_num = 42 self.load_config(apiurl) self.test_project = '%s:%s' % (project, self.test_subproject) - self.is_image_product = not len(self.main_products) def load_config(self, apiurl): config = yaml.safe_load(attribute_value_load(apiurl, self.name, 'ToTestManagerConfig')) From 9e41f45f52342fc0ae3db25d59a9dc2a0aca062f Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Wed, 27 Mar 2019 19:59:17 +0100 Subject: [PATCH 20/20] Skip ttm subdir in nosetests --- .travis.yml | 6 +++--- dist/package/openSUSE-release-tools.spec | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 160a0424..27ea656f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,7 +72,7 @@ matrix: # Needs python prefix to use the correct interpretor. - python ./obs_clone.py --cache --debug --apiurl-target local script: - - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint --exclude-dir=./pkglistgen -c .noserc + - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint --exclude-dir=./pkglistgen --exclude-dir=./ttm -c .noserc after_success: - coveralls - env: TEST_SUITE=nosetests-osc-python3 @@ -100,7 +100,7 @@ matrix: # Needs python prefix to use the correct interpretor. - python ./obs_clone.py --cache --debug --apiurl-target local script: - - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint --exclude-dir=./pkglistgen -c .noserc + - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint --exclude-dir=./pkglistgen --exclude-dir=./ttm -c .noserc after_success: - coveralls - env: TEST_SUITE=nosetests-osc-python3 @@ -128,7 +128,7 @@ matrix: # Needs python prefix to use the correct interpretor. - python ./obs_clone.py --cache --debug --apiurl-target local script: - - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint -c .noserc + - nosetests --with-coverage --cover-package=. --cover-inclusive --exclude-dir=./oqamaint --exclude-dir=./ttm --exclude-dir=./pkglistgen -c .noserc after_success: - coveralls allow_failures: diff --git a/dist/package/openSUSE-release-tools.spec b/dist/package/openSUSE-release-tools.spec index 210c97a4..993a81eb 100644 --- a/dist/package/openSUSE-release-tools.spec +++ b/dist/package/openSUSE-release-tools.spec @@ -74,6 +74,9 @@ Requires: perl-XML-Parser # Spec related requirements. Requires: osclib = %{version} +# no longer deployed as package +Obsoletes: %{name}-totest-manager + # Avoid needlessly building on s390x and such in various repos. # Must include noarch for older systems even though it makes no sense due to # https://bugzilla.redhat.com/show_bug.cgi?id=1298668.