#499 New command `disable-monitoring`
Merged a year ago by onosek. Opened a year ago by onosek.
onosek/fedpkg disable_monitoring  into  master

file modified
+54 -2
@@ -34,8 +34,8 @@ 

  from fedpkg.completers import (build_arches, distgit_branches, fedpkg_packages,

                                 list_targets)

  from fedpkg.utils import (assert_new_tests_repo, assert_valid_epel_package,

-                           config_get_safely, do_add_remote, do_fork,

-                           expand_release, get_dist_git_url,

+                           config_get_safely, disable_monitoring, do_add_remote,

+                           do_fork, expand_release, get_dist_git_url,

                            get_fedora_release_state, get_pagure_branches,

                            get_release_branches, get_stream_branches, is_epel,

                            new_pagure_issue, sl_list_to_dict, verify_sls)
@@ -130,6 +130,7 @@ 

          self.register_override()

          self.register_set_distgit_token()

          self.register_set_pagure_token()

+         self.register_do_disable_monitoring()

  

      def setup_completers(self):

          """
@@ -721,6 +722,39 @@ 

              targets to build the package for a particular stream.

          '''.format('\n'.join(textwrap.wrap(build_parser.description))))

  

+     def register_do_disable_monitoring(self):

+         help_msg = 'Disable monitoring of the current repository'

+         distgit_section = '{0}.distgit'.format(self.name)

+         distgit_api_base_url = config_get_safely(self.config, distgit_section, "apibaseurl")

+ 

+         description = textwrap.dedent('''

+             Disable monitoring of the current repository

+ 

+             No arguments are needed.

+             Before the operation, you need to generate a pagure.io API token at:

+                 https://{1}/settings/token/new

+ 

+             ACL required:

+                 "Modify an existing project"

+ 

+             Update your token with the following command:

+                 fedpkg set-distgit-token <api_key_here>

+ 

+             Command saves token to fedpkg config file:

+                 ~/.config/rpkg/{0}.conf

+ 

+             For example:

+                 [{0}.distgit]

+                 token = <api_key_here>

+         '''.format(self.name, urlparse(distgit_api_base_url).netloc))

+ 

+         disable_monitoring_parser = self.subparsers.add_parser(

+             'disable-monitoring',

+             formatter_class=argparse.RawDescriptionHelpFormatter,

+             help=help_msg,

+             description=description)

+         disable_monitoring_parser.set_defaults(command=self.do_disable_monitoring)

+ 

      # Target functions go here

      def _format_update_clog(self, clog):

          ''' Format clog for the update template. '''
@@ -1516,12 +1550,30 @@ 

          # Allow retiring in epel

          if is_epel(self.cmd.branch_merge):

              super(fedpkgClient, self).retire()

+             self.do_disable_monitoring()

          else:

              state = get_fedora_release_state(self.config, self.name, self.cmd.branch_merge)

  

              # Allow retiring in Rawhide and Branched until Final Freeze

              if state is None or state == 'pending':

                  super(fedpkgClient, self).retire()

+                 self.do_disable_monitoring()

              else:

                  self.log.error("Fedora release (%s) is in state '%s' - retire operation "

                                 "is not allowed." % (self.cmd.branch_merge, state))

+ 

+     def do_disable_monitoring(self):

+         """

+         Disable monitoring when package is retired.

+         """

+         distgit_section = '{0}.distgit'.format(self.name)

+         distgit_api_base_url = config_get_safely(self.config, distgit_section, "apibaseurl")

+         distgit_token = config_get_safely(self.config, distgit_section, 'token')

+         disable_monitoring(

+             logger=self.log,

+             base_url=distgit_api_base_url,

+             token=distgit_token,

+             repo_name=self.cmd.repo_name,

+             namespace=self.cmd.ns,

+             cli_name=self.name,

+         )

file modified
+51
@@ -645,3 +645,54 @@ 

          raise rpkgError("{0}\n{1}".format(msg, hint))

      except Exception:

          raise

+ 

+ 

+ def disable_monitoring(logger, base_url, token, repo_name, namespace, cli_name):

+     """

