def get_metadata_item(context, path_tokens, os_instance_id, remote_ip): version = path_tokens[0] if version == "latest": version = VERSIONS[-1] elif version not in VERSIONS: raise exception.EC2MetadataNotFound() ec2_instance, ec2_reservation = (_get_ec2_instance_and_reservation( context, os_instance_id)) # NOTE(ft): check for case of Neutron metadata proxy. # It sends project_id as X-Tenant-ID HTTP header. We make sure it's correct if context.project_id != ec2_reservation['ownerId']: LOG.warning( _('Tenant_id %(tenant_id)s does not match tenant_id ' 'of instance %(instance_id)s.'), { 'tenant_id': context.project_id, 'instance_id': os_instance_id }) raise exception.EC2MetadataNotFound() metadata = _build_metadata(context, ec2_instance, ec2_reservation, os_instance_id, remote_ip) # TODO(ft): cache built metadata metadata = _cut_down_to_version(metadata, version) metadata_item = _find_path_in_tree(metadata, path_tokens[1:]) return _format_metadata_item(metadata_item)
def _find_path_in_tree(data, path_tokens): # given a dict/list tree, and a path in that tree, return data found there. for i in range(0, len(path_tokens)): if isinstance(data, dict) or isinstance(data, list): if path_tokens[i] in data: data = data[path_tokens[i]] else: raise exception.EC2MetadataNotFound() else: if i != len(path_tokens) - 1: raise exception.EC2MetadataNotFound() data = data[path_tokens[i]] return data
def test_build_proxy_request_headers(self, get_remote_ip, get_context, sign_instance_id): req = mock.Mock(headers={}) req.headers = {'X-Instance-ID': 'fake_instance_id', 'fake_key': 'fake_value'} self.assertThat(self.handler._build_proxy_request_headers(req), matchers.DictMatches(req.headers)) req.headers = {'fake_key': 'fake_value'} get_remote_ip.return_value = 'fake_instance_ip' get_context.return_value = 'fake_context' sign_instance_id.return_value = 'signed' with mock.patch('ec2api.metadata.api.' 'get_os_instance_and_project_id') as get_ids: get_ids.return_value = ('fake_instance_id', 'fake_project_id') self.assertThat(self.handler._build_proxy_request_headers(req), matchers.DictMatches( {'X-Forwarded-For': 'fake_instance_ip', 'X-Instance-ID': 'fake_instance_id', 'X-Tenant-ID': 'fake_project_id', 'X-Instance-ID-Signature': 'signed'})) get_remote_ip.assert_called_with(req) get_context.assert_called_with() sign_instance_id.assert_called_with('fake_instance_id') get_ids.assert_called_with('fake_context', 'fake_instance_ip') get_ids.side_effect = exception.EC2MetadataNotFound() self.assertRaises(exception.EC2MetadataNotFound, self.handler._build_proxy_request_headers, req)
def test_proxy_call_no_instance(self, proxy): req = mock.Mock(path_info='/openstack') proxy.side_effect = exception.EC2MetadataNotFound() with mock.patch.object(metadata.MetadataRequestHandler, '_get_requester'): retval = self.handler(req) self.assertIsInstance(retval, webob.exc.HTTPNotFound)
def get_metadata_item(context, path_tokens, os_instance_id, remote_ip, cache_region): version = path_tokens[0] if version == "latest": version = VERSIONS[-1] elif version not in VERSIONS: raise exception.EC2MetadataNotFound() cache_key = 'ec2api-metadata-%s' % os_instance_id cache = cache_region.get(cache_key, expiration_time=CONF.metadata.cache_expiration) if cache and cache != cache_core.NO_VALUE: _check_instance_owner(context, os_instance_id, cache['owner_id']) LOG.debug("Using cached metadata for instance %s", os_instance_id) else: ec2_instance, ec2_reservation = (_get_ec2_instance_and_reservation( context, os_instance_id)) _check_instance_owner(context, os_instance_id, ec2_reservation['ownerId']) metadata = _build_metadata(context, ec2_instance, ec2_reservation, os_instance_id, remote_ip) cache = {'metadata': metadata, 'owner_id': ec2_reservation['ownerId']} cache_region.set(cache_key, cache) metadata = cache['metadata'] metadata = _cut_down_to_version(metadata, version) metadata_item = _find_path_in_tree(metadata, path_tokens[1:]) return _format_metadata_item(metadata_item)
def get_os_instance_and_project_id_by_provider_id(context, provider_id, fixed_ip): neutron = clients.neutron(context) os_subnets = neutron.list_subnets(advanced_service_providers=[provider_id], fields=['network_id']) if not os_subnets: raise exception.EC2MetadataNotFound() os_networks = [subnet['network_id'] for subnet in os_subnets['subnets']] try: os_port = neutron.list_ports(fixed_ips='ip_address=' + fixed_ip, network_id=os_networks, fields=['device_id', 'tenant_id'])['ports'][0] except IndexError: raise exception.EC2MetadataNotFound() os_instance_id = os_port['device_id'] project_id = os_port['tenant_id'] return os_instance_id, project_id
def _check_instance_owner(context, os_instance_id, owner_id): # NOTE(ft): check for case of Neutron metadata proxy. # It sends project_id as X-Tenant-ID HTTP header. # We make sure it's correct if context.project_id != owner_id: LOG.warning( 'Tenant_id %(tenant_id)s does not match tenant_id ' 'of instance %(instance_id)s.', { 'tenant_id': context.project_id, 'instance_id': os_instance_id }) raise exception.EC2MetadataNotFound()
def get_os_instance_and_project_id(context, fixed_ip): try: nova = clients.nova(context) os_address = nova.fixed_ips.get(fixed_ip) os_instances = nova.servers.list( search_opts={'hostname': os_address.hostname, 'all_tenants': True}) return next((os_instance.id, os_instance.tenant_id) for os_instance in os_instances if any((addr['addr'] == fixed_ip and addr['OS-EXT-IPS:type'] == 'fixed') for addr in itertools.chain( *os_instance.addresses.itervalues()))) except (nova_exception.NotFound, StopIteration): raise exception.EC2MetadataNotFound()
def _get_ec2_instance_and_reservation(context, os_instance_id): instance_id = ec2utils.os_id_to_ec2_id(context, 'i', os_instance_id) try: ec2_reservations = instance_api.describe_instances( context, [instance_id]) except exception.InvalidInstanceIDNotFound: ec2_reservations = instance_api.describe_instances( context, filter=[{'name': 'instance-id', 'value': [instance_id]}]) if (len(ec2_reservations['reservationSet']) != 1 or len(ec2_reservations['reservationSet'][0]['instancesSet']) != 1): LOG.error(_('Failed to get metadata for instance id: %s'), os_instance_id) raise exception.EC2MetadataNotFound() ec2_reservation = ec2_reservations['reservationSet'][0] ec2_instance = ec2_reservation['instancesSet'][0] return ec2_instance, ec2_reservation
def test_version_root(self, get_metadata): get_metadata.return_value = 'fake' request = webob.Request.blank('/latest') response = request.get_response(self.handler) self.assertEqual('fake', response.body) response_ctype = response.headers['Content-Type'] self.assertTrue(response_ctype.startswith("text/plain")) get_metadata.assert_called_with(mock.ANY, ['latest']) get_metadata.side_effect = exception.EC2MetadataNotFound() request = webob.Request.blank('/latest') response = request.get_response(self.handler) self.assertEqual(404, response.status_int) with mock.patch.object(metadata, 'LOG') as log: get_metadata.side_effect = Exception() request = webob.Request.blank('/latest') response = request.get_response(self.handler) self.assertEqual(500, response.status_int) self.assertEqual(len(log.mock_calls), 2)
def test_proxy_call_no_instance(self, proxy): req = mock.Mock(path_info='/openstack') proxy.side_effect = exception.EC2MetadataNotFound() retval = self.handler(req) self.assertIsInstance(retval, webob.exc.HTTPNotFound)