mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2025-10-25 13:34:01 -07:00 
			
		
		
		
	* sanity: Add future boilerplate Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> * Module Utils Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> * Scripts Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> * sanity: Add future boilerplate * Tests Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com> * CI failure Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
		
			
				
	
	
		
			270 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # This code is part of Ansible, but is an independent component.
 | |
| # This particular file snippet, and this file snippet only, is BSD licensed.
 | |
| # Modules you write using this snippet, which is embedded dynamically by Ansible
 | |
| # still belong to the author of the module, and may assign their own license
 | |
| # to the complete work.
 | |
| #
 | |
| # Copyright (c), James Laska
 | |
| #
 | |
| # Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
 | |
| 
 | |
| from __future__ import (absolute_import, division, print_function)
 | |
| __metaclass__ = type
 | |
| 
 | |
| 
 | |
| import os
 | |
| import re
 | |
| import shutil
 | |
| import tempfile
 | |
| import types
 | |
| 
 | |
| from ansible.module_utils.six.moves import configparser
 | |
| 
 | |
| 
 | |
| class RegistrationBase(object):
 | |
|     def __init__(self, module, username=None, password=None):
 | |
|         self.module = module
 | |
|         self.username = username
 | |
|         self.password = password
 | |
| 
 | |
|     def configure(self):
 | |
|         raise NotImplementedError("Must be implemented by a sub-class")
 | |
| 
 | |
|     def enable(self):
 | |
|         # Remove any existing redhat.repo
 | |
|         redhat_repo = '/etc/yum.repos.d/redhat.repo'
 | |
|         if os.path.isfile(redhat_repo):
 | |
|             os.unlink(redhat_repo)
 | |
| 
 | |
|     def register(self):
 | |
|         raise NotImplementedError("Must be implemented by a sub-class")
 | |
| 
 | |
|     def unregister(self):
 | |
|         raise NotImplementedError("Must be implemented by a sub-class")
 | |
| 
 | |
|     def unsubscribe(self):
 | |
|         raise NotImplementedError("Must be implemented by a sub-class")
 | |
| 
 | |
|     def update_plugin_conf(self, plugin, enabled=True):
 | |
|         plugin_conf = '/etc/yum/pluginconf.d/%s.conf' % plugin
 | |
| 
 | |
|         if os.path.isfile(plugin_conf):
 | |
|             tmpfd, tmpfile = tempfile.mkstemp()
 | |
|             shutil.copy2(plugin_conf, tmpfile)
 | |
|             cfg = configparser.ConfigParser()
 | |
|             cfg.read([tmpfile])
 | |
| 
 | |
|             if enabled:
 | |
|                 cfg.set('main', 'enabled', 1)
 | |
|             else:
 | |
|                 cfg.set('main', 'enabled', 0)
 | |
| 
 | |
|             fd = open(tmpfile, 'w+')
 | |
|             cfg.write(fd)
 | |
|             fd.close()
 | |
|             self.module.atomic_move(tmpfile, plugin_conf)
 | |
| 
 | |
|     def subscribe(self, **kwargs):
 | |
|         raise NotImplementedError("Must be implemented by a sub-class")
 | |
| 
 | |
| 
 | |
| class Rhsm(RegistrationBase):
 | |
|     def __init__(self, module, username=None, password=None):
 | |
|         RegistrationBase.__init__(self, module, username, password)
 | |
|         self.config = self._read_config()
 | |
|         self.module = module
 | |
| 
 | |
|     def _read_config(self, rhsm_conf='/etc/rhsm/rhsm.conf'):
 | |
|         '''
 | |
|             Load RHSM configuration from /etc/rhsm/rhsm.conf.
 | |
|             Returns:
 | |
|              * ConfigParser object
 | |
|         '''
 | |
| 
 | |
|         # Read RHSM defaults ...
 | |
|         cp = configparser.ConfigParser()
 | |
|         cp.read(rhsm_conf)
 | |
| 
 | |
|         # Add support for specifying a default value w/o having to standup some configuration
 | |
|         # Yeah, I know this should be subclassed ... but, oh well
 | |
|         def get_option_default(self, key, default=''):
 | |
|             sect, opt = key.split('.', 1)
 | |
|             if self.has_section(sect) and self.has_option(sect, opt):
 | |
|                 return self.get(sect, opt)
 | |
|             else:
 | |
|                 return default
 | |
| 
 | |
|         cp.get_option = types.MethodType(get_option_default, cp, configparser.ConfigParser)
 | |
| 
 | |
|         return cp
 | |
| 
 | |
|     def enable(self):
 | |
|         '''
 | |
|             Enable the system to receive updates from subscription-manager.
 | |
|             This involves updating affected yum plugins and removing any
 | |
|             conflicting yum repositories.
 | |
|         '''
 | |
|         RegistrationBase.enable(self)
 | |
|         self.update_plugin_conf('rhnplugin', False)
 | |
|         self.update_plugin_conf('subscription-manager', True)
 | |
| 
 | |
|     def configure(self, **kwargs):
 | |
|         '''
 | |
|             Configure the system as directed for registration with RHN
 | |
|             Raises:
 | |
|               * Exception - if error occurs while running command
 | |
|         '''
 | |
|         args = ['subscription-manager', 'config']
 | |
| 
 | |
|         # Pass supplied **kwargs as parameters to subscription-manager.  Ignore
 | |
|         # non-configuration parameters and replace '_' with '.'.  For example,
 | |
|         # 'server_hostname' becomes '--system.hostname'.
 | |
|         for k, v in kwargs.items():
 | |
|             if re.search(r'^(system|rhsm)_', k):
 | |