+     Disable monitoring when package is retired.

+     :param logger: A logger object

+     :param base_url: a string of the URL repository

+     :param token: a string of the API token that has rights to modify the project

+     :param repo_name: a string of the repository name

+     :param namespace: a string determines a type of the repository

+     :param cli_name: string of the CLI's name (e.g. fedpkg)

+     :return: a bool; True when monitoring wa disabled, False when failed to disable

+     """

+     pagure_anitya_status_url = '{0}/_dg/anitya/{1}/{2}'.format(

+         base_url.rstrip('/'), namespace, repo_name)

+     logger.debug('Pagure API request URL: {0}'.format(pagure_anitya_status_url))

+     headers = {

+         'Authorization': 'token {0}'.format(token.strip('"').strip("'")),

+         'Accept': 'application/json',

+         'Content-Type': 'application/json'

+     }

+     payload = json.dumps({

+         'anitya_status': 'no-monitoring',

+     })

+ 

+     try:

+         rv = requests.post(

+             pagure_anitya_status_url, headers=headers, data=payload, timeout=90)

+     except ConnectionError as error:

+         error_msg = ('The connection to API failed while trying to disable monitoring '

+                      'of the project. The error was: {0}'.format(str(error)))

+         raise rpkgError(error_msg)

+ 

+     try:

+         # Extract response error text (and debug data)

+         rv_json = rv.json()

+         logger.debug("Pagure API response: '{0}'".format(rv_json))

+         rv_error = rv_json.get('error')

+     except (ValueError, AttributeError):

+         rv_error = rv.text

+ 

+     base_error_msg = ('The following error occurred while disabling monitoring: {0}')

+     if not rv.ok:

+         # show hint for expired token

+         if re.search(r"Invalid or expired token", rv_error, re.IGNORECASE):

+             base_error_msg += '\nFor invalid or expired tokens please ' \

+                 'set a new token in your user configuration with:' \

+                 '\n\n\t{0} set-distgit-token <token>\n'.format(cli_name)

+         raise rpkgError(base_error_msg.format(rv_error))

+ 

+     logger.info("Monitoring of the project was sucessfully disabled.")

file modified
+1
@@ -25,3 +25,4 @@ 

  

  [fedpkg.distgit]

  apibaseurl = https://src.example.com

+ token = notsecretatall

file modified
+57 -4
@@ -5,10 +5,12 @@ 

  import subprocess

  import tempfile

  

+ import six

+ from pyrpkg.errors import rpkgError

  from six.moves import configparser

+ from utils import unittest

  

  from fedpkg.cli import fedpkgClient

- from utils import unittest

  

  try:

      from unittest import mock
@@ -76,8 +78,14 @@ 

                                                       'fedpkg.spec')))

          self.assertEqual(self._get_latest_commit(), reason)

  

+     @mock.patch('requests.post')

      @mock.patch("requests.get", new=lambda *args, **kwargs: mock.Mock(status_code=404))

-     def test_retire_with_namespace(self):

+     def test_retire_with_namespace(self, requests_post):

+         mock_rv = mock.Mock()

+         mock_rv.ok = True

+         mock_rv.json.return_value = {"anitya_status": "no-monitoring"}

+         requests_post.return_value = mock_rv

+ 

          self._setup_repo('ssh://git@pkgs.example.com/rpms/fedpkg')

          args = ['fedpkg', '--release=rawhide', 'retire', 'my reason']

  
@@ -87,8 +95,52 @@ 

          self.assertRetired('my reason')

          self.assertEqual(len(client.cmd.push.call_args_list), 1)

  

+         url = 'https://src.example.com/_dg/anitya/rpms/fedpkg'

+         data = '{"anitya_status": "no-monitoring"}'

+         headers = {

+             'Authorization': 'token notsecretatall',

+             'Accept': 'application/json',

+             'Content-Type': 'application/json'

+         }

+         requests_post.assert_called_once_with(url, data=data, headers=headers, timeout=90)

+ 

+     @mock.patch('requests.post')

+     @mock.patch("requests.get", new=lambda *args, **kwargs: mock.Mock(status_code=404))

+     def test_retire_with_namespace_disable_monitoring_fails(self, requests_post):

+         """

