[PATCH] enhancements to rpkg

Mike Bonnet mikeb at redhat.com
Thu Oct 30 20:21:45 UTC 2014


Hi.  Attached are a couple of enhancements to rpkg.  The first adds a 
--runas option.  This allows you to run Koji commands as a different 
user, if the Koji hub has been configured to allow you to do so.  This 
is useful for automation that launches builds on behalf of other users. 
  The other patch fixes support for password authentication (it has 
never worked correctly) and cleans up Koji session creation, so all 
relevant config options are passed through to the new session.  This 
should improve compatibility between the Koji cli and rpkg.  Let me know 
if there are any questions.

Thanks,
Mike
-------------- next part --------------
From 6e1467872b3d715c2aa04ca9c3d4f27396050991 Mon Sep 17 00:00:00 2001
From: Mike Bonnet <mikeb at redhat.com>
Date: Thu, 30 Oct 2014 12:58:32 -0400
Subject: [PATCH 1/2] add --runas option

---
 src/pyrpkg/__init__.py |   17 ++++++++++++++---
 src/pyrpkg/cli.py      |    5 +++++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/pyrpkg/__init__.py b/src/pyrpkg/__init__.py
index 57d187e..bb8d78c 100644
--- a/src/pyrpkg/__init__.py
+++ b/src/pyrpkg/__init__.py
@@ -70,7 +70,7 @@ class Commands(object):
 
     def __init__(self, path, lookaside, lookasidehash, lookaside_cgi,
                  gitbaseurl, anongiturl, branchre, kojiconfig,
-                 build_client, user=None, dist=None, target=None,
+                 build_client, user=None, runas=None, dist=None, target=None,
                  quiet=False):
         """Init the object and some configuration details."""
 
@@ -142,6 +142,8 @@ class Commands(object):
         self._topurl = None
         # The user to use or discover
         self._user = user
+        # The alternate Koji user to run commands as
+        self._runas = runas
         # The rpm version of the cloned module
         self._ver = None
         self.log = log
@@ -246,16 +248,19 @@ class Commands(object):
                 defaults['authtype'] is None:
                     self._kojisession.ssl_login(defaults['cert'],
                                                 defaults['ca'],
-                                                defaults['serverca'])
+                                                defaults['serverca'],
+                                                proxyuser=self.runas)
                 # Or try password auth
                 elif defaults['authtype'] == 'password' or \
                 'user' in defaults and defaults['authtype'] is None:
+                    if self.runas is not None:
+                        raise rpkgError('--runas cannot be used with password auth')
                     self._kojisession.login()
                 # Or try kerberos
                 elif defaults['authtype'] == 'kerberos' or \
                 self._has_krb_creds() and \
                 defaults['authtype'] is None:
-                    self._kojisession.krb_login()
+                    self._kojisession.krb_login(proxyuser=self.runas)
                 if not self._kojisession.logged_in:
                     raise rpkgError('Could not auth with koji as %s' %
                                     self.user)
@@ -655,6 +660,12 @@ class Commands(object):
         self._user = os.getlogin()
 
     @property
+    def runas(self):
+        """This property ensures the runas attribute"""
+
+        return self._runas
+
+    @property
     def ver(self):
         """This property ensures the ver attribute"""
         if not self._ver:
diff --git a/src/pyrpkg/cli.py b/src/pyrpkg/cli.py
index 80812e6..a6b02d4 100755
--- a/src/pyrpkg/cli.py
+++ b/src/pyrpkg/cli.py
@@ -104,6 +104,7 @@ class cliClient(object):
                                        items['kojiconfig'],
                                        items['build_client'],
                                        user=self.args.user,
+                                       runas=self.args.runas,
                                        dist=self.args.dist,
                                        target=target,
                                        quiet=self.args.q,
@@ -157,6 +158,10 @@ class cliClient(object):
         # Override the  discovered user name
         self.parser.add_argument('--user', default=None,
                                  help='Override the discovered user name')
