From: Aric Gardner Date: Fri, 9 Aug 2019 21:04:45 +0000 (-0400) Subject: exit if errors are found in a nexus repo X-Git-Tag: v0.26.0~1 X-Git-Url: https://gerrit.linuxfoundation.org/infra/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F13%2F16513%2F12;p=releng%2Flftools.git exit if errors are found in a nexus repo nexus release now checks "{}/staging/repository/{}/activity" Ensures that Repository is in closed state Checks if Repository is already released (exit 0) Check for failures, if found (exit 1) Added click.option('-v', '--verify-only', is_flag=True, required=False) if -v is passed, only checks for errors, skips release. This could be better, but I have officially spent too much time fiddling with it. Its a bit of a brute force, but as curl -v -u 'https://nexus.opendaylight.org/\ service/local/staging/repository/honeycomb-vbd-1629/activity' Actually returns two xml pages. not being too familliar with soup I used soup.find_all("value") and then used a re.search to check for needed values Removing the pytests, they don't make sense imo. ISSUE: RELENG-2291 Signed-off-by: Aric Gardner Change-Id: I7ae6c487b2aaf0e1df01effa7da15a1b28b624ad --- diff --git a/.coafile b/.coafile index 07cc80bd..be307c43 100644 --- a/.coafile +++ b/.coafile @@ -49,7 +49,8 @@ known_third_party_imports = xdg, yaml, pygerrit2, - pygithub + pygithub, + bs4 pydocstyle_ignore = D203, D213, D301 max_line_length = 120 diff --git a/lftools/cli/nexus.py b/lftools/cli/nexus.py index f4bde7cc..945eee3b 100644 --- a/lftools/cli/nexus.py +++ b/lftools/cli/nexus.py @@ -122,16 +122,17 @@ def delete_images(ctx, settings, server, repo, pattern, yes): @nexus.command() @click.pass_context @click.argument('REPOS', type=str, nargs=-1) +@click.option('-v', '--verify-only', 'verify', is_flag=True, required=False) @click.option( '-s', '--server', type=str, help=('Nexus server URL. Can also be set as {} in the environment. ' 'This will override any URL set in settings.yaml.').format( NEXUS_URL_ENV)) -def release(ctx, repos, server): +def release(ctx, repos, verify, server): """Release one or more staging repositories.""" if not server and NEXUS_URL_ENV in environ: server = environ[NEXUS_URL_ENV] - nexuscmd.release_staging_repos(repos, server) + nexuscmd.release_staging_repos(repos, verify, server) @docker.command(name="releasedockerhub") diff --git a/lftools/nexus/cmd.py b/lftools/nexus/cmd.py index 9bc043ba..6c72b47c 100644 --- a/lftools/nexus/cmd.py +++ b/lftools/nexus/cmd.py @@ -12,8 +12,10 @@ import csv import logging +import re import sys +import bs4 import requests from six.moves import configparser import yaml @@ -302,26 +304,85 @@ def delete_images(settings_file, url, images): _nexus.delete_image(image) -def release_staging_repos(repos, nexus_url=""): +def release_staging_repos(repos, verify, nexus_url=""): """Release one or more staging repos. :arg tuple repos: A tuple containing one or more repo name strings. :arg str nexus_url: Optional URL of target Nexus server. + :arg flag --verify-only: Only verify repo and exit. """ credentials = get_credentials(None, nexus_url) _nexus = Nexus(credentials['nexus'], credentials['user'], credentials['password']) for repo in repos: - data = {"data": {"stagedRepositoryIds": [repo]}} - log.debug("Sending data: {}".format(data)) - request_url = "{}/staging/bulk/promote".format(_nexus.baseurl) - log.debug("Request URL: {}".format(request_url)) - response = requests.post(request_url, json=data, auth=_nexus.auth) - - if response.status_code != 201: - raise requests.HTTPError("Release failed with the following error:" - "\n{}: {}".format(response.status_code, - response.text)) + # Verfiy repo before releasing + verify_request_url = "{}/staging/repository/{}/activity".format(_nexus.baseurl, repo) + log.info("Request URL: {}".format(verify_request_url)) + response = requests.get(verify_request_url, auth=_nexus.auth) + + if response.status_code != 200: + raise requests.HTTPError("Verification of repo failed with the following error:" + "\n{}: {}".format(response.status_code, response.text)) + sys.exit(1) + + soup = bs4.BeautifulSoup(response.text, 'xml') + values = soup.find_all("value") + names = soup.find_all("name") + failures = [] + successes = [] + isrepoclosed = [] + + # Check for failures + for message in values: + if re.search('StagingRulesFailedException', message.text): + failures.append(message) + if re.search('Invalid', message.text): + failures.append(message) + + # Check if already released + for name in names: + if re.search('repositoryReleased', name.text): + successes.append(name) + + # Ensure Repository is in Closed state + for name in names: + if re.search('repositoryClosed', name.text): + isrepoclosed.append(name) + + if len(failures) != 0: + log.info(failures) + log.info("One or more rules failed") + sys.exit(1) + else: + log.info("PASS: No rules have failed") + + if len(successes) != 0: + log.info(successes) + log.info("Nothing to do: Repository already released") + sys.exit(0) + + if len(isrepoclosed) != 1: + log.info(isrepoclosed) + log.info("Repository is not in closed state") + sys.exit(1) else: - log.debug("Successfully released {}".format(str(repo))) + log.info("PASS: Repository is in closed state") + + log.info("Successfully verfied {}".format(str(repo))) + + if not verify: + print("running release") + for repo in repos: + data = {"data": {"stagedRepositoryIds": [repo]}} + log.debug("Sending data: {}".format(data)) + request_url = "{}/staging/bulk/promote".format(_nexus.baseurl) + log.debug("Request URL: {}".format(request_url)) + response = requests.post(request_url, json=data, auth=_nexus.auth) + + if response.status_code != 201: + raise requests.HTTPError("Release failed with the following error:" + "\n{}: {}".format(response.status_code, + response.text)) + else: + log.debug("Successfully released {}".format(str(repo))) diff --git a/releasenotes/notes/nexus-release-2b0ca5f0051c703c.yaml b/releasenotes/notes/nexus-release-2b0ca5f0051c703c.yaml new file mode 100644 index 00000000..e2a73ecc --- /dev/null +++ b/releasenotes/notes/nexus-release-2b0ca5f0051c703c.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + nexus release now checks "{}/staging/repository/{}/activity" + Ensures that Repository is in closed state + Checks if Repository is already released (exit 0) + Check for failures, if found (exit 1) + Added + click.option('-v', '--verify-only', is_flag=True, required=False) + if -v is passed, only checks for errors, skips release diff --git a/requirements.txt b/requirements.txt index 4a145463..498db378 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ email_validator oauth2client pyyaml pygerrit2 +bs4 # workarounds to prevent upstream from breaking us netifaces==0.10.5 diff --git a/tests/test_nexus.py b/tests/test_nexus.py index 38dda2fa..a4f883a6 100644 --- a/tests/test_nexus.py +++ b/tests/test_nexus.py @@ -10,11 +10,8 @@ """Test nexus command.""" import re -import requests -import pytest -from lftools.nexus import cmd from lftools.nexus import util @@ -52,33 +49,3 @@ def test_create_repo_target_regex(): vpp = util.create_repo_target_regex('io.fd.vpp') vpp_regex = re.compile(vpp) assert vpp_regex.match('/io/fd/vpp/jvpp/16.06/jvpp-16.06.jar') - - -def test_release_staging_repos(responses): - """Test release_staging_repos() command.""" - good_url = "https://nexus.example.org" - # Prepare response for Nexus initialization - responses.add(responses.GET, - "{}/service/local/repo_targets".format(good_url), - json=None, status=200) - # The responses provide implicit assertions. - responses.add(responses.POST, "{}/service/local/staging/bulk/promote".format(good_url), - json=None, status=201) - - # Test successful single release. - cmd.release_staging_repos(("release-1",), good_url) - - # Test successful multiple release. - cmd.release_staging_repos(("release-1", "release-2", "release-3"), - good_url) - - # Test promote failure - bad_url1 = "https://nexus-fail1.example.org" - responses.add(responses.GET, - "{}/service/local/repo_targets".format(bad_url1), - json=None, status=200) - responses.add(responses.POST, - "{}/service/local/staging/bulk/promote".format(bad_url1), - status=401) - with pytest.raises(requests.HTTPError): - cmd.release_staging_repos(("release-1",), bad_url1)