def test_unchanged_value_does_nothing( self, m_subp, update_ssh_config, mock_uses_systemd ): """If 'unchanged', then no updates to config and no restart.""" update_ssh_config.assert_not_called() cloud = get_cloud("ubuntu") setpass.handle_ssh_pwauth("unchanged", cloud.distro) assert [ mock.call(["systemctl", "status", "ssh"], capture=True) ] == m_subp.call_args_list
def test_append_random(self): cfg = { 'random_seed': { 'file': self._seed_file, 'data': 'tiny-tim-was-here', } } cc_seed_random.handle('test', cfg, get_cloud('ubuntu'), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("tiny-tim-was-here", contents)
def test_handle_ssh_keys_in_cfg(self, m_write_file, m_nug, m_setup_keys): """Test handle with ssh keys and certificate.""" # Populate a config dictionary to pass to handle() as well # as the expected file-writing calls. cfg = {"ssh_keys": {}} expected_calls = [] for key_type in cc_ssh.GENERATE_KEY_NAMES: private_name = "{}_private".format(key_type) public_name = "{}_public".format(key_type) cert_name = "{}_certificate".format(key_type) # Actual key contents don't have to be realistic private_value = "{}_PRIVATE_KEY".format(key_type) public_value = "{}_PUBLIC_KEY".format(key_type) cert_value = "{}_CERT_KEY".format(key_type) cfg["ssh_keys"][private_name] = private_value cfg["ssh_keys"][public_name] = public_value cfg["ssh_keys"][cert_name] = cert_value expected_calls.extend([ mock.call( "/etc/ssh/ssh_host_{}_key".format(key_type), private_value, 384, ), mock.call( "/etc/ssh/ssh_host_{}_key.pub".format(key_type), public_value, 384, ), mock.call( "/etc/ssh/ssh_host_{}_key-cert.pub".format(key_type), cert_value, 384, ), mock.call( "/etc/ssh/sshd_config", "HostCertificate /etc/ssh/ssh_host_{}_key-cert.pub" "\n".format(key_type), preserve_mode=True, ), ]) # Run the handler. m_nug.return_value = ([], {}) with mock.patch(MODPATH + "ssh_util.parse_ssh_config", return_value=[]): cc_ssh.handle("name", cfg, get_cloud(distro="ubuntu"), LOG, None) # Check that all expected output has been done. for call_ in expected_calls: assert call_ in m_write_file.call_args_list
def test_append_random_metadata(self): cfg = { 'random_seed': { 'file': self._seed_file, 'data': 'tiny-tim-was-here', } } c = get_cloud('ubuntu', metadata={'random_seed': '-so-was-josh'}) cc_seed_random.handle('test', cfg, c, LOG, []) contents = util.load_file(self._seed_file) self.assertEqual('tiny-tim-was-here-so-was-josh', contents)
def test_handler_invalid_command_set(self): """Commands which can't be converted to shell will raise errors.""" invalid_config = {"runcmd": 1} cc = get_cloud(paths=self.paths) with self.assertRaises(TypeError) as cm: handle("cc_runcmd", invalid_config, cc, LOG, []) self.assertIn( "Failed to shellify 1 into file" " /var/lib/cloud/instances/iid-datasource-none/scripts/runcmd", str(cm.exception), )
def test_handler_invalid_command_set(self): """Commands which can't be converted to shell will raise errors.""" invalid_config = {"bootcmd": 1} cc = get_cloud() with self.assertRaises(TypeError) as context_manager: handle("cc_bootcmd", invalid_config, cc, LOG, []) self.assertIn("Failed to shellify bootcmd", self.logs.getvalue()) self.assertEqual( "Input to shellify was type 'int'. Expected list or tuple.", str(context_manager.exception), )
def test_unavailable_seed_command_and_required_raises_error(self): c = get_cloud("ubuntu") self.whichdata = {} cfg = { "random_seed": { "command": ["THIS_NO_COMMAND"], "command_required": True, } } self.assertRaises(ValueError, cc_seed_random.handle, "test", cfg, c, LOG, [])
def test_locale_rhel_defaults_en_us_utf8(self): """Test cc_locale gets en_US.UTF-8 from distro get_locale fallback""" cfg = {} cc = get_cloud('rhel') update_sysconfig = 'cloudinit.distros.rhel_util.update_sysconfig_file' with mock.patch.object(cc.distro, 'uses_systemd') as m_use_sd: m_use_sd.return_value = True with mock.patch(update_sysconfig) as m_update_syscfg: cc_locale.handle('cc_locale', cfg, cc, LOG, []) m_update_syscfg.assert_called_with('/etc/locale.conf', {'LANG': 'en_US.UTF-8'})
def test_locale_rhel_defaults_en_us_utf8(self): """Test cc_locale gets en_US.UTF-8 from distro get_locale fallback""" cfg = {} cc = get_cloud("rhel") update_sysconfig = "cloudinit.distros.rhel_util.update_sysconfig_file" with mock.patch.object(cc.distro, "uses_systemd") as m_use_sd: m_use_sd.return_value = True with mock.patch(update_sysconfig) as m_update_syscfg: cc_locale.handle("cc_locale", cfg, cc, LOG, []) m_update_syscfg.assert_called_with("/etc/locale.conf", {"LANG": "en_US.UTF-8"})
def test_lxd_install(self, mock_subp, m_maybe_clean): cc = get_cloud() cc.distro = mock.MagicMock() mock_subp.which.return_value = None cc_lxd.handle('cc_lxd', self.lxd_cfg, cc, self.logger, []) self.assertNotIn('WARN', self.logs.getvalue()) self.assertTrue(cc.distro.install_packages.called) cc_lxd.handle('cc_lxd', self.lxd_cfg, cc, self.logger, []) self.assertFalse(m_maybe_clean.called) install_pkg = cc.distro.install_packages.call_args_list[0][0][0] self.assertEqual(sorted(install_pkg), ['lxd', 'zfsutils-linux'])
def test_append_random_unknown_encoding(self): data = self._compress(b"tiny-toe") cfg = { 'random_seed': { 'file': self._seed_file, 'data': data, 'encoding': 'special_encoding', } } self.assertRaises(IOError, cc_seed_random.handle, 'test', cfg, get_cloud('ubuntu'), LOG, [])
def test_file_in_environment_for_command(self): c = get_cloud('ubuntu') self.whichdata = {'foo': 'foo'} cfg = {'random_seed': {'command_required': True, 'command': ['foo'], 'file': self._seed_file}} cc_seed_random.handle('test', cfg, c, LOG, []) # this just instists that the first time subp was called, # RANDOM_SEED_FILE was in the environment set up correctly subp_env = [f['env'] for f in self.subp_called] self.assertEqual(subp_env[0].get('RANDOM_SEED_FILE'), self._seed_file)
def test_append_random_metadata(self): cfg = { "random_seed": { "file": self._seed_file, "data": "tiny-tim-was-here", } } c = get_cloud("ubuntu", metadata={"random_seed": "-so-was-josh"}) cc_seed_random.handle("test", cfg, c, LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("tiny-tim-was-here-so-was-josh", contents)
def test_handler_write_valid_runcmd_schema_to_file(self): """Valid runcmd schema is written to a runcmd shell script.""" valid_config = {'runcmd': [['ls', '/']]} cc = get_cloud(paths=self.paths) handle('cc_runcmd', valid_config, cc, LOG, []) runcmd_file = os.path.join( self.new_root, 'var/lib/cloud/instances/iid-datasource-none/scripts/runcmd') self.assertEqual("#!/bin/sh\n'ls' '/'\n", util.load_file(runcmd_file)) file_stat = os.stat(runcmd_file) self.assertEqual(0o700, stat.S_IMODE(file_stat.st_mode))
def test_append_random_b64(self): data = util.b64e("kit-kat") cfg = { "random_seed": { "file": self._seed_file, "data": data, "encoding": "b64", } } cc_seed_random.handle("test", cfg, get_cloud("ubuntu"), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("kit-kat", contents)
def test_empty_trusted_list(self): """Test that no certificate are written if 'trusted' list is empty.""" config = {"ca-certs": {"trusted": []}} for distro_name in cc_ca_certs.distros: self._mock_init() cloud = get_cloud(distro_name) cc_ca_certs.handle(self.name, config, cloud, self.log, self.args) self.assertEqual(self.mock_add.call_count, 0) self.assertEqual(self.mock_update.call_count, 1) self.assertEqual(self.mock_remove.call_count, 0)
def test_no_remove_defaults_if_false(self): """Test remove_defaults is not called when config value is False.""" config = {"ca-certs": {"remove-defaults": False}} for distro_name in cc_ca_certs.distros: self._mock_init() cloud = get_cloud(distro_name) cc_ca_certs.handle(self.name, config, cloud, self.log, self.args) self.assertEqual(self.mock_add.call_count, 0) self.assertEqual(self.mock_update.call_count, 1) self.assertEqual(self.mock_remove.call_count, 0)
def test_remove_default_ca_certs(self): """Test remove_defaults works as expected.""" config = {"ca-certs": {"remove-defaults": True}} for distro_name in cc_ca_certs.distros: self._mock_init() cloud = get_cloud(distro_name) cc_ca_certs.handle(self.name, config, cloud, self.log, self.args) self.assertEqual(self.mock_add.call_count, 0) self.assertEqual(self.mock_update.call_count, 1) self.assertEqual(self.mock_remove.call_count, 1)
def test_append_random_gz(self): data = self._compress(b"big-toe") cfg = { 'random_seed': { 'file': self._seed_file, 'data': data, 'encoding': 'gz', } } cc_seed_random.handle('test', cfg, get_cloud('ubuntu'), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("big-toe", contents)
def test_append_random_b64(self): data = util.b64e('kit-kat') cfg = { 'random_seed': { 'file': self._seed_file, 'data': data, 'encoding': 'b64', } } cc_seed_random.handle('test', cfg, get_cloud('ubuntu'), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("kit-kat", contents)
def test_handler_restarts_landscape_client(self, m_subp): """handler restarts lansdscape-client after install.""" mycloud = get_cloud('ubuntu') cfg = {'landscape': {'client': {}}} wrap_and_call('cloudinit.config.cc_landscape', {'LSC_CLIENT_CFG_FILE': { 'new': self.conf }}, cc_landscape.handle, 'notimportant', cfg, mycloud, LOG, None) self.assertEqual( [mock.call(['service', 'landscape-client', 'restart'])], m_subp.subp.call_args_list)
def test_append_random_gzip(self): data = self._compress(b"tiny-toe") cfg = { "random_seed": { "file": self._seed_file, "data": data, "encoding": "gzip", } } cc_seed_random.handle("test", cfg, get_cloud("ubuntu"), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("tiny-toe", contents)
def test_single_trusted(self): """Test that a single cert gets passed to add_ca_certs.""" config = {"ca-certs": {"trusted": ["CERT1"]}} for distro_name in cc_ca_certs.distros: self._mock_init() cloud = get_cloud(distro_name) conf = cc_ca_certs._distro_ca_certs_configs(distro_name) cc_ca_certs.handle(self.name, config, cloud, self.log, self.args) self.mock_add.assert_called_once_with(conf, ['CERT1']) self.assertEqual(self.mock_update.call_count, 1) self.assertEqual(self.mock_remove.call_count, 0)
def test_locale_update_config_if_different_than_default(self): """Test cc_locale writes updates conf if different than default""" locale_conf = os.path.join(self.new_root, "etc/default/locale") util.write_file(locale_conf, 'LANG="en_US.UTF-8"\n') cfg = {'locale': 'C.UTF-8'} cc = get_cloud('ubuntu') with mock.patch('cloudinit.distros.debian.subp.subp') as m_subp: with mock.patch('cloudinit.distros.debian.LOCALE_CONF_FN', locale_conf): cc_locale.handle('cc_locale', cfg, cc, LOG, []) m_subp.assert_called_with(['update-locale', '--locale-file=%s' % locale_conf, 'LANG=C.UTF-8'], capture=False)
def test_mcollective_install(self, mock_util, mock_subp): cc = get_cloud() cc.distro = t_help.mock.MagicMock() mock_util.load_file.return_value = b"" mycfg = {'mcollective': {'conf': {'loglevel': 'debug'}}} cc_mcollective.handle('cc_mcollective', mycfg, cc, LOG, []) self.assertTrue(cc.distro.install_packages.called) install_pkg = cc.distro.install_packages.call_args_list[0][0][0] self.assertEqual(install_pkg, ('mcollective',)) self.assertTrue(mock_subp.subp.called) self.assertEqual(mock_subp.subp.call_args_list[0][0][0], ['service', 'mcollective', 'restart'])
def test_handler_schema_validation_warns_non_array_type(self): """Schema validation warns of non-array type for bootcmd key. Schema validation is not strict, so bootcmd attempts to shellify the invalid content. """ invalid_config = {'bootcmd': 1} cc = get_cloud() with self.assertRaises(TypeError): handle('cc_bootcmd', invalid_config, cc, LOG, []) self.assertIn('Invalid config:\nbootcmd: 1 is not of type \'array\'', self.logs.getvalue()) self.assertIn('Failed to shellify', self.logs.getvalue())
def test_apt_v3_source_list_ubuntu_snappy(self): """test_apt_v3_source_list_ubuntu_snappy - without custom sources or parms""" cfg = {'apt': {}} mycloud = get_cloud() with mock.patch.object(util, 'write_file') as mock_writefile: with mock.patch.object(util, 'system_is_snappy', return_value=True) as mock_issnappy: cc_apt_configure.handle("test", cfg, mycloud, LOG, None) self.assertEqual(0, mock_writefile.call_count) self.assertEqual(1, mock_issnappy.call_count)
def test_correct_order_for_remove_then_add(self): """Test remove_defaults is not called when config value is False.""" config = {"ca-certs": {"remove-defaults": True, "trusted": ["CERT1"]}} for distro_name in cc_ca_certs.distros: self._mock_init() cloud = get_cloud(distro_name) conf = cc_ca_certs._distro_ca_certs_configs(distro_name) cc_ca_certs.handle(self.name, config, cloud, self.log, self.args) self.mock_add.assert_called_once_with(conf, ['CERT1']) self.assertEqual(self.mock_update.call_count, 1) self.assertEqual(self.mock_remove.call_count, 1)
def test_valid_value_changes_updates_ssh(self, m_subp, mock_uses_systemd): """If value is a valid changed value, then update will be called.""" cloud = get_cloud("ubuntu") upname = MODPATH + "update_ssh_config" optname = "PasswordAuthentication" for n, value in enumerate(util.FALSE_STRINGS + util.TRUE_STRINGS, 1): optval = "yes" if value in util.TRUE_STRINGS else "no" with mock.patch(upname, return_value=False) as m_update: setpass.handle_ssh_pwauth(value, cloud.distro) assert ( mock.call({optname: optval}) == m_update.call_args_list[-1] ) assert m_subp.call_count == n
def apt_source_list(self, distro, mirror, mirrorcheck=None): """apt_source_list Test rendering of a source.list from template for a given distro """ if mirrorcheck is None: mirrorcheck = mirror if isinstance(mirror, list): cfg = {"apt_mirror_search": mirror} else: cfg = {"apt_mirror": mirror} mycloud = get_cloud(distro) with mock.patch.object(util, "write_file") as mockwf: with mock.patch.object( util, "load_file", return_value="faketmpl" ) as mocklf: with mock.patch.object( os.path, "isfile", return_value=True ) as mockisfile: with mock.patch.object( templater, "render_string", return_value="fake" ) as mockrnd: with mock.patch.object(util, "rename"): cc_apt_configure.handle( "test", cfg, mycloud, LOG, None ) mockisfile.assert_any_call( "/etc/cloud/templates/sources.list.%s.tmpl" % distro ) mocklf.assert_any_call( "/etc/cloud/templates/sources.list.%s.tmpl" % distro ) mockrnd.assert_called_once_with( "faketmpl", { "RELEASE": "fakerelease", "PRIMARY": mirrorcheck, "MIRROR": mirrorcheck, "SECURITY": mirrorcheck, "codename": "fakerelease", "primary": mirrorcheck, "mirror": mirrorcheck, "security": mirrorcheck, }, ) mockwf.assert_called_once_with( "/etc/apt/sources.list", "fake", mode=0o644 )