+        # Run Koji commands as a user other then the one you have
+        # credentials for (requires configuration on the Koji hub)
+        self.parser.add_argument('--runas', default=None,
+                                 help='Run Koji commands as a different user')
         # Let the user define a path to work in rather than cwd
         self.parser.add_argument('--path', default=None,
                                  help='Define the directory to work in '
-- 
1.7.1
-------------- next part --------------
From 3f8a57e733bdcc410c448f3600e0c0ffcb71feb0 Mon Sep 17 00:00:00 2001
From: Mike Bonnet <mikeb at redhat.com>
Date: Thu, 30 Oct 2014 14:02:09 -0400
Subject: [PATCH 2/2] clean up Koji login, and properly support password auth

---
 src/pyrpkg/__init__.py |  148 +++++++++++++++++++++++++++++-------------------
 src/pyrpkg/cli.py      |    4 +
 2 files changed, 93 insertions(+), 59 deletions(-)

diff --git a/src/pyrpkg/__init__.py b/src/pyrpkg/__init__.py
index bb8d78c..0879622 100644
--- a/src/pyrpkg/__init__.py
+++ b/src/pyrpkg/__init__.py
@@ -70,8 +70,8 @@ class Commands(object):
 
     def __init__(self, path, lookaside, lookasidehash, lookaside_cgi,
                  gitbaseurl, anongiturl, branchre, kojiconfig,
-                 build_client, user=None, runas=None, dist=None, target=None,
-                 quiet=False):
+                 build_client, user=None, password=None, runas=None,
+                 dist=None, target=None, quiet=False):
         """Init the object and some configuration details."""
 
         # Path to operate on, most often pwd
@@ -142,6 +142,8 @@ class Commands(object):
         self._topurl = None
         # The user to use or discover
         self._user = user
+        # The password to use
+        self._password = password
         # The alternate Koji user to run commands as
         self._runas = runas
         # The rpm version of the cloned module
@@ -190,50 +192,71 @@ class Commands(object):
         # Stealing a bunch of code from /usr/bin/koji here, too bad it isn't
         # in a more usable library form
         defaults = {
-                    'server' : 'http://localhost/kojihub',
-                    'weburl' : 'http://localhost/koji',
-                    'pkgurl' : 'http://localhost/packages',
-                    'topdir' : '/mnt/koji',
-                    'cert': '~/.koji/client.crt',
-                    'ca': '~/.koji/clientca.crt',
-                    'serverca': '~/.koji/serverca.crt',
-                    'krbservice' : 'host',
-                    'authtype': None,
-                    'topurl': None
-                    }
-        # Process the configs in order, global, user, then any option passed
-        for configfile in (self.kojiconfig,
-                           os.path.expanduser('~/.koji/config')):
-            try:
-                f = open(configfile)
-            except IOError:
-                self.log.debug("Could not read %s for config values" %
-                               configfile)
+            'server': None,
+            'topurl': 'http://localhost/kojiroot',
+            'weburl' : 'http://localhost/koji',
+            'cert': '~/.koji/client.crt',
+            'ca': '~/.koji/clientca.crt',
+            'serverca': '~/.koji/serverca.crt',
+            'authtype': None,
+            'krbservice': None,
+            'timeout' : None,
+            'keepalive' : True,
+            'max_retries': None,
+            'retry_interval': None,
+            'anon_retry' : True,
+            'offline_retry' : None,
+            'offline_retry_interval' : None,
+            'use_fast_upload': None,
+            'debug': None,
+            'debug_xmlrpc': None
+            }
 
-            else:
-                with f:
-                    config = ConfigParser.ConfigParser()
-                    config.readfp(f)
-
-                if config.has_section(os.path.basename(self.build_client)):
-                    for name, value in config.items(os.path.basename(
-                                                    self.build_client)):
-                        if defaults.has_key(name):
-                            defaults[name] = value
+        # Process the configs in order, global, user, then any option passed
+        config = ConfigParser.ConfigParser()
+        confs = [self.kojiconfig,
+                 os.path.expanduser('~/.koji/config')]
+        config.read(confs)
+
+        if config.has_section(os.path.basename(self.build_client)):
+            for name, value in config.items(os.path.basename(
+                    self.build_client)):
+                if name in defaults:
+                    if name in ('keepalive', 'anon_retry', 'offline_retry',
+                                'use_fast_upload',
+                                'debug', 'debug_xmlrpc'):
+                        defaults[name] = config.getboolean(os.path.basename(
+                                self.build_client), name)
+                    elif name in ('timeout', 'max_retries', 'retry_interval',
+                                  'offline_retry_interval'):
+                        defaults[name] = config.getint(os.path.basename(
+                                self.build_client), name)
+                    else:
+                        defaults[name] = value
+        if not defaults['server']:
+            raise rpkgError('No server defined in: %s' % ', '.join(confs))
         # Expand out the directory options
-        for name in ('topdir', 'cert', 'ca', 'serverca', 'topurl', 'krbservice'):
+        for name in ('cert', 'ca', 'serverca'):
             if defaults[name]:
                 defaults[name] = os.path.expanduser(defaults[name])
         self.log.debug('Initiating a %s session to %s' %
                        (os.path.basename(self.build_client),
                         defaults['server']))