|                 args.append('--%s=%s' % (k.replace('_', '.'), v))
 | |
| 
 | |
|         self.module.run_command(args, check_rc=True)
 | |
| 
 | |
|     @property
 | |
|     def is_registered(self):
 | |
|         '''
 | |
|             Determine whether the current system
 | |
|             Returns:
 | |
|               * Boolean - whether the current system is currently registered to
 | |
|                           RHN.
 | |
|         '''
 | |
|         args = ['subscription-manager', 'identity']
 | |
|         rc, stdout, stderr = self.module.run_command(args, check_rc=False)
 | |
|         if rc == 0:
 | |
|             return True
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
|     def register(self, username, password, autosubscribe, activationkey):
 | |
|         '''
 | |
|             Register the current system to the provided RHN server
 | |
|             Raises:
 | |
|               * Exception - if error occurs while running command
 | |
|         '''
 | |
|         args = ['subscription-manager', 'register']
 | |
| 
 | |
|         # Generate command arguments
 | |
|         if activationkey:
 | |
|             args.append('--activationkey "%s"' % activationkey)
 | |
|         else:
 | |
|             if autosubscribe:
 | |
|                 args.append('--autosubscribe')
 | |
|             if username:
 | |
|                 args.extend(['--username', username])
 | |
|             if password:
 | |
|                 args.extend(['--password', password])
 | |
| 
 | |
|         # Do the needful...
 | |
|         rc, stderr, stdout = self.module.run_command(args, check_rc=True)
 | |
| 
 | |
|     def unsubscribe(self):
 | |
|         '''
 | |
|             Unsubscribe a system from all subscribed channels
 | |
|             Raises:
 | |
|               * Exception - if error occurs while running command
 | |
|         '''
 | |
|         args = ['subscription-manager', 'unsubscribe', '--all']
 | |
|         rc, stderr, stdout = self.module.run_command(args, check_rc=True)
 | |
| 
 | |
|     def unregister(self):
 | |
|         '''
 | |
|             Unregister a currently registered system
 | |
|             Raises:
 | |
|               * Exception - if error occurs while running command
 | |
|         '''
 | |
|         args = ['subscription-manager', 'unregister']
 | |
|         rc, stderr, stdout = self.module.run_command(args, check_rc=True)
 | |
|         self.update_plugin_conf('rhnplugin', False)
 | |
|         self.update_plugin_conf('subscription-manager', False)
 | |
| 
 | |
|     def subscribe(self, regexp):
 | |
|         '''
 | |
|             Subscribe current system to available pools matching the specified
 | |
|             regular expression
 | |
|             Raises:
 | |
|               * Exception - if error occurs while running command
 | |
|         '''
 | |
| 
 | |
|         # Available pools ready for subscription
 | |
|         available_pools = RhsmPools(self.module)
 | |
| 
 | |
|         for pool in available_pools.filter(regexp):
 | |
|             pool.subscribe()
 | |
| 
 | |
| 
 | |
| class RhsmPool(object):
 | |
|     '''
 | |
|         Convenience class for housing subscription information
 | |
|     '''
 | |
| 
 | |
|     def __init__(self, module, **kwargs):
 | |
|         self.module = module
 | |
|         for k, v in kwargs.items():
 | |
|             setattr(self, k, v)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return str(self.__getattribute__('_name'))
 | |
| 
 | |
|     def subscribe(self):
 | |
|         args = "subscription-manager subscribe --pool %s" % self.PoolId
 | |
|         rc, stdout, stderr = self.module.run_command(args, check_rc=True)
 | |
|         if rc == 0:
 | |
|             return True
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
| 
 | |
| class RhsmPools(object):
 | |
|     """
 | |
|         This class is used for manipulating pools subscriptions with RHSM
 | |
|     """
 | |
|     def __init__(self, module):
 | |
|         self.module = module
 | |
|         self.products = self._load_product_list()
 | |
| 
 | |
|     def __iter__(self):
 | |
|         return self.products.__iter__()
 | |
| 
 | |
|     def _load_product_list(self):
 | |
|         """
 | |
|             Loads list of all available pools for system in data structure
 | |
|         """
 | |
|         args = "subscription-manager list --available"
 | |
|         rc, stdout, stderr = self.module.run_command(args, check_rc=True)
 | |
| 
 | |
|         products = []
 | |
|         for line in stdout.split('\n'):
 | |
|             # Remove leading+trailing whitespace
 | |
|             line = line.strip()
 | |
|             # An empty line implies the end of an output group
 | |
|             if len(line) == 0:
 | |
|                 continue
 | |
|             # If a colon ':' is found, parse
 | |
|             elif ':' in line:
 | |
|                 (key, value) = line.split(':', 1)
 | |
|                 key = key.strip().replace(" ", "")  # To unify
 | |
|                 value = value.strip()
 | |
|                 if key in ['ProductName', 'SubscriptionName']:
 | |
|                     # Remember the name for later processing
 | |
|                     products.append(RhsmPool(self.module, _name=value, key=value))
 | |
|                 elif products:
 | |
|                     # Associate value with most recently recorded product
 | |
|                     products[-1].__setattr__(key, value)
 | |
|                 # FIXME - log some warning?
 | |
|                 # else:
 | |
|                     # warnings.warn("Unhandled subscription key/value: %s/%s" % (key,value))
 | |
|         return products
 | |
| 
 | |
|     def filter(self, regexp='^$'):
 | |
|         '''
 | |
|             Return a list of RhsmPools whose name matches the provided regular expression
 | |
|         '''
 | |
|         r = re.compile(regexp)
 | |
|         for product in self.products:
 | |
|             if r.search(product._name):
 | |
|                 yield product
 |