def test_existing_ovf_diff(self): # waagent/SharedConfig must be removed if ovfenv is found elsewhere # 'get_data' should remove SharedConfig.xml in /var/lib/waagent # if ovf-env.xml differs. cached_ovfenv = construct_valid_ovf_env( {'userdata': b64e("FOO_USERDATA")}) new_ovfenv = construct_valid_ovf_env( {'userdata': b64e("NEW_USERDATA")}) populate_dir(self.waagent_d, {'ovf-env.xml': cached_ovfenv, 'SharedConfig.xml': "mysharedconfigxml", 'otherfile': 'otherfilecontent'}) dsrc = self._get_ds({'ovfcontent': new_ovfenv}) ret = dsrc.get_data() self.assertTrue(ret) self.assertEqual(dsrc.userdata_raw, b"NEW_USERDATA") self.assertTrue(os.path.exists( os.path.join(self.waagent_d, 'otherfile'))) self.assertFalse( os.path.exists(os.path.join(self.waagent_d, 'SharedConfig.xml'))) self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'ovf-env.xml'))) self.assertEqual(new_ovfenv, load_file(os.path.join(self.waagent_d, 'ovf-env.xml')))
def setUp(self): super(TestJoyentMetadataClient, self).setUp() self.serial = mock.MagicMock(spec=serial.Serial) self.request_id = 0xabcdef12 self.metadata_value = 'value' self.response_parts = { 'command': 'SUCCESS', 'crc': 'b5a9ff00', 'length': 17 + len(b64e(self.metadata_value)), 'payload': b64e(self.metadata_value), 'request_id': '{0:08x}'.format(self.request_id), } def make_response(): payload = '' if self.response_parts['payload']: payload = ' {0}'.format(self.response_parts['payload']) del self.response_parts['payload'] return ( 'V2 {length} {crc} {request_id} {command}{payload}\n'.format( payload=payload, **self.response_parts).encode('ascii')) self.serial.readline.side_effect = make_response self.patched_funcs.enter_context( mock.patch('cloudinit.sources.DataSourceSmartOS.random.randint', mock.Mock(return_value=self.request_id)))
def test_existing_ovf_diff(self): # waagent/SharedConfig must be removed if ovfenv is found elsewhere # 'get_data' should remove SharedConfig.xml in /var/lib/waagent # if ovf-env.xml differs. cached_ovfenv = construct_valid_ovf_env( {'userdata': b64e("FOO_USERDATA")}) new_ovfenv = construct_valid_ovf_env( {'userdata': b64e("NEW_USERDATA")}) populate_dir( self.waagent_d, { 'ovf-env.xml': cached_ovfenv, 'SharedConfig.xml': "mysharedconfigxml", 'otherfile': 'otherfilecontent' }) dsrc = self._get_ds({'ovfcontent': new_ovfenv}) ret = dsrc.get_data() self.assertTrue(ret) self.assertEqual(dsrc.userdata_raw, b"NEW_USERDATA") self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'otherfile'))) self.assertFalse( os.path.exists(os.path.join(self.waagent_d, 'SharedConfig.xml'))) self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'ovf-env.xml'))) new_xml = load_file(os.path.join(self.waagent_d, 'ovf-env.xml')) self.xml_equals(new_ovfenv, new_xml)
def test_handle_args_root_processes_user_data(self, ud_src, ud_expected, vd_src, vd_expected, capsys, tmpdir): """Support reading multiple user-data file content types""" paths, run_dir, user_data, vendor_data = self._setup_paths( tmpdir, ud_val=ud_src, vd_val=vd_src) sensitive_file = run_dir.join(INSTANCE_JSON_SENSITIVE_FILE) sensitive_file.write('{"my-var": "it worked"}') args = self.args(debug=False, dump_all=True, format=None, instance_data=None, list_keys=False, user_data=user_data.strpath, vendor_data=vendor_data.strpath, varname=None) with mock.patch('cloudinit.cmd.query.read_cfg_paths') as m_paths: m_paths.return_value = paths with mock.patch('os.getuid') as m_getuid: m_getuid.return_value = 0 assert 0 == query.handle_args('anyname', args) out, _err = capsys.readouterr() cmd_output = json.loads(out) assert "it worked" == cmd_output['my_var'] if ud_expected == "ci-b64:": ud_expected = "ci-b64:{}".format(b64e(ud_src)) if vd_expected == "ci-b64:": vd_expected = "ci-b64:{}".format(b64e(vd_src)) assert ud_expected == cmd_output['userdata'] assert vd_expected == cmd_output['vendordata']
def test_provide_disk_aliases(self): # Make sure that user can affect disk aliases dscfg = {'disk_aliases': {'ephemeral0': '/dev/sdc'}} odata = { 'HostName': "myhost", 'UserName': "******", 'dscfg': { 'text': b64e(yaml.dump(dscfg)), 'encoding': 'base64' } } usercfg = { 'disk_setup': { '/dev/sdc': { 'something': '...' }, 'ephemeral0': False } } userdata = '#cloud-config' + yaml.dump(usercfg) + "\n" ovfcontent = construct_valid_ovf_env(data=odata, userdata=userdata) data = {'ovfcontent': ovfcontent, 'sys_cfg': {}} dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) cfg = dsrc.get_config_obj() self.assertTrue(cfg)
def test_user_data_base64_encoding(self): for k in ("USER_DATA", "USERDATA"): my_d = os.path.join(self.tmp, k) populate_context_dir(my_d, {k: util.b64e(USER_DATA), "USERDATA_ENCODING": "base64"}) results = ds.read_context_disk_dir(my_d) self.assertTrue("userdata" in results) self.assertEqual(USER_DATA, results["userdata"])
def test_list_metadata_returns_list(self): parts = ['foo', 'bar'] value = b64e('\n'.join(parts)) self.response_parts['payload'] = value self.response_parts['crc'] = '40873553' self.response_parts['length'] = SUCCESS_LEN + len(value) client = self._get_client() self.assertEqual(client.list(), parts)
def test_list_metadata_returns_list(self): parts = ["foo", "bar"] value = b64e("\n".join(parts)) self.response_parts["payload"] = value self.response_parts["crc"] = "40873553" self.response_parts["length"] = SUCCESS_LEN + len(value) client = self._get_client() self.assertEqual(client.list(), parts)
def test_user_data_encoding_required_for_decode(self): b64userdata = util.b64e(USER_DATA) for k in ('USER_DATA', 'USERDATA'): my_d = os.path.join(self.tmp, k) populate_context_dir(my_d, {k: b64userdata}) results = ds.read_context_disk_dir(my_d, mock.Mock()) self.assertTrue('userdata' in results) self.assertEqual(b64userdata, results['userdata'])
def test_user_data_base64_encoding(self): for k in ('USER_DATA', 'USERDATA'): my_d = os.path.join(self.tmp, k) populate_context_dir(my_d, {k: util.b64e(USER_DATA), 'USERDATA_ENCODING': 'base64'}) results = ds.read_context_disk_dir(my_d) self.assertTrue('userdata' in results) self.assertEqual(USER_DATA, results['userdata'])
def get_ovf_env_with_dscfg(self, hostname, cfg): odata = { 'HostName': hostname, 'dscfg': { 'text': b64e(yaml.dump(cfg)), 'encoding': 'base64' } } return construct_valid_ovf_env(data=odata)
def test_user_data_encoding_required_for_decode(self): b64userdata = util.b64e(USER_DATA) for k in ('USER_DATA', 'USERDATA'): my_d = os.path.join(self.tmp, k) populate_context_dir(my_d, {k: b64userdata}) results = ds.read_context_disk_dir(my_d) self.assertTrue('userdata' in results) self.assertEqual(b64userdata, results['userdata'])
def test_userdata_found(self): mydata = "FOOBAR" odata = {'UserData': {'text': b64e(mydata), 'encoding': 'base64'}} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) self.assertEqual(dsrc.userdata_raw, mydata.encode('utf-8'))
def construct_valid_ovf_env(data=None, pubkeys=None, userdata=None): if data is None: data = {'HostName': 'FOOHOST'} if pubkeys is None: pubkeys = {} content = """<?xml version="1.0" encoding="utf-8"?> <Environment xmlns="http://schemas.dmtf.org/ovf/environment/1" xmlns:oe="http://schemas.dmtf.org/ovf/environment/1" xmlns:wa="http://schemas.microsoft.com/windowsazure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <wa:ProvisioningSection><wa:Version>1.0</wa:Version> <LinuxProvisioningConfigurationSet xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType> """ for key, dval in data.items(): if isinstance(dval, dict): val = dval.get('text') attrs = ' ' + ' '.join(["%s='%s'" % (k, v) for k, v in dval.items() if k != 'text']) else: val = dval attrs = "" content += "<%s%s>%s</%s>\n" % (key, attrs, val, key) if userdata: content += "<UserData>%s</UserData>\n" % (b64e(userdata)) if pubkeys: content += "<SSH><PublicKeys>\n" for fp, path, value in pubkeys: content += " <PublicKey>" if fp and path: content += ("<Fingerprint>%s</Fingerprint><Path>%s</Path>" % (fp, path)) if value: content += "<Value>%s</Value>" % value content += "</PublicKey>\n" content += "</PublicKeys></SSH>" content += """ </LinuxProvisioningConfigurationSet> </wa:ProvisioningSection> <wa:PlatformSettingsSection><wa:Version>1.0</wa:Version> <PlatformSettings xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <KmsServerHostname>kms.core.windows.net</KmsServerHostname> <ProvisionGuestAgent>false</ProvisionGuestAgent> <GuestAgentPackageName i:nil="true" /> </PlatformSettings></wa:PlatformSettingsSection> </Environment> """ return content
def test_set_hostname_disabled(self): # config specifying set_hostname off should not bounce cfg = {'set_hostname': False} odata = {'HostName': "xhost", 'dscfg': {'text': b64e(yaml.dump(cfg)), 'encoding': 'base64'}} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} self._get_ds(data).get_data() self.assertEqual(data.get('apply_hostname_bounce', "N/A"), "N/A")
def test_user_data_base64_encoding(self): for k in ("USER_DATA", "USERDATA"): my_d = os.path.join(self.tmp, k) populate_context_dir( my_d, {k: util.b64e(USER_DATA), "USERDATA_ENCODING": "base64"} ) results = ds.read_context_disk_dir(my_d, mock.Mock()) self.assertTrue("userdata" in results) self.assertEqual(USER_DATA, results["userdata"])
def setUp(self): super(TestJoyentMetadataClient, self).setUp() self.serial = mock.MagicMock(spec=serial.Serial) self.request_id = 0xABCDEF12 self.metadata_value = "value" self.response_parts = { "command": "SUCCESS", "crc": "b5a9ff00", "length": SUCCESS_LEN + len(b64e(self.metadata_value)), "payload": b64e(self.metadata_value), "request_id": "{0:08x}".format(self.request_id), } def make_response(): payloadstr = "" if "payload" in self.response_parts: payloadstr = " {0}".format(self.response_parts["payload"]) return ( "V2 {length} {crc} {request_id} " "{command}{payloadstr}\n".format( payloadstr=payloadstr, **self.response_parts ).encode("ascii") ) self.metasource_data = None def read_response(length): if not self.metasource_data: self.metasource_data = make_response() self.metasource_data_len = len(self.metasource_data) resp = self.metasource_data[:length] self.metasource_data = self.metasource_data[length:] return resp self.serial.read.side_effect = read_response self.patched_funcs.enter_context( mock.patch( "cloudinit.sources.DataSourceSmartOS.random.randint", mock.Mock(return_value=self.request_id), ) )
def test_user_cfg_set_agent_command(self): # set dscfg in via base64 encoded yaml cfg = {'agent_command': "my_command"} odata = {'HostName': "myhost", 'UserName': "******", 'dscfg': {'text': b64e(yaml.dump(cfg)), 'encoding': 'base64'}} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) self.assertEqual(data['agent_invoked'], cfg['agent_command'])
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 get_metadata(self, metadata_key): LOG.debug('Fetching metadata key "%s"...', metadata_key) request_id = '{0:08x}'.format(random.randint(0, 0xffffffff)) message_body = '{0} GET {1}'.format(request_id, util.b64e(metadata_key)) msg = 'V2 {0} {1} {2}\n'.format( len(message_body), self._checksum(message_body), message_body) LOG.debug('Writing "%s" to serial port.', msg) self.serial.write(msg.encode('ascii')) response = self.serial.readline().decode('ascii') LOG.debug('Read "%s" from serial port.', response) return self._get_value_from_frame(request_id, response)
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, self._get_cloud('ubuntu'), LOG, []) contents = util.load_file(self._seed_file) self.assertEqual("kit-kat", contents)
def test_b64_keys(self): my_returns = MOCK_RETURNS.copy() my_returns['base64_keys'] = 'hostname,ignored' for k in ('hostname',): my_returns[k] = b64e(my_returns[k]) dsrc = self._get_ds(mockdata=my_returns) ret = dsrc.get_data() self.assertTrue(ret) self.assertEquals(MOCK_RETURNS['hostname'], dsrc.metadata['local-hostname']) self.assertEquals(MOCK_RETURNS['cloud-init:user-data'], dsrc.userdata_raw)
def get_metadata(self, metadata_key): LOG.debug('Fetching metadata key "%s"...', metadata_key) request_id = '{0:08x}'.format(random.randint(0, 0xffffffff)) message_body = '{0} GET {1}'.format(request_id, util.b64e(metadata_key)) msg = 'V2 {0} {1} {2}\n'.format(len(message_body), self._checksum(message_body), message_body) LOG.debug('Writing "%s" to serial port.', msg) self.serial.write(msg.encode('ascii')) response = self.serial.readline().decode('ascii') LOG.debug('Read "%s" from serial port.', response) return self._get_value_from_frame(request_id, response)
def setUp(self): super(TestJoyentMetadataClient, self).setUp() self.serial = mock.MagicMock(spec=serial.Serial) self.request_id = 0xabcdef12 self.metadata_value = 'value' self.response_parts = { 'command': 'SUCCESS', 'crc': 'b5a9ff00', 'length': SUCCESS_LEN + len(b64e(self.metadata_value)), 'payload': b64e(self.metadata_value), 'request_id': '{0:08x}'.format(self.request_id), } def make_response(): payloadstr = '' if 'payload' in self.response_parts: payloadstr = ' {0}'.format(self.response_parts['payload']) return ('V2 {length} {crc} {request_id} ' '{command}{payloadstr}\n'.format( payloadstr=payloadstr, **self.response_parts).encode('ascii')) self.metasource_data = None def read_response(length): if not self.metasource_data: self.metasource_data = make_response() self.metasource_data_len = len(self.metasource_data) resp = self.metasource_data[:length] self.metasource_data = self.metasource_data[length:] return resp self.serial.read.side_effect = read_response self.patched_funcs.enter_context( mock.patch('cloudinit.sources.DataSourceSmartOS.random.randint', mock.Mock(return_value=self.request_id)))
def setUp(self): super(TestJoyentMetadataClient, self).setUp() self.serial = mock.MagicMock(spec=serial.Serial) self.request_id = 0xABCDEF12 self.metadata_value = "value" self.response_parts = { "command": "SUCCESS", "crc": "b5a9ff00", "length": 17 + len(b64e(self.metadata_value)), "payload": b64e(self.metadata_value), "request_id": "{0:08x}".format(self.request_id), } def make_response(): payloadstr = "" if "payload" in self.response_parts: payloadstr = " {0}".format(self.response_parts["payload"]) return "V2 {length} {crc} {request_id} " "{command}{payloadstr}\n".format( payloadstr=payloadstr, **self.response_parts ).encode("ascii") self.metasource_data = None def read_response(length): if not self.metasource_data: self.metasource_data = make_response() self.metasource_data_len = len(self.metasource_data) resp = self.metasource_data[:length] self.metasource_data = self.metasource_data[length:] return resp self.serial.read.side_effect = read_response self.patched_funcs.enter_context( mock.patch("cloudinit.sources.DataSourceSmartOS.random.randint", mock.Mock(return_value=self.request_id)) )
def test_apply_bounce_call_configurable(self): # hostname_bounce should be configurable in datasource cfg cfg = {'hostname_bounce': {'interface': 'eth1', 'policy': 'off', 'command': 'my-bounce-command', 'hostname_command': 'my-hostname-command'}} odata = {'HostName': "xhost", 'dscfg': {'text': b64e(yaml.dump(cfg)), 'encoding': 'base64'}} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} self._get_ds(data).get_data() for k in cfg['hostname_bounce']: self.assertIn(k, data['apply_hostname_bounce']) for k, v in cfg['hostname_bounce'].items(): self.assertEqual(data['apply_hostname_bounce'][k], v)
def test_b64_userdata(self): my_returns = MOCK_RETURNS.copy() my_returns['b64-cloud-init:user-data'] = "true" my_returns['b64-hostname'] = "true" for k in ('hostname', 'cloud-init:user-data'): my_returns[k] = b64e(my_returns[k]) dsrc = self._get_ds(mockdata=my_returns) ret = dsrc.get_data() self.assertTrue(ret) self.assertEquals(MOCK_RETURNS['hostname'], dsrc.metadata['local-hostname']) self.assertEquals(MOCK_RETURNS['cloud-init:user-data'], dsrc.userdata_raw) self.assertEquals(MOCK_RETURNS['root_authorized_keys'], dsrc.metadata['public-keys'])
def test_non_utf8_encoding_gets_b64encoded(self): """When non-utf-8 values exist in py2 instance-data is b64encoded.""" tmp = self.tmp_dir() datasource = DataSourceTestSubclassNet(self.sys_cfg, self.distro, Paths({'run_dir': tmp}), custom_metadata={ 'key1': 'val1', 'key2': { 'key2.1': b'ab\xaadef' } }) self.assertTrue(datasource.get_data()) json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp) instance_json = util.load_json(util.load_file(json_file)) key21_value = instance_json['ds']['meta_data']['key2']['key2.1'] self.assertEqual('ci-b64:' + util.b64e(b'ab\xaadef'), key21_value)
def test_provide_disk_aliases(self): # Make sure that user can affect disk aliases dscfg = {'disk_aliases': {'ephemeral0': '/dev/sdc'}} odata = {'HostName': "myhost", 'UserName': "******", 'dscfg': {'text': b64e(yaml.dump(dscfg)), 'encoding': 'base64'}} usercfg = {'disk_setup': {'/dev/sdc': {'something': '...'}, 'ephemeral0': False}} userdata = '#cloud-config' + yaml.dump(usercfg) + "\n" ovfcontent = construct_valid_ovf_env(data=odata, userdata=userdata) data = {'ovfcontent': ovfcontent, 'sys_cfg': {}} dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) cfg = dsrc.get_config_obj() self.assertTrue(cfg)
def test_existing_ovf_same(self): # waagent/SharedConfig left alone if found ovf-env.xml same as cached odata = {'UserData': b64e("SOMEUSERDATA")} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} populate_dir(self.waagent_d, {'ovf-env.xml': data['ovfcontent'], 'otherfile': 'otherfile-content', 'SharedConfig.xml': 'mysharedconfig'}) dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) self.assertTrue(os.path.exists( os.path.join(self.waagent_d, 'ovf-env.xml'))) self.assertTrue(os.path.exists( os.path.join(self.waagent_d, 'otherfile'))) self.assertTrue(os.path.exists( os.path.join(self.waagent_d, 'SharedConfig.xml')))
def test_base64_all(self): # metadata provided base64_all of true my_returns = MOCK_RETURNS.copy() my_returns['base64_all'] = "true" for k in ('hostname', 'cloud-init:user-data'): my_returns[k] = b64e(my_returns[k]) dsrc = self._get_ds(mockdata=my_returns) ret = dsrc.get_data() self.assertTrue(ret) self.assertEquals(MOCK_RETURNS['hostname'], dsrc.metadata['local-hostname']) self.assertEquals(MOCK_RETURNS['cloud-init:user-data'], dsrc.userdata_raw) self.assertEquals(MOCK_RETURNS['root_authorized_keys'], dsrc.metadata['public-keys']) self.assertEquals(MOCK_RETURNS['disable_iptables_flag'], dsrc.metadata['iptables_disable']) self.assertEquals(MOCK_RETURNS['enable_motd_sys_info'], dsrc.metadata['motd_sys_info'])
def test_existing_ovf_same(self): # waagent/SharedConfig left alone if found ovf-env.xml same as cached odata = {'UserData': b64e("SOMEUSERDATA")} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} populate_dir( self.waagent_d, { 'ovf-env.xml': data['ovfcontent'], 'otherfile': 'otherfile-content', 'SharedConfig.xml': 'mysharedconfig' }) dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'ovf-env.xml'))) self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'otherfile'))) self.assertTrue( os.path.exists(os.path.join(self.waagent_d, 'SharedConfig.xml')))
def get_metadata(self, metadata_key): LOG.debug('Fetching metadata key "%s"...', metadata_key) request_id = '{0:08x}'.format(random.randint(0, 0xffffffff)) message_body = '{0} GET {1}'.format(request_id, util.b64e(metadata_key)) msg = 'V2 {0} {1} {2}\n'.format( len(message_body), self._checksum(message_body), message_body) LOG.debug('Writing "%s" to metadata transport.', msg) self.metasource.write(msg.encode('ascii')) self.metasource.flush() response = bytearray() response.extend(self.metasource.read(1)) while response[-1:] != b'\n': response.extend(self.metasource.read(1)) response = response.rstrip().decode('ascii') LOG.debug('Read "%s" from metadata transport.', response) if 'SUCCESS' not in response: return None return self._get_value_from_frame(request_id, response)
def test_get_metadata_base64_encodes_argument(self): key = 'my_key' parts = self._get_written_line(key).decode('ascii').strip().split(' ') self.assertEqual(b64e(key), parts[5])
def test_get_metadata_base64_encodes_argument(self): key = "my_key" parts = self._get_written_line(key).decode("ascii").strip().split(" ") self.assertEqual(b64e(key), parts[5])