+        session_opts = {}
+        for name in ('krbservice', 'timeout', 'keepalive',
+                     'max_retries', 'retry_interval', 'anon_retry',
+                     'offline_retry', 'offline_retry_interval',
+                     'debug', 'debug_xmlrpc',
+                     'use_fast_upload'):
+            if defaults[name] is not None:
+                session_opts[name] = defaults[name]
         try:
-            if not anon:
-                session_opts = {'user': self.user}
+            if anon:
+                self._anon_kojisession = koji.ClientSession(defaults['server'],
+                                                            session_opts)
+            else:
                 self._kojisession = koji.ClientSession(defaults['server'],
                                                        session_opts)
-            else:
-                self._anon_kojisession = koji.ClientSession(defaults['server'])
         except:
             raise rpkgError('Could not initiate %s session' %
                             os.path.basename(self.build_client))
@@ -241,29 +264,30 @@ class Commands(object):
         self._kojiweburl = defaults['weburl']
         self._topurl = defaults['topurl']
         if not anon:
-                # Default to ssl if not otherwise specified and we have
-                # the cert
-                if defaults['authtype'] == 'ssl' or \
-                os.path.isfile(defaults['cert']) and \
-                defaults['authtype'] is None:
-                    self._kojisession.ssl_login(defaults['cert'],
-                                                defaults['ca'],
-                                                defaults['serverca'],
-                                                proxyuser=self.runas)
-                # Or try password auth
-                elif defaults['authtype'] == 'password' or \
-                'user' in defaults and defaults['authtype'] is None:
-                    if self.runas is not None:
-                        raise rpkgError('--runas cannot be used with password auth')
-                    self._kojisession.login()
-                # Or try kerberos
-                elif defaults['authtype'] == 'kerberos' or \
-                self._has_krb_creds() and \
-                defaults['authtype'] is None:
-                    self._kojisession.krb_login(proxyuser=self.runas)
-                if not self._kojisession.logged_in:
-                    raise rpkgError('Could not auth with koji as %s' %
-                                    self.user)
+            # Default to ssl if not otherwise specified and we have
+            # the cert
+            if defaults['authtype'] == 'ssl' or \
+                    (os.path.isfile(defaults['cert']) and \
+                         defaults['authtype'] is None):
+                self._kojisession.ssl_login(defaults['cert'],
+                                            defaults['ca'],
+                                            defaults['serverca'],
+                                            proxyuser=self.runas)
+            # Or try password auth
+            elif defaults['authtype'] == 'password' or \
+                    (self.password and defaults['authtype'] is None):
+                if self.runas:
+                    raise rpkgError('--runas cannot be used with password auth')
+                self._kojisession.opts['user'] = self.user
+                self._kojisession.opts['password'] = self.password
+                self._kojisession.login()
+            # Or try kerberos
+            elif defaults['authtype'] == 'kerberos' or \
+                    (self._has_krb_creds() and \
+                         defaults['authtype'] is None):
+                self._kojisession.krb_login(proxyuser=self.runas)
+            if not self._kojisession.logged_in:
+                raise rpkgError('Could not login to %s' % defaults['server'])
 
     @property
     def branch_merge(self):
@@ -660,6 +684,12 @@ class Commands(object):
         self._user = os.getlogin()
 
     @property
+    def password(self):
+        """This property ensures the password attribute"""
+
+        return self._password
+
+    @property
     def runas(self):
         """This property ensures the runas attribute"""
 
diff --git a/src/pyrpkg/cli.py b/src/pyrpkg/cli.py
index a6b02d4..e743850 100755
--- a/src/pyrpkg/cli.py
+++ b/src/pyrpkg/cli.py
@@ -104,6 +104,7 @@ class cliClient(object):
                                        items['kojiconfig'],
                                        items['build_client'],
                                        user=self.args.user,
+                                       password=self.args.password,
                                        runas=self.args.runas,
                                        dist=self.args.dist,
                                        target=target,
@@ -158,6 +159,9 @@ class cliClient(object):
         # Override the  discovered user name
         self.parser.add_argument('--user', default=None,
                                  help='Override the discovered user name')
+        # If using password auth
+        self.parser.add_argument('--password', default=None,
+                                 help='Password for Koji login')
         # Run Koji commands as a user other then the one you have
         # credentials for (requires configuration on the Koji hub)
         self.parser.add_argument('--runas', default=None,
-- 
1.7.1


More information about the buildsys mailing list