+         retire operation itself runs fine, but subsequent procedure disable-monitoring fails

+         """

+         mock_rv = mock.Mock()

+         mock_rv.ok = False

+         mock_rv.json.return_value = {"error": "Invalid or expired token"}

+         requests_post.return_value = mock_rv

+ 

+         self._setup_repo('ssh://git@pkgs.example.com/rpms/fedpkg')

+         args = ['fedpkg', '--release=rawhide', 'retire', 'my reason']

+ 

+         client = self._fake_client(args)

+         self.assertRaisesRegex(

+             rpkgError,

+             "The following error occurred while disabling monitoring: Invalid or expired token\n"

+             "For invalid or expired tokens please set a new token",

+             client.retire

+         )

+ 

+         self.assertRetired('my reason')

+         self.assertEqual(len(client.cmd.push.call_args_list), 1)

+ 

+         url = 'https://src.example.com/_dg/anitya/rpms/fedpkg'

+         data = '{"anitya_status": "no-monitoring"}'

+         headers = {

+             'Authorization': 'token notsecretatall',

+             'Accept': 'application/json',

+             'Content-Type': 'application/json'

+         }

+         requests_post.assert_called_once_with(url, data=data, headers=headers, timeout=90)

+ 

+     @mock.patch('requests.post')

      @mock.patch("requests.get", new=lambda *args, **kwargs: mock.Mock(status_code=404))

-     def test_retire_without_namespace(self):

+     def test_retire_without_namespace(self, requests_post):

          self._setup_repo('ssh://git@pkgs.example.com/fedpkg')

          args = ['fedpkg', '--release=rawhide', 'retire', 'my reason']

  
@@ -98,8 +150,9 @@ 

          self.assertRetired('my reason')

          self.assertEqual(len(client.cmd.push.call_args_list), 1)

  

+     @mock.patch('requests.post')

      @mock.patch("requests.get", new=lambda *args, **kwargs: mock.Mock(status_code=404))

-     def test_package_is_retired_already(self):

+     def test_package_is_retired_already(self, requests_post):

          self._setup_repo('ssh://git@pkgs.example.com/fedpkg')

          with open(os.path.join(self.tmpdir, 'dead.package'), 'w') as f:

              f.write('dead package')

After the repository is retired, its monitoring needs to be disabled.

Relates: https://pagure.io/releng/issue/10724
JIRA: RHELCMP-11025

Signed-off-by: Ondrej Nosek onosek@redhat.com

Hi @lenkaseg,

please check the code and functionality. For POST requests I am obtaining 401 every time (even for a token with all ACLs). Is this functionality accessible just for Pagure admins?
The code doesn't contain unit tests so far.

Thanks

Should not need to be pagure admin, because I am not and it worked for me...

I think the token had to be in the form of "token <the actual token>"
I solved it like this: https://pagure.io/rpkg/pull-request/646#_1__17
Modifying the token string and removing any quotes if present. I can be probably done better :)

rebased onto 1857acff13ddfde788d5a23df2ebde23d9e70054

a year ago

rebased onto 2d42179d9f83439bb8e9b44fa8c72a8d3e911e83

a year ago

rebased onto cdb93640437b5eb26f68c80c9609c3abcb3fc990

a year ago

rebased onto 7f1b8c7

a year ago

Pull-Request has been merged by onosek

a year ago