summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Watkins <daniel.watkins@canonical.com>2015-06-10 17:33:17 +0100
committerDaniel Watkins <daniel.watkins@canonical.com>2015-06-10 17:33:17 +0100
commit1489a6a0db44bd3f40deba3073d26600bcd23cfb (patch)
tree5b20c8e2060fc60c159fba8564f4c974ac78071a
parent162ce6a5635574e8dba0be3e06d313a18b46adc6 (diff)
parent3c01b8e48400697362f190984ab9c96dee27a369 (diff)
downloadvyos-cloud-init-1489a6a0db44bd3f40deba3073d26600bcd23cfb.tar.gz
vyos-cloud-init-1489a6a0db44bd3f40deba3073d26600bcd23cfb.zip
Add a cloud-init plugin for helping users register and subscribe their RHEL-based systems.
This patch adds a cloud-init plugin for helping users register and subscribe their RHEL based systems. As inputs, it can take: - user and password OR activation key and org | requires on of the two pair - auto-attach: True or False | optional - service-level: <string> | optional - add-pool [list, of, pool, ids] | optional - enable-repos [list, of, yum, repos, to, enable] | optional - disable-repos [list, of, yum, repos, to, disable] | optional You can also pass the following to influence your registration via rhsm.conf: - rhsm-baseurl | optional - server-hostname | optional
-rw-r--r--cloudinit/config/cc_rh_subscription.py404
-rw-r--r--doc/examples/cloud-config-rh_subscription.txt49
-rw-r--r--tests/unittests/test_rh_subscription.py208
3 files changed, 661 insertions, 0 deletions
diff --git a/cloudinit/config/cc_rh_subscription.py b/cloudinit/config/cc_rh_subscription.py
new file mode 100644
index 00000000..cabebca4
--- /dev/null
+++ b/cloudinit/config/cc_rh_subscription.py
@@ -0,0 +1,404 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# Author: Brent Baude <bbaude@redhat.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from cloudinit import util
+
+
+def handle(_name, cfg, _cloud, log, _args):
+ sm = SubscriptionManager(cfg)
+ sm.log = log
+ if not sm.is_registered:
+ try:
+ verify, verify_msg = sm._verify_keys()
+ if verify is not True:
+ raise SubscriptionError(verify_msg)
+ cont = sm.rhn_register()
+ if not cont:
+ raise SubscriptionError("Registration failed or did not "
+ "run completely")
+
+ # Splitting up the registration, auto-attach, and servicelevel
+ # commands because the error codes, messages from subman are not
+ # specific enough.
+
+ # Attempt to change the service level
+ if sm.auto_attach and sm.servicelevel is not None:
+ if not sm._set_service_level():
+ raise SubscriptionError("Setting of service-level "
+ "failed")
+ else:
+ sm.log.debug("Completed auto-attach with service level")
+ elif sm.auto_attach:
+ if not sm._set_auto_attach():
+ raise SubscriptionError("Setting auto-attach failed")
+ else:
+ sm.log.debug("Completed auto-attach")
+
+ if sm.pools is not None:
+ if not isinstance(sm.pools, list):
+ pool_fail = "Pools must in the format of a list"
+ raise SubscriptionError(pool_fail)
+
+ return_stat = sm.addPool(sm.pools)
+ if not return_stat:
+ raise SubscriptionError("Unable to attach pools {0}"
+ .format(sm.pools))
+ if (sm.enable_repo is not None) or (sm.disable_repo is not None):
+ return_stat = sm.update_repos(sm.enable_repo, sm.disable_repo)
+ if not return_stat:
+ raise SubscriptionError("Unable to add or remove repos")
+ sm.log_success("rh_subscription plugin completed successfully")
+ except SubscriptionError as e:
+ sm.log_warn(str(e))
+ sm.log_warn("rh_subscription plugin did not complete successfully")
+ else:
+ sm.log_success("System is already registered")
+
+
+class SubscriptionError(Exception):
+ pass
+
+
+class SubscriptionManager(object):
+ valid_rh_keys = ['org', 'activation-key', 'username', 'password',
+ 'disable-repo', 'enable-repo', 'add-pool',
+ 'rhsm-baseurl', 'server-hostname',
+ 'auto-attach', 'service-level']
+
+ def __init__(self, cfg):
+ self.cfg = cfg
+ self.rhel_cfg = self.cfg.get('rh_subscription', {})
+ self.rhsm_baseurl = self.rhel_cfg.get('rhsm-baseurl')
+ self.server_hostname = self.rhel_cfg.get('server-hostname')
+ self.pools = self.rhel_cfg.get('add-pool')
+ self.activation_key = self.rhel_cfg.get('activation-key')
+ self.org = self.rhel_cfg.get('org')
+ self.userid = self.rhel_cfg.get('username')
+ self.password = self.rhel_cfg.get('password')
+ self.auto_attach = self.rhel_cfg.get('auto-attach')
+ self.enable_repo = self.rhel_cfg.get('enable-repo')
+ self.disable_repo = self.rhel_cfg.get('disable-repo')
+ self.servicelevel = self.rhel_cfg.get('service-level')
+ self.subman = ['subscription-manager']
+ self.is_registered = self._is_registered()
+
+ def log_success(self, msg):
+ '''Simple wrapper for logging info messages. Useful for unittests'''
+ self.log.info(msg)
+
+ def log_warn(self, msg):
+ '''Simple wrapper for logging warning messages. Useful for unittests'''
+ self.log.warn(msg)
+
+ def _verify_keys(self):
+ '''
+ Checks that the keys in the rh_subscription dict from the user-data
+ are what we expect.
+ '''
+
+ for k in self.rhel_cfg:
+ if k not in self.valid_rh_keys:
+ bad_key = "{0} is not a valid key for rh_subscription. "\
+ "Valid keys are: "\
+ "{1}".format(k, ', '.join(self.valid_rh_keys))
+ return False, bad_key
+
+ # Check for bad auto-attach value
+ if (self.auto_attach is not None) and \
+ not (util.is_true(self.auto_attach) or
+ util.is_false(self.auto_attach)):
+ not_bool = "The key auto-attach must be a boolean value "\
+ "(True/False "
+ return False, not_bool
+
+ if (self.servicelevel is not None) and \
+ ((not self.auto_attach)
+ or (util.is_false(str(self.auto_attach)))):
+
+ no_auto = "The service-level key must be used in conjunction with "\
+ "the auto-attach key. Please re-run with auto-attach: "\
+ "True"
+ return False, no_auto
+ return True, None
+
+ def _is_registered(self):
+ '''
+ Checks if the system is already registered and returns
+ True if so, else False
+ '''
+ cmd = ['identity']
+
+ try:
+ self._sub_man_cli(cmd)
+ except util.ProcessExecutionError:
+ return False
+
+ return True
+
+ def _sub_man_cli(self, cmd, logstring_val=False):
+ '''
+ Uses the prefered cloud-init subprocess def of util.subp
+ and runs subscription-manager. Breaking this to a
+ separate function for later use in mocking and unittests
+ '''
+ cmd = self.subman + cmd
+ return util.subp(cmd, logstring=logstring_val)
+
+ def rhn_register(self):
+ '''
+ Registers the system by userid and password or activation key
+ and org. Returns True when successful False when not.
+ '''
+
+ if (self.activation_key is not None) and (self.org is not None):
+ # register by activation key
+ cmd = ['register', '--activationkey={0}'.
+ format(self.activation_key), '--org={0}'.format(self.org)]
+
+ # If the baseurl and/or server url are passed in, we register
+ # with them.
+
+ if self.rhsm_baseurl is not None:
+ cmd.append("--baseurl={0}".format(self.rhsm_baseurl))
+
+ if self.server_hostname is not None:
+ cmd.append("--serverurl={0}".format(self.server_hostname))
+
+ try:
+ return_out, return_err = self._sub_man_cli(cmd,
+ logstring_val=True)
+ except util.ProcessExecutionError as e:
+ if e.stdout == "":
+ self.log_warn("Registration failed due "
+ "to: {0}".format(e.stderr))
+ return False
+
+ elif (self.userid is not None) and (self.password is not None):
+ # register by username and password
+ cmd = ['register', '--username={0}'.format(self.userid),
+ '--password={0}'.format(self.password)]
+
+ # If the baseurl and/or server url are passed in, we register
+ # with them.
+
+ if self.rhsm_baseurl is not None:
+ cmd.append("--baseurl={0}".format(self.rhsm_baseurl))
+
+ if self.server_hostname is not None:
+ cmd.append("--serverurl={0}".format(self.server_hostname))
+
+ # Attempting to register the system only
+ try:
+ return_out, return_err = self._sub_man_cli(cmd,
+ logstring_val=True)
+ except util.ProcessExecutionError as e:
+ if e.stdout == "":
+ self.log_warn("Registration failed due "
+ "to: {0}".format(e.stderr))
+ return False
+
+ else:
+ self.log_warn("Unable to register system due to incomplete "
+ "information.")
+ self.log_warn("Use either activationkey and org *or* userid "
+ "and password")
+ return False
+
+ reg_id = return_out.split("ID: ")[1].rstrip()
+ self.log.debug("Registered successfully with ID {0}".format(reg_id))
+ return True
+
+ def _set_service_level(self):
+ cmd = ['attach', '--auto', '--servicelevel={0}'
+ .format(self.servicelevel)]
+
+ try:
+ return_out, return_err = self._sub_man_cli(cmd)
+ except util.ProcessExecutionError as e:
+ if e.stdout.rstrip() != '':
+ for line in e.stdout.split("\n"):
+ if line is not '':
+ self.log_warn(line)
+ else:
+ self.log_warn("Setting the service level failed with: "
+ "{0}".format(e.stderr.strip()))
+ return False
+ for line in return_out.split("\n"):
+ if line is not "":
+ self.log.debug(line)
+ return True
+
+ def _set_auto_attach(self):
+ cmd = ['attach', '--auto']
+ try:
+ return_out, return_err = self._sub_man_cli(cmd)
+ except util.ProcessExecutionError:
+ self.log_warn("Auto-attach failed with: "
+ "{0}]".format(return_err.strip()))
+ return False
+ for line in return_out.split("\n"):
+ if line is not "":
+ self.log.debug(line)
+ return True
+
+ def _getPools(self):
+ '''
+ Gets the list pools for the active subscription and returns them
+ in list form.
+ '''
+ available = []
+ consumed = []
+
+ # Get all available pools
+ cmd = ['list', '--available', '--pool-only']
+ results, errors = self._sub_man_cli(cmd)
+ available = (results.rstrip()).split("\n")
+
+ # Get all consumed pools
+ cmd = ['list', '--consumed', '--pool-only']
+ results, errors = self._sub_man_cli(cmd)
+ consumed = (results.rstrip()).split("\n")
+
+ return available, consumed
+
+ def _getRepos(self):
+ '''
+ Obtains the current list of active yum repositories and returns
+ them in list form.
+ '''
+
+ cmd = ['repos', '--list-enabled']
+ return_out, return_err = self._sub_man_cli(cmd)
+ active_repos = []
+ for repo in return_out.split("\n"):
+ if "Repo ID:" in repo:
+ active_repos.append((repo.split(':')[1]).strip())
+
+ cmd = ['repos', '--list-disabled']
+ return_out, return_err = self._sub_man_cli(cmd)
+
+ inactive_repos = []
+ for repo in return_out.split("\n"):
+ if "Repo ID:" in repo:
+ inactive_repos.append((repo.split(':')[1]).strip())
+ return active_repos, inactive_repos
+
+ def addPool(self, pools):
+ '''
+ Takes a list of subscription pools and "attaches" them to the
+ current subscription
+ '''
+
+ # An empty list was passed
+ if len(pools) == 0:
+ self.log.debug("No pools to attach")
+ return True
+
+ pool_available, pool_consumed = self._getPools()
+ pool_list = []
+ cmd = ['attach']
+ for pool in pools:
+ if (pool not in pool_consumed) and (pool in pool_available):
+ pool_list.append('--pool={0}'.format(pool))
+ else:
+ self.log_warn("Pool {0} is not available".format(pool))
+ if len(pool_list) > 0:
+ cmd.extend(pool_list)
+ try:
+ self._sub_man_cli(cmd)
+ self.log.debug("Attached the following pools to your "
+ "system: %s" % (", ".join(pool_list))
+ .replace('--pool=', ''))
+ return True
+ except util.ProcessExecutionError as e:
+ self.log_warn("Unable to attach pool {0} "
+ "due to {1}".format(pool, e))
+ return False
+
+ def update_repos(self, erepos, drepos):
+ '''
+ Takes a list of yum repo ids that need to be disabled or enabled; then
+ it verifies if they are already enabled or disabled and finally
+ executes the action to disable or enable
+ '''
+
+ if (erepos is not None) and (not isinstance(erepos, list)):
+ self.log_warn("Repo IDs must in the format of a list.")
+ return False
+
+ if (drepos is not None) and (not isinstance(drepos, list)):
+ self.log_warn("Repo IDs must in the format of a list.")
+ return False
+
+ # Bail if both lists are not populated
+ if (len(erepos) == 0) and (len(drepos) == 0):
+ self.log.debug("No repo IDs to enable or disable")
+ return True
+
+ active_repos, inactive_repos = self._getRepos()
+ # Creating a list of repoids to be enabled
+ enable_list = []
+ enable_list_fail = []
+ for repoid in erepos:
+ if (repoid in inactive_repos):
+ enable_list.append("--enable={0}".format(repoid))
+ else:
+ enable_list_fail.append(repoid)
+
+ # Creating a list of repoids to be disabled
+ disable_list = []
+ disable_list_fail = []
+ for repoid in drepos:
+ if repoid in active_repos:
+ disable_list.append("--disable={0}".format(repoid))
+ else:
+ disable_list_fail.append(repoid)
+
+ # Logging any repos that are already enabled or disabled
+ if len(enable_list_fail) > 0:
+ for fail in enable_list_fail:
+ # Check if the repo exists or not
+ if fail in active_repos:
+ self.log.debug("Repo {0} is already enabled".format(fail))
+ else:
+ self.log_warn("Repo {0} does not appear to "
+ "exist".format(fail))
+ if len(disable_list_fail) > 0:
+ for fail in disable_list_fail:
+ self.log.debug("Repo {0} not disabled "
+ "because it is not enabled".format(fail))
+
+ cmd = ['repos']
+ if enable_list > 0:
+ cmd.extend(enable_list)
+ if disable_list > 0:
+ cmd.extend(disable_list)
+
+ try:
+ self._sub_man_cli(cmd)
+ except util.ProcessExecutionError as e:
+ self.log_warn("Unable to alter repos due to {0}".format(e))
+ return False
+
+ if enable_list > 0:
+ self.log.debug("Enabled the following repos: %s" %
+ (", ".join(enable_list)).replace('--enable=', ''))
+ if disable_list > 0:
+ self.log.debug("Disabled the following repos: %s" %
+ (", ".join(disable_list)).replace('--disable=', ''))
+ return True
diff --git a/doc/examples/cloud-config-rh_subscription.txt b/doc/examples/cloud-config-rh_subscription.txt
new file mode 100644
index 00000000..be121338
--- /dev/null
+++ b/doc/examples/cloud-config-rh_subscription.txt
@@ -0,0 +1,49 @@
+#cloud-config
+
+# register your Red Hat Enterprise Linux based operating system
+#
+# this cloud-init plugin is capable of registering by username
+# and password *or* activation and org. Following a successfully
+# registration you can:
+# - auto-attach subscriptions
+# - set the service level
+# - add subscriptions based on its pool ID
+# - enable yum repositories based on its repo id
+# - disable yum repositories based on its repo id
+# - alter the rhsm_baseurl and server-hostname in the
+# /etc/rhsm/rhs.conf file
+
+rh_subscription:
+ username: joe@foo.bar
+
+ ## Quote your password if it has symbols to be safe
+ password: '1234abcd'
+
+ ## If you prefer, you can use the activation key and
+ ## org instead of username and password. Be sure to
+ ## comment out username and password
+
+ #activation-key: foobar
+ #org: 12345
+
+ ## Uncomment to auto-attach subscriptions to your system
+ #auto-attach: True
+
+ ## Uncomment to set the service level for your
+ ## subscriptions
+ #service-level: self-support
+
+ ## Uncomment to add pools (needs to be a list of IDs)
+ #add-pool: []
+
+ ## Uncomment to add or remove yum repos
+ ## (needs to be a list of repo IDs)
+ #enable-repo: []
+ #disable-repo: []
+
+ ## Uncomment to alter the baseurl in /etc/rhsm/rhsm.conf
+ #rhsm-baseurl: http://url
+
+ ## Uncomment to alter the server hostname in
+ ## /etc/rhsm/rhsm.conf
+ #server-hostname: foo.bar.com
diff --git a/tests/unittests/test_rh_subscription.py b/tests/unittests/test_rh_subscription.py
new file mode 100644
index 00000000..38d5763a
--- /dev/null
+++ b/tests/unittests/test_rh_subscription.py
@@ -0,0 +1,208 @@
+from cloudinit import util
+from cloudinit.config import cc_rh_subscription
+import logging
+import mock
+import unittest
+
+
+class GoodTests(unittest.TestCase):
+ def setUp(self):
+ super(GoodTests, self).setUp()
+ self.name = "cc_rh_subscription"
+ self.cloud_init = None
+ self.log = logging.getLogger("good_tests")
+ self.args = []
+ self.handle = cc_rh_subscription.handle
+ self.SM = cc_rh_subscription.SubscriptionManager
+
+ self.config = {'rh_subscription':
+ {'username': 'scooby@do.com',
+ 'password': 'scooby-snacks'
+ }}
+ self.config_full = {'rh_subscription':
+ {'username': 'scooby@do.com',
+ 'password': 'scooby-snacks',
+ 'auto-attach': True,
+ 'service-level': 'self-support',
+ 'add-pool': ['pool1', 'pool2', 'pool3'],
+ 'enable-repo': ['repo1', 'repo2', 'repo3'],
+ 'disable-repo': ['repo4', 'repo5']
+ }}
+
+ def test_already_registered(self):
+ '''
+ Emulates a system that is already registered. Ensure it gets
+ a non-ProcessExecution error from is_registered()
+ '''
+ with mock.patch.object(cc_rh_subscription.SubscriptionManager,
+ '_sub_man_cli') as mockobj:
+ self.SM.log_success = mock.MagicMock()
+ self.handle(self.name, self.config, self.cloud_init,
+ self.log, self.args)
+ self.assertEqual(self.SM.log_success.call_count, 1)
+ self.assertEqual(mockobj.call_count, 1)
+
+ def test_simple_registration(self):
+ '''
+ Simple registration with username and password
+ '''
+ self.SM.log_success = mock.MagicMock()
+ reg = "The system has been registered with ID:" \
+ " 12345678-abde-abcde-1234-1234567890abc"
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (reg, 'bar')])
+ self.handle(self.name, self.config, self.cloud_init,
+ self.log, self.args)
+ self.assertIn(mock.call(['identity']),
+ self.SM._sub_man_cli.call_args_list)
+ self.assertIn(mock.call(['register', '--username=scooby@do.com',
+ '--password=scooby-snacks'],
+ logstring_val=True),
+ self.SM._sub_man_cli.call_args_list)
+
+ self.assertEqual(self.SM.log_success.call_count, 1)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 2)
+
+ def test_full_registration(self):
+ '''
+ Registration with auto-attach, service-level, adding pools,
+ and enabling and disabling yum repos
+ '''
+ call_lists = []
+ call_lists.append(['attach', '--pool=pool1', '--pool=pool3'])
+ call_lists.append(['repos', '--enable=repo2', '--enable=repo3',
+ '--disable=repo5'])
+ call_lists.append(['attach', '--auto', '--servicelevel=self-support'])
+ self.SM.log_success = mock.MagicMock()
+ reg = "The system has been registered with ID:" \
+ " 12345678-abde-abcde-1234-1234567890abc"
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (reg, 'bar'),
+ ('Service level set to: self-support', ''),
+ ('pool1\npool3\n', ''), ('pool2\n', ''), ('', ''),
+ ('Repo ID: repo1\nRepo ID: repo5\n', ''),
+ ('Repo ID: repo2\nRepo ID: repo3\nRepo ID: '
+ 'repo4', ''),
+ ('', '')])
+ self.handle(self.name, self.config_full, self.cloud_init,
+ self.log, self.args)
+ for call in call_lists:
+ self.assertIn(mock.call(call), self.SM._sub_man_cli.call_args_list)
+ self.assertEqual(self.SM.log_success.call_count, 1)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 9)
+
+
+class TestBadInput(unittest.TestCase):
+ name = "cc_rh_subscription"
+ cloud_init = None
+ log = logging.getLogger("bad_tests")
+ args = []
+ SM = cc_rh_subscription.SubscriptionManager
+ reg = "The system has been registered with ID:" \
+ " 12345678-abde-abcde-1234-1234567890abc"
+
+ config_no_password = {'rh_subscription':
+ {'username': 'scooby@do.com'
+ }}
+
+ config_no_key = {'rh_subscription':
+ {'activation-key': '1234abcde',
+ }}
+
+ config_service = {'rh_subscription':
+ {'username': 'scooby@do.com',
+ 'password': 'scooby-snacks',
+ 'service-level': 'self-support'
+ }}
+
+ config_badpool = {'rh_subscription':
+ {'username': 'scooby@do.com',
+ 'password': 'scooby-snacks',
+ 'add-pool': 'not_a_list'
+ }}
+ config_badrepo = {'rh_subscription':
+ {'username': 'scooby@do.com',
+ 'password': 'scooby-snacks',
+ 'enable-repo': 'not_a_list'
+ }}
+ config_badkey = {'rh_subscription':
+ {'activation_key': 'abcdef1234',
+ 'org': '123',
+ }}
+
+ def setUp(self):
+ super(TestBadInput, self).setUp()
+ self.handle = cc_rh_subscription.handle
+
+ def test_no_password(self):
+ '''
+ Attempt to register without the password key/value
+ '''
+ self.input_is_missing_data(self.config_no_password)
+
+ def test_no_org(self):
+ '''
+ Attempt to register without the org key/value
+ '''
+ self.input_is_missing_data(self.config_no_key)
+
+ def test_service_level_without_auto(self):
+ '''
+ Attempt to register using service-level without the auto-attach key
+ '''
+ self.SM.log_warn = mock.MagicMock()
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (self.reg, 'bar')])
+ self.handle(self.name, self.config_service, self.cloud_init,
+ self.log, self.args)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 1)
+ self.assertEqual(self.SM.log_warn.call_count, 2)
+
+ def test_pool_not_a_list(self):
+ '''
+ Register with pools that are not in the format of a list
+ '''
+ self.SM.log_warn = mock.MagicMock()
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (self.reg, 'bar')])
+ self.handle(self.name, self.config_badpool, self.cloud_init,
+ self.log, self.args)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 2)
+ self.assertEqual(self.SM.log_warn.call_count, 2)
+
+ def test_repo_not_a_list(self):
+ '''
+ Register with repos that are not in the format of a list
+ '''
+ self.SM.log_warn = mock.MagicMock()
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (self.reg, 'bar')])
+ self.handle(self.name, self.config_badrepo, self.cloud_init,
+ self.log, self.args)
+ self.assertEqual(self.SM.log_warn.call_count, 3)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 2)
+
+ def test_bad_key_value(self):
+ '''
+ Attempt to register with a key that we don't know
+ '''
+ self.SM.log_warn = mock.MagicMock()
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError, (self.reg, 'bar')])
+ self.handle(self.name, self.config_badkey, self.cloud_init,
+ self.log, self.args)
+ self.assertEqual(self.SM.log_warn.call_count, 2)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 1)
+
+ def input_is_missing_data(self, config):
+ '''
+ Helper def for tests that having missing information
+ '''
+ self.SM.log_warn = mock.MagicMock()
+ self.SM._sub_man_cli = mock.MagicMock(
+ side_effect=[util.ProcessExecutionError])
+ self.handle(self.name, config, self.cloud_init,
+ self.log, self.args)
+ self.SM._sub_man_cli.assert_called_with(['identity'])
+ self.assertEqual(self.SM.log_warn.call_count, 4)
+ self.assertEqual(self.SM._sub_man_cli.call_count, 1)