From 2fd22530737468a00bfb58eed9b6e231aa6d6652 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Thu, 30 Jul 2015 15:18:53 -0700 Subject: Ensure that when a resolve conf object is written we pass the str() version of it Instead of passing the raw object and expecting the write_file to work automatically make sure we explicitly pass the string version of it so that the write_file routine can correctly encode/decode it as needed. LP: #1479988 --- tests/unittests/test_distros/test_resolv.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests') diff --git a/tests/unittests/test_distros/test_resolv.py b/tests/unittests/test_distros/test_resolv.py index faaf5b7f..9edeb6e7 100644 --- a/tests/unittests/test_distros/test_resolv.py +++ b/tests/unittests/test_distros/test_resolv.py @@ -1,6 +1,8 @@ from cloudinit.distros.parsers import resolv_conf +from cloudinit.distros import rhel_util import re +import tempfile from ..helpers import TestCase @@ -19,6 +21,10 @@ class TestResolvHelper(TestCase): rp_r = str(rp).strip() self.assertEquals(BASE_RESOLVE, rp_r) + def test_write_works(self): + with tempfile.NamedTemporaryFile() as fh: + rhel_util.update_resolve_conf_file(fh.name, [], []) + def test_local_domain(self): rp = resolv_conf.ResolvConf(BASE_RESOLVE) self.assertEquals(None, rp.local_domain) -- cgit v1.2.3 From 578fed15061293ce421eec1c9c1e2e056631a734 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 6 Apr 2016 13:57:00 -0400 Subject: fix tests and hopefully actually work --- cloudinit/config/cc_rh_subscription.py | 7 +++---- tests/unittests/test_rh_subscription.py | 9 +++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/cloudinit/config/cc_rh_subscription.py b/cloudinit/config/cc_rh_subscription.py index 2871984a..3a113aea 100644 --- a/cloudinit/config/cc_rh_subscription.py +++ b/cloudinit/config/cc_rh_subscription.py @@ -23,11 +23,10 @@ def handle(name, cfg, _cloud, log, _args): sm = SubscriptionManager(cfg) sm.log = log if not sm.is_configured(): - log.debug("Activation key not provided, config module %s disabled.", - _name) + log.debug("%s: module not configured.", name) return None - if not sm.is_registered: + if not sm.is_registered(): try: verify, verify_msg = sm._verify_keys() if verify is not True: @@ -406,4 +405,4 @@ class SubscriptionManager(object): return True def is_configured(self): - return (self.userid and self.password) or self.activation_key + return bool((self.userid and self.password) or self.activation_key) diff --git a/tests/unittests/test_rh_subscription.py b/tests/unittests/test_rh_subscription.py index 38d5763a..8c586ad7 100644 --- a/tests/unittests/test_rh_subscription.py +++ b/tests/unittests/test_rh_subscription.py @@ -126,7 +126,8 @@ class TestBadInput(unittest.TestCase): 'enable-repo': 'not_a_list' }} config_badkey = {'rh_subscription': - {'activation_key': 'abcdef1234', + {'activation-key': 'abcdef1234', + 'fookey': 'bar', 'org': '123', }} @@ -138,7 +139,11 @@ class TestBadInput(unittest.TestCase): ''' Attempt to register without the password key/value ''' - self.input_is_missing_data(self.config_no_password) + self.SM._sub_man_cli = mock.MagicMock( + side_effect=[util.ProcessExecutionError, (self.reg, 'bar')]) + self.handle(self.name, self.config_no_password, self.cloud_init, + self.log, self.args) + self.assertEqual(self.SM._sub_man_cli.call_count, 0) def test_no_org(self): ''' -- cgit v1.2.3 From 32340db1f8b232855b635686e89608e23f2530cc Mon Sep 17 00:00:00 2001 From: Stéphane Graber Date: Mon, 11 Apr 2016 12:58:01 -0400 Subject: Add tests for lxd-bridge --- tests/unittests/test_handler/test_handler_lxd.py | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'tests') diff --git a/tests/unittests/test_handler/test_handler_lxd.py b/tests/unittests/test_handler/test_handler_lxd.py index 7ffa2a53..5f61ba6a 100644 --- a/tests/unittests/test_handler/test_handler_lxd.py +++ b/tests/unittests/test_handler/test_handler_lxd.py @@ -73,3 +73,62 @@ class TestLxd(t_help.TestCase): cc_lxd.handle('cc_lxd', {'package_update': True}, cc, LOG, []) self.assertFalse(cc.distro.install_packages.called) self.assertFalse(mock_util.subp.called) + + def test_lxd_debconf_new_full(self): + data = {"mode": "new", + "name": "testbr0", + "ipv4_address": "10.0.8.1", + "ipv4_netmask": "24", + "ipv4_dhcp_first": "10.0.8.2", + "ipv4_dhcp_last": "10.0.8.254", + "ipv4_dhcp_leases": "250", + "ipv4_nat": "true", + "ipv6_address": "fd98:9e0:3744::1", + "ipv6_netmask": "64", + "ipv6_nat": "true", + "domain": "lxd"} + self.assertEquals( + cc_lxd.bridge_to_debconf(data), + {"lxd/setup-bridge": "true", + "lxd/bridge-name": "testbr0", + "lxd/bridge-ipv4": "true", + "lxd/bridge-ipv4-address": "10.0.8.1", + "lxd/bridge-ipv4-netmask": "24", + "lxd/bridge-ipv4-dhcp-first": "10.0.8.2", + "lxd/bridge-ipv4-dhcp-last": "10.0.8.254", + "lxd/bridge-ipv4-dhcp-leases": "250", + "lxd/bridge-ipv4-nat": "true", + "lxd/bridge-ipv6": "true", + "lxd/bridge-ipv6-address": "fd98:9e0:3744::1", + "lxd/bridge-ipv6-netmask": "64", + "lxd/bridge-ipv6-nat": "true", + "lxd/bridge-domain": "lxd"}) + + def test_lxd_debconf_new_partial(self): + data = {"mode": "new", + "ipv6_address": "fd98:9e0:3744::1", + "ipv6_netmask": "64", + "ipv6_nat": "true"} + self.assertEquals( + cc_lxd.bridge_to_debconf(data), + {"lxd/setup-bridge": "true", + "lxd/bridge-ipv6": "true", + "lxd/bridge-ipv6-address": "fd98:9e0:3744::1", + "lxd/bridge-ipv6-netmask": "64", + "lxd/bridge-ipv6-nat": "true"}) + + def test_lxd_debconf_existing(self): + data = {"mode": "existing", + "name": "testbr0"} + self.assertEquals( + cc_lxd.bridge_to_debconf(data), + {"lxd/setup-bridge": "false", + "lxd/use-existing-bridge": "true", + "lxd/bridge-name": "testbr0"}) + + def test_lxd_debconf_none(self): + data = {"mode": "none"} + self.assertEquals( + cc_lxd.bridge_to_debconf(data), + {"lxd/setup-bridge": "false", + "lxd/bridge-name": ""}) -- cgit v1.2.3 From 7122f7d6fac6eb78922a474facfd9d439d1bf5b6 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 12 Apr 2016 10:38:09 -0400 Subject: chef: straighten out validation_cert and validation_key Now, validation_key is always a path to a file, as it is in chef's client.rb syntax. validation_cert is always the *content* of that file that should be written. However, if validation_cert is the string "system", then we do not write that value, but rather assume the file exists. LP: #1568940 --- cloudinit/config/cc_chef.py | 21 ++++---- doc/examples/cloud-config-chef.txt | 4 +- templates/chef_client.rb.tmpl | 2 +- tests/unittests/test_handler/test_handler_chef.py | 65 ++++++++++++++++++++++- 4 files changed, 79 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py index 28711a59..07dacb0c 100644 --- a/cloudinit/config/cc_chef.py +++ b/cloudinit/config/cc_chef.py @@ -38,8 +38,10 @@ It can be configured with the following option structure:: chef: directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef, /var/cache/chef, /var/backups/chef, /var/run/chef) - validation_key or validation_cert: (optional string to be written to - /etc/chef/validation.pem) + validation_cert: (optional string to be written to file validation_key) + special value 'system' means set use existing file + validation_key: (optional the path for validation_cert. default + /etc/chef/validation.pem) firstboot_path: (path to write run_list and initial_attributes keys that should also be present in this configuration, defaults to /etc/chef/firstboot.json) @@ -64,6 +66,7 @@ It can be configured with the following option structure:: server_url: show_time: ssl_verify_mode: + validation_cert: validation_key: validation_name: """ @@ -105,6 +108,7 @@ CHEF_RB_TPL_DEFAULTS = { # These are not symbols... 'log_location': '/var/log/chef/client.log', 'validation_key': CHEF_VALIDATION_PEM_PATH, + 'validation_cert': None, 'client_key': "/etc/chef/client.pem", 'json_attribs': CHEF_FB_PATH, 'file_cache_path': "/var/cache/chef", @@ -201,13 +205,12 @@ def handle(name, cfg, cloud, log, _args): for d in itertools.chain(chef_dirs, REQUIRED_CHEF_DIRS): util.ensure_dir(d) - # Set the validation key based on the presence of either 'validation_key' - # or 'validation_cert'. In the case where both exist, 'validation_key' - # takes precedence - for key in ('validation_key', 'validation_cert'): - if key in chef_cfg and chef_cfg[key]: - util.write_file(CHEF_VALIDATION_PEM_PATH, chef_cfg[key]) - break + vkey_path = chef_cfg.get('validation_key', CHEF_VALIDATION_PEM_PATH) + vcert = chef_cfg.get('validation_cert') + # special value 'system' means do not overwrite the file + # but still render the template to contain 'validation_key' + if vcert and vcert != "system": + util.write_file(vkey_path, vcert) # Create the chef config from template template_fn = cloud.get_template_filename('chef_client.rb') diff --git a/doc/examples/cloud-config-chef.txt b/doc/examples/cloud-config-chef.txt index 4edad653..b886cba2 100644 --- a/doc/examples/cloud-config-chef.txt +++ b/doc/examples/cloud-config-chef.txt @@ -67,7 +67,9 @@ chef: # Default validation name is chef-validator validation_name: "yourorg-validator" - validation_key: | + # if validation_cert's value is "system" then it is expected + # that the file already exists on the system. + validation_cert: | -----BEGIN RSA PRIVATE KEY----- YOUR-ORGS-VALIDATION-KEY-HERE -----END RSA PRIVATE KEY----- diff --git a/templates/chef_client.rb.tmpl b/templates/chef_client.rb.tmpl index c4069d22..cbb6b15f 100644 --- a/templates/chef_client.rb.tmpl +++ b/templates/chef_client.rb.tmpl @@ -26,7 +26,7 @@ log_location "{{log_location}}" {% if validation_name %} validation_client_name "{{validation_name}}" {% endif %} -{% if validation_key %} +{% if validation_cert %} validation_key "{{validation_key}}" {% endif %} {% if client_key %} diff --git a/tests/unittests/test_handler/test_handler_chef.py b/tests/unittests/test_handler/test_handler_chef.py index edad88cb..7763f23b 100644 --- a/tests/unittests/test_handler/test_handler_chef.py +++ b/tests/unittests/test_handler/test_handler_chef.py @@ -75,17 +75,28 @@ class TestChef(t_help.FilesystemMockingTestCase): 'chef': { 'server_url': 'localhost', 'validation_name': 'bob', + 'validation_key': "/etc/chef/vkey.pem", + 'validation_cert': "this is my cert", }, } cc_chef.handle('chef', cfg, self.fetch_cloud('ubuntu'), LOG, []) for d in cc_chef.CHEF_DIRS: self.assertTrue(os.path.isdir(d)) c = util.load_file(cc_chef.CHEF_RB_PATH) + + # the content of these keys is not expected to be rendered to tmpl + unrendered_keys = ('validation_cert',) for k, v in cfg['chef'].items(): + if k in unrendered_keys: + continue self.assertIn(v, c) for k, v in cc_chef.CHEF_RB_TPL_DEFAULTS.items(): - if isinstance(v, six.string_types): - self.assertIn(v, c) + if k in unrendered_keys: + continue + # the value from the cfg overrides that in the default + val = cfg['chef'].get(k, v) + if isinstance(val, six.string_types): + self.assertIn(val, c) c = util.load_file(cc_chef.CHEF_FB_PATH) self.assertEqual({}, json.loads(c)) @@ -131,3 +142,53 @@ class TestChef(t_help.FilesystemMockingTestCase): c = util.load_file(cc_chef.CHEF_RB_PATH) self.assertNotIn('json_attribs', c) self.assertNotIn('Formatter.show_time', c) + + @t_help.skipIf(not os.path.isfile(CLIENT_TEMPL), + CLIENT_TEMPL + " is not available") + def test_validation_cert_and_validation_key(self): + # test validation_cert content is written to validation_key path + tpl_file = util.load_file('templates/chef_client.rb.tmpl') + self.patchUtils(self.tmp) + self.patchOS(self.tmp) + + util.write_file('/etc/cloud/templates/chef_client.rb.tmpl', tpl_file) + v_path = '/etc/chef/vkey.pem' + v_cert = 'this is my cert' + cfg = { + 'chef': { + 'server_url': 'localhost', + 'validation_name': 'bob', + 'validation_key': v_path, + 'validation_cert': v_cert + }, + } + cc_chef.handle('chef', cfg, self.fetch_cloud('ubuntu'), LOG, []) + content = util.load_file(cc_chef.CHEF_RB_PATH) + self.assertIn(v_path, content) + util.load_file(v_path) + self.assertEqual(v_cert, util.load_file(v_path)) + + def test_validation_cert_with_system(self): + # test validation_cert content is not written over system file + tpl_file = util.load_file('templates/chef_client.rb.tmpl') + self.patchUtils(self.tmp) + self.patchOS(self.tmp) + + v_path = '/etc/chef/vkey.pem' + v_cert = "system" + expected_cert = "this is the system file certificate" + cfg = { + 'chef': { + 'server_url': 'localhost', + 'validation_name': 'bob', + 'validation_key': v_path, + 'validation_cert': v_cert + }, + } + util.write_file('/etc/cloud/templates/chef_client.rb.tmpl', tpl_file) + util.write_file(v_path, expected_cert) + cc_chef.handle('chef', cfg, self.fetch_cloud('ubuntu'), LOG, []) + content = util.load_file(cc_chef.CHEF_RB_PATH) + self.assertIn(v_path, content) + util.load_file(v_path) + self.assertEqual(expected_cert, util.load_file(v_path)) -- cgit v1.2.3