def test_get_instance_nw_info_with_nets(self): # Test get instance_nw_info with networks passed in. api = quantumapi.API() self.mox.StubOutWithMock(api.db, 'instance_info_cache_update') api.db.instance_info_cache_update( mox.IgnoreArg(), self.instance['uuid'], mox.IgnoreArg()) self.moxed_client.list_ports( tenant_id=self.instance['project_id'], device_id=self.instance['uuid']).AndReturn( {'ports': self.port_data1}) self.moxed_client.list_subnets( id=mox.SameElementsAs(['my_subid1'])).AndReturn( {'subnets': self.subnet_data1}) self.moxed_client.list_ports( network_id='my_netid1', device_owner='network:dhcp').AndReturn( {'ports': self.dhcp_port_data1}) quantumv2.get_client(mox.IgnoreArg(), admin=True).MultipleTimes().AndReturn( self.moxed_client) self.mox.ReplayAll() nw_inf = api.get_instance_nw_info(self.context, self.instance, networks=self.nets1) self._verify_nw_info(nw_inf, 0)
def validate_networks(self, context, requested_networks): """Validate that the tenant has the requested networks.""" LOG.debug(_('validate_networks() for %s'), requested_networks) if not requested_networks: return search_opts = {"tenant_id": context.project_id} net_ids = [] for (net_id, _i, port_id) in requested_networks: if not port_id: net_ids.append(net_id) continue port = quantumv2.get_client(context).show_port(port_id).get('port') if not port: raise exception.PortNotFound(port_id=port_id) if port.get('device_id', None): raise exception.PortInUse(port_id=port_id) net_id = port['network_id'] if net_id in net_ids: raise exception.NetworkDuplicated(network_id=net_id) net_ids.append(net_id) search_opts['id'] = net_ids data = quantumv2.get_client(context).list_networks(**search_opts) nets = data.get('networks', []) if len(nets) != len(net_ids): requsted_netid_set = set(net_ids) returned_netid_set = set([net['id'] for net in nets]) lostid_set = requsted_netid_set - returned_netid_set id_str = '' for _id in lostid_set: id_str = id_str and id_str + ', ' + _id or _id raise exception.NetworkNotFound(network_id=id_str)
def add_fixed_ip_to_instance(self, context, instance, network_id, conductor_api=None): """Add a fixed ip to the instance from specified network.""" search_opts = {'network_id': network_id} data = quantumv2.get_client(context).list_subnets(**search_opts) ipam_subnets = data.get('subnets', []) if not ipam_subnets: raise exception.NetworkNotFoundForInstance( instance_id=instance['uuid']) zone = 'compute:%s' % instance['availability_zone'] search_opts = {'device_id': instance['uuid'], 'device_owner': zone, 'network_id': network_id} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data['ports'] for p in ports: for subnet in ipam_subnets: fixed_ips = p['fixed_ips'] fixed_ips.append({'subnet_id': subnet['id']}) port_req_body = {'port': {'fixed_ips': fixed_ips}} try: quantumv2.get_client(context).update_port(p['id'], port_req_body) return except Exception as ex: msg = _("Unable to update port %(portid)s on subnet " "%(subnet_id)s with failure: %(exception)s") LOG.debug(msg, {'portid': p['id'], 'subnet_id': subnet['id'], 'exception': ex}) raise exception.NetworkNotFoundForInstance( instance_id=instance['uuid'])
def remove_fixed_ip_from_instance(self, context, instance, address, conductor_api=None): """Remove a fixed ip from the instance.""" zone = 'compute:%s' % instance['availability_zone'] search_opts = {'device_id': instance['uuid'], 'device_owner': zone, 'fixed_ips': 'ip_address=%s' % address} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data['ports'] for p in ports: fixed_ips = p['fixed_ips'] new_fixed_ips = [] for fixed_ip in fixed_ips: if fixed_ip['ip_address'] != address: new_fixed_ips.append(fixed_ip) port_req_body = {'port': {'fixed_ips': new_fixed_ips}} try: quantumv2.get_client(context).update_port(p['id'], port_req_body) except Exception as ex: msg = _("Unable to update port %(portid)s with" " failure: %(exception)s") LOG.debug(msg, {'portid': p['id'], 'exception': ex}) return raise exception.FixedIpNotFoundForSpecificInstance( instance_uuid=instance['uuid'], ip=address)
def test_get_instance_nw_info_without_subnet(self): # Test get instance_nw_info for a port without subnet. api = quantumapi.API() self.mox.StubOutWithMock(api.db, 'instance_info_cache_update') api.db.instance_info_cache_update( mox.IgnoreArg(), self.instance['uuid'], mox.IgnoreArg()) self.moxed_client.list_ports( tenant_id=self.instance['project_id'], device_id=self.instance['uuid']).AndReturn( {'ports': self.port_data3}) self.moxed_client.list_networks( shared=False, tenant_id=self.instance['project_id']).AndReturn( {'networks': self.nets1}) self.moxed_client.list_networks( shared=True).AndReturn({'networks': []}) quantumv2.get_client(mox.IgnoreArg(), admin=True).MultipleTimes().AndReturn( self.moxed_client) self.mox.ReplayAll() nw_inf = api.get_instance_nw_info(self.context, self.instance) id_suffix = 3 self.assertEquals(0, len(nw_inf.fixed_ips())) self.assertEquals('my_netname1', nw_inf[0]['network']['label']) self.assertEquals('my_portid%s' % id_suffix, nw_inf[0]['id']) self.assertEquals('my_mac%s' % id_suffix, nw_inf[0]['address']) self.assertEquals(0, len(nw_inf[0]['network']['subnets']))
def allocate_for_instance(self, context, instance, **kwargs): """Allocate all network resources for the instance.""" LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) search_opts = {} if instance['project_id']: search_opts.update({"tenant_id": instance['project_id']}) else: msg = _('empty project id for instance %s') raise exception.InvalidInput( reason=msg % instance['display_name']) data = quantumv2.get_client(context).list_networks(**search_opts) nets = data.get('networks', []) created_port_ids = [] for network in nets: port_req_body = {'port': {'network_id': network['id'], 'admin_state_up': True, 'device_id': instance['uuid'], 'tenant_id': instance['project_id']}, } try: created_port_ids.append( quantumv2.get_client(context).create_port( port_req_body)['port']['id']) except Exception: with excutils.save_and_reraise_exception(): for port_id in created_port_ids: try: quantumv2.get_client(context).delete_port(port_id) except Exception as ex: msg = _("Fail to delete port %(portid)s with" " failure: %(exception)s") LOG.debug(msg, {'portid': port_id, 'exception': ex}) return self.get_instance_nw_info(context, instance, networks=nets)
def _get_subnets_from_port(self, context, port): """Return the subnets for a given port.""" fixed_ips = port['fixed_ips'] search_opts = {'id': [ip['subnet_id'] for ip in fixed_ips]} data = quantumv2.get_client(context).list_subnets(**search_opts) ipam_subnets = data.get('subnets', []) subnets = [] for subnet in ipam_subnets: subnet_dict = {'cidr': subnet['cidr'], 'gateway': network_model.IP( address=subnet['gateway_ip'], type='gateway'), } # attempt to populate DHCP server field search_opts = {'network_id': subnet['network_id'], 'device_owner': 'network:dhcp'} data = quantumv2.get_client(context).list_ports(**search_opts) dhcp_ports = data.get('ports', []) for p in dhcp_ports: for ip_pair in p['fixed_ips']: if ip_pair['subnet_id'] == subnet['id']: subnet_dict['dhcp_server'] = ip_pair['ip_address'] break subnet_object = network_model.Subnet(**subnet_dict) for dns in subnet.get('dns_nameservers', []): subnet_object.add_dns( network_model.IP(address=dns, type='dns')) # TODO(gongysh) get the routes for this subnet subnets.append(subnet_object) return subnets
def _test_deallocate_port_for_instance(self, number): port_data = number == 1 and self.port_data1 or self.port_data2 self.moxed_client.delete_port(port_data[0]['id']) nets = [port_data[0]['network_id']] quantumv2.get_client(mox.IgnoreArg(), admin=True).AndReturn( self.moxed_client) self.moxed_client.list_ports( tenant_id=self.instance['project_id'], device_id=self.instance['uuid']).AndReturn( {'ports': port_data[1:]}) quantumv2.get_client(mox.IgnoreArg()).MultipleTimes().AndReturn( self.moxed_client) self.moxed_client.list_networks( tenant_id=self.instance['project_id'], shared=False).AndReturn( {'networks': [self.nets2[1]]}) self.moxed_client.list_networks(shared=True).AndReturn( {'networks': []}) for port in port_data[1:]: self.moxed_client.list_subnets(id=['my_subid2']).AndReturn({}) self.mox.ReplayAll() api = quantumapi.API() nwinfo = api.deallocate_port_for_instance(self.context, self.instance, port_data[0]['id']) self.assertEqual(len(nwinfo), len(port_data[1:])) if len(port_data) > 1: self.assertEqual(nwinfo[0]['network']['id'], 'my_netid2')
def test_withtoken(self): self.flags(quantum_url="http://anyhost/") self.flags(quantum_url_timeout=30) my_context = context.RequestContext("userid", "my_tenantid", auth_token="token") self.mox.StubOutWithMock(client.Client, "__init__") client.Client.__init__( endpoint_url=FLAGS.quantum_url, token=my_context.auth_token, timeout=FLAGS.quantum_url_timeout ).AndReturn(None) self.mox.ReplayAll() quantumv2.get_client(my_context)
def test_withouttoken_keystone_not_auth(self): self.flags(quantum_auth_strategy=None) self.flags(quantum_url="http://anyhost/") self.flags(quantum_url_timeout=30) my_context = context.RequestContext("userid", "my_tenantid") self.mox.StubOutWithMock(client.Client, "__init__") client.Client.__init__( endpoint_url=CONF.quantum_url, auth_strategy=None, timeout=CONF.quantum_url_timeout ).AndReturn(None) self.mox.ReplayAll() quantumv2.get_client(my_context)
def deallocate_for_instance(self, context, instance, **kwargs): """Deallocate all network resources related to the instance.""" LOG.debug(_("deallocate_for_instance() for %s"), instance["display_name"]) search_opts = {"device_id": instance["uuid"]} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data.get("ports", []) for port in ports: try: quantumv2.get_client(context).delete_port(port["id"]) except Exception as ex: LOG.exception(_("Failed to delete quantum port %(portid)s ") % {"portid": port["id"]}) self.trigger_security_group_members_refresh(context, instance)
def deallocate_port_for_instance(self, context, instance, port_id, conductor_api=None): try: quantumv2.get_client(context).delete_port(port_id) except Exception as ex: LOG.exception(_("Failed to delete quantum port %(port_id)s ") % locals()) self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_remove_security_group_refresh(context, instance) return self._get_instance_nw_info(context, instance)
def deallocate_for_instance(self, context, instance, **kwargs): """Deallocate all network resources related to the instance.""" LOG.debug(_('deallocate_for_instance() for %s'), instance['display_name']) search_opts = {'device_id': instance['uuid']} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data.get('ports', []) for port in ports: try: quantumv2.get_client(context).delete_port(port['id']) except Exception: LOG.exception(_("Failed to delete quantum port %(portid)s ") % {'portid': port['id']})
def deallocate_for_instance(self, context, instance, **kwargs): """Deallocate all network resources related to the instance.""" LOG.debug(_("deallocate_for_instance() for %s"), instance["display_name"]) search_opts = {"device_id": instance["uuid"]} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data.get("ports", []) for port in ports: try: quantumv2.get_client(context).delete_port(port["id"]) except Exception as ex: with excutils.save_and_reraise_exception(): msg = _("Fail to delete port %(portid)s with failure:" "%(exception)s") LOG.debug(msg, {"portid": port["id"], "exception": ex})
def deallocate_port_for_instance(self, context, instance, port_id, conductor_api=None): """Remove a specified port from the instance. Return network information for the instance """ try: quantumv2.get_client(context).delete_port(port_id) except Exception as ex: LOG.exception(_("Failed to delete quantum port %(port_id)s ") % locals()) return self._get_instance_nw_info(context, instance)
def test_withtoken(self): self.flags(quantum_url='http://anyhost/') self.flags(quantum_url_timeout=30) my_context = context.RequestContext('userid', 'my_tenantid', auth_token='token') self.mox.StubOutWithMock(client.Client, "__init__") client.Client.__init__( endpoint_url=CONF.quantum_url, token=my_context.auth_token, timeout=CONF.quantum_url_timeout, insecure=False).AndReturn(None) self.mox.ReplayAll() quantumv2.get_client(my_context)
def setUp(self): super(TestQuantumv2, self).setUp() self.mox.StubOutWithMock(quantumv2, 'get_client') self.moxed_client = self.mox.CreateMock(client.Client) quantumv2.get_client(mox.IgnoreArg()).MultipleTimes().AndReturn( self.moxed_client) self.context = context.RequestContext('userid', 'my_tenantid') setattr(self.context, 'auth_token', 'bff4a5a6b9eb4ea2a6efec6eefb77936') self.instance = {'project_id': '9d049e4b60b64716978ab415e6fbd5c0', 'uuid': str(utils.gen_uuid()), 'display_name': 'test_instance'} self.nets1 = [{'id': 'my_netid1', 'name': 'my_netname1', 'tenant_id': 'my_tenantid'}] self.nets2 = [] self.nets2.append(self.nets1[0]) self.nets2.append({'id': 'my_netid2', 'name': 'my_netname2', 'tenant_id': 'my_tenantid'}) self.nets3 = self.nets2 + [{'id': 'my_netid3', 'name': 'my_netname3', 'tenant_id': 'my_tenantid'}] self.nets = [self.nets1, self.nets2, self.nets3] self.port_data1 = [{'network_id': 'my_netid1', 'device_id': 'device_id1', 'device_owner': 'compute:nova', 'id': 'my_portid1', 'fixed_ips': [{'ip_address': '10.0.1.2', 'subnet_id': 'my_subid1'}], 'mac_address': 'my_mac1', }] self.port_data2 = [] self.port_data2.append(self.port_data1[0]) self.port_data2.append({'network_id': 'my_netid2', 'device_id': 'device_id2', 'device_owner': 'compute:nova', 'id': 'my_portid2', 'fixed_ips': [{'ip_address': '10.0.2.2', 'subnet_id': 'my_subid2'}], 'mac_address': 'my_mac2', }) self.subnet_data1 = [{'cidr': '10.0.1.0/24', 'gateway_ip': '10.0.1.1', 'dns_nameservers': ['8.8.1.1', '8.8.1.2']}] self.subnet_data2 = [] self.subnet_data2.append({'cidr': '10.0.2.0/24', 'gateway_ip': '10.0.2.1', 'dns_nameservers': ['8.8.2.1', '8.8.2.2']})
def get_floating_ips_by_project(self, context): client = quantumv2.get_client(context) project_id = context.project_id fips = client.list_floatingips(tenant_id=project_id)["floatingips"] pool_dict = self._setup_pools_dict(client) port_dict = self._setup_ports_dict(client, project_id) return [self._format_floating_ip_model(fip, pool_dict, port_dict) for fip in fips]
def _build_network_info_model(self, context, instance, networks=None): search_opts = {"tenant_id": instance["project_id"], "device_id": instance["uuid"]} data = quantumv2.get_client(context).list_ports(**search_opts) ports = data.get("ports", []) if not networks: networks = self._get_available_networks(context, instance["project_id"]) nw_info = network_model.NetworkInfo() for port in ports: network_name = None for net in networks: if port["network_id"] == net["id"]: network_name = net["name"] break network_IPs = [ network_model.FixedIP(address=ip_address) for ip_address in [ip["ip_address"] for ip in port["fixed_ips"]] ] # TODO(gongysh) get floating_ips for each fixed_ip subnets = self._get_subnets_from_port(context, port) for subnet in subnets: subnet["ips"] = [fixed_ip for fixed_ip in network_IPs if fixed_ip.is_in_subnet(subnet)] network = network_model.Network( id=port["network_id"], bridge="", # Quantum ignores this field injected=FLAGS.flat_injected, label=network_name, tenant_id=net["tenant_id"], ) network["subnets"] = subnets nw_info.append(network_model.VIF(id=port["id"], address=port["mac_address"], network=network)) return nw_info
def get_all(self, context): """Get all networks for client.""" client = quantumv2.get_client(context) networks = client.list_networks().get('networks') or {} for network in networks: network['label'] = network['name'] return networks
def get_instance_security_groups(self, req, instance_id): dict_security_groups = {} security_group_name_map = {} admin_context = context.get_admin_context() quantum = quantumv2.get_client(admin_context) params = {'device_id': instance_id} ports = quantum.list_ports(**params) security_groups = quantum.list_security_groups().get('security_groups') for security_group in security_groups: name = security_group.get('name') # Since the name is optional for quantum security groups if not name: name = security_group['id'] security_group_name_map[security_group['id']] = name for port in ports['ports']: for security_group in port.get('security_groups', []): try: dict_security_groups[security_group] = ( security_group_name_map[security_group]) except KeyError: # If this should only happen due to a race condition # if the security group on a port was deleted after the # ports were returned. We pass since this security group # is no longer on the port. pass ret = [] for security_group in dict_security_groups.values(): ret.append({'name': security_group}) return ret
def get_instances_security_groups_bindings(self, context): """Returns a dict(instance_id, [security_groups]) to allow obtaining all of the instances and their security groups in one shot.""" quantum = quantumv2.get_client(context) ports = quantum.list_ports().get('ports') security_groups = quantum.list_security_groups().get('security_groups') security_group_lookup = {} instances_security_group_bindings = {} for security_group in security_groups: security_group_lookup[security_group['id']] = security_group for port in ports: for port_security_group in port.get('security_groups', []): try: sg = security_group_lookup[port_security_group] # name is optional in quantum so if not specified return id if sg.get('name'): sg_entry = {'name': sg['name']} else: sg_entry = {'name': sg['id']} instances_security_group_bindings.setdefault( port['device_id'], []).append(sg_entry) except KeyError: # This should only happen due to a race condition # if the security group on a port was deleted after the # ports were returned. We pass since this security # group is no longer on the port. pass return instances_security_group_bindings
def test_withouttoken_keystone_not_auth(self): # self.flags(quantum_auth_strategy=None) fail to work old_quantum_auth_strategy = FLAGS.quantum_auth_strategy setattr(FLAGS, "quantum_auth_strategy", None) self.flags(quantum_url="http://anyhost/") self.flags(quantum_url_timeout=30) my_context = context.RequestContext("userid", "my_tenantid") self.mox.StubOutWithMock(client.Client, "__init__") client.Client.__init__( endpoint_url=FLAGS.quantum_url, auth_strategy=None, timeout=FLAGS.quantum_url_timeout ).AndReturn(None) self.mox.ReplayAll() try: quantumv2.get_client(my_context) finally: setattr(FLAGS, "quantum_auth_strategy", old_quantum_auth_strategy)
def validate_networks(self, context, requested_networks): """Validate that the tenant can use the requested networks.""" LOG.debug(_('validate_networks() for %s'), requested_networks) if not requested_networks: return net_ids = [] for (net_id, _i, port_id) in requested_networks: if port_id: port = (quantumv2.get_client(context) .show_port(port_id) .get('port')) if not port: raise exception.PortNotFound(port_id=port_id) if port.get('device_id', None): raise exception.PortInUse(port_id=port_id) net_id = port['network_id'] if net_id in net_ids: continue # raise exception.NetworkDuplicated(network_id=net_id) net_ids.append(net_id) nets = self._get_available_networks(context, context.project_id, net_ids) if len(nets) != len(net_ids): requsted_netid_set = set(net_ids) returned_netid_set = set([net['id'] for net in nets]) lostid_set = requsted_netid_set - returned_netid_set id_str = '' for _id in lostid_set: id_str = id_str and id_str + ', ' + _id or _id raise exception.NetworkNotFound(network_id=id_str)
def _get_available_networks(self, context, project_id, net_ids=None): """Return a network list available for the tenant. The list contains networks owned by the tenant and public networks. If net_ids specified, it searches networks with requested IDs only. """ quantum = quantumv2.get_client(context) # If user has specified to attach instance only to specific # networks, add them to **search_opts # (1) Retrieve non-public network list owned by the tenant. search_opts = {"tenant_id": project_id, 'shared': False} if net_ids: search_opts['id'] = net_ids nets = quantum.list_networks(**search_opts).get('networks', []) # (2) Retrieve public network list. search_opts = {'shared': True} if net_ids: search_opts['id'] = net_ids nets += quantum.list_networks(**search_opts).get('networks', []) _ensure_requested_network_ordering( lambda x: x['id'], nets, net_ids) return nets
def get_floating_ip(self, context, id): client = quantumv2.get_client(context) fip = client.show_floatingip(id)['floatingip'] pool_dict = self._setup_net_dict(client, fip['floating_network_id']) port_dict = self._setup_port_dict(client, fip['port_id']) return self._format_floating_ip_model(fip, pool_dict, port_dict)
def get_instance_security_groups(self, context, instance_uuid, detailed=False): """Returns the security groups that are associated with an instance. If detailed is True then it also returns the full details of the security groups associated with an instance. """ quantum = quantumv2.get_client(context) params = {"device_id": instance_uuid} ports = quantum.list_ports(**params) security_groups = quantum.list_security_groups().get("security_groups") security_group_lookup = {} for security_group in security_groups: security_group_lookup[security_group["id"]] = security_group ret = [] for port in ports["ports"]: for security_group in port.get("security_groups", []): try: if detailed: ret.append(self._convert_to_nova_security_group_format(security_group_lookup[security_group])) else: name = security_group_lookup[security_group].get("name") # Since the name is optional for # quantum security groups if not name: name = security_group ret.append({"name": name}) except KeyError: # This should only happen due to a race condition # if the security group on a port was deleted after the # ports were returned. We pass since this security # group is no longer on the port. pass return ret
def get_floating_ip_by_address(self, context, address): client = quantumv2.get_client(context) fip = self._get_floating_ip_by_address(client, address) pool_dict = self._setup_net_dict(client, fip['floating_network_id']) port_dict = self._setup_port_dict(client, fip['port_id']) return self._format_floating_ip_model(fip, pool_dict, port_dict)
def _build_network_info_model(self, context, instance, networks=None): search_opts = {'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } data = quantumv2.get_client(context, admin=True).list_ports(**search_opts) ports = data.get('ports', []) if not networks: networks = self._get_available_networks(context, instance['project_id']) else: # ensure ports are in preferred network order _ensure_requested_network_ordering( lambda x: x['network_id'], ports, [n['id'] for n in networks]) nw_info = network_model.NetworkInfo() for port in ports: network_name = None for net in networks: if port['network_id'] == net['id']: network_name = net['name'] break network_IPs = [network_model.FixedIP(address=ip_address) for ip_address in [ip['ip_address'] for ip in port['fixed_ips']]] # TODO(gongysh) get floating_ips for each fixed_ip subnets = self._get_subnets_from_port(context, port) for subnet in subnets: subnet['ips'] = [fixed_ip for fixed_ip in network_IPs if fixed_ip.is_in_subnet(subnet)] bridge = None vif_type = port.get('binding:vif_type') # TODO(berrange) Quantum should pass the bridge name # in another binding metadata field if vif_type == network_model.VIF_TYPE_OVS: bridge = CONF.quantum_ovs_bridge elif vif_type == network_model.VIF_TYPE_BRIDGE: bridge = "brq" + port['network_id'] if bridge is not None: bridge = bridge[:network_model.BRIDGE_NAME_LEN] network = network_model.Network( id=port['network_id'], bridge=bridge, injected=CONF.flat_injected, label=network_name, tenant_id=net['tenant_id'] ) network['subnets'] = subnets nw_info.append(network_model.VIF( id=port['id'], address=port['mac_address'], network=network, type=port.get('binding:vif_type'))) return nw_info
def add_rules(self, context, id, name, vals): """Add security group rule(s) to security group. Note: the Nova security group API doesn't support adding muliple security group rules at once but the EC2 one does. Therefore, this function is writen to support both. Multiple rules are installed to a security group in quantum using bulk support.""" quantum = quantumv2.get_client(context) body = self._make_quantum_security_group_rules_list(vals) try: rules = quantum.create_security_group_rule( body).get('security_group_rules') except q_exc.QuantumClientException as e: if e.status_code == 409: LOG.exception(_("Quantum Error getting security group %s"), name) self.raise_not_found(e.message) else: LOG.exception(_("Quantum Error:")) raise e converted_rules = [] for rule in rules: converted_rules.append( self._convert_to_nova_security_group_rule_format(rule)) return converted_rules
def release_floating_ip(self, context, address, affect_auto_assigned=False): """Remove a floating ip with the given address from a project.""" # Note(amotoki): We cannot handle a case where multiple pools # have overlapping IP address range. In this case we cannot use # 'address' as a unique key. # This is a limitation of the current nova. # Note(amotoki): 'affect_auto_assigned' is not respected # since it is not used anywhere in nova code and I could # find why this parameter exists. client = quantumv2.get_client(context) fip = self._get_floating_ip_by_address(client, address) if fip['port_id']: raise exception.FloatingIpAssociated(address=address) client.delete_floatingip(fip['id'])
def _get_available_networks(self, context, project_id, net_ids=None): """Return a network list available for the tenant. The list contains networks owned by the tenant and public networks. If net_ids specified, it searches networks with requested IDs only. """ quantum = quantumv2.get_client(context) # If user has specified to attach instance only to specific # networks, add them to **search_opts # (1) Retrieve non-public network list owned by the tenant. search_opts = {"tenant_id": project_id, 'shared': False} if net_ids: search_opts['id'] = net_ids nets = quantum.list_networks(**search_opts).get('networks', []) # (2) Retrieve public network list. search_opts = {'shared': True} if net_ids: search_opts['id'] = net_ids nets += quantum.list_networks(**search_opts).get('networks', []) return nets
def list(self, context, names=None, ids=None, project=None, search_opts=None): """Returns list of security group rules owned by tenant.""" quantum = quantumv2.get_client(context) search_opts = {} if names: search_opts['name'] = names if ids: search_opts['id'] = ids if project: search_opts['tenant_id'] = project try: security_groups = quantum.list_security_groups(**search_opts).get( 'security_groups') except q_exc.QuantumClientException: with excutils.save_and_reraise_exception(): LOG.exception(_("Quantum Error getting security groups")) converted_rules = [] for security_group in security_groups: converted_rules.append( self._convert_to_nova_security_group_format(security_group)) return converted_rules
def _build_network_info_model(self, context, instance, networks=None): search_opts = {'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } data = quantumv2.get_client(context).list_ports(**search_opts) ports = data.get('ports', []) if not networks: networks = self._get_available_networks(context, instance['project_id']) nw_info = network_model.NetworkInfo() for port in ports: network_name = None for net in networks: if port['network_id'] == net['id']: network_name = net['name'] break network_IPs = [network_model.FixedIP(address=ip_address) for ip_address in [ip['ip_address'] for ip in port['fixed_ips']]] # TODO(gongysh) get floating_ips for each fixed_ip subnets = self._get_subnets_from_port(context, port) for subnet in subnets: subnet['ips'] = [fixed_ip for fixed_ip in network_IPs if fixed_ip.is_in_subnet(subnet)] network = network_model.Network( id=port['network_id'], bridge='', # Quantum ignores this field injected=FLAGS.flat_injected, label=network_name, tenant_id=net['tenant_id'] ) network['subnets'] = subnets nw_info.append(network_model.VIF( id=port['id'], address=port['mac_address'], network=network)) return nw_info
def _build_network_info_model(self, context, instance, networks=None): search_opts = { 'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } client = quantumv2.get_client(context, admin=True) data = client.list_ports(**search_opts) ports = data.get('ports', []) if networks is None: networks = self._get_available_networks(context, instance['project_id']) # ensure ports are in preferred network order, and filter out # those not attached to one of the provided list of networks net_ids = [n['id'] for n in networks] ports = [port for port in ports if port['network_id'] in net_ids] _ensure_requested_network_ordering(lambda x: x['network_id'], ports, net_ids) nw_info = network_model.NetworkInfo() for port in ports: network_IPs = self._nw_info_get_ips(client, port) subnets = self._nw_info_get_subnets(context, port, network_IPs) devname = "tap" + port['id'] devname = devname[:network_model.NIC_NAME_LEN] network, ovs_interfaceid = self._nw_info_build_network( port, networks, subnets) nw_info.append( network_model.VIF(id=port['id'], address=port['mac_address'], network=network, type=port.get('binding:vif_type'), ovs_interfaceid=ovs_interfaceid, devname=devname)) return nw_info
def get_instance_security_groups(self, context, instance_uuid, detailed=False): """Returns the security groups that are associated with an instance. If detailed is True then it also returns the full details of the security groups associated with an instance. """ quantum = quantumv2.get_client(context) params = {'device_id': instance_uuid} ports = quantum.list_ports(**params) security_groups = quantum.list_security_groups().get('security_groups') security_group_lookup = {} for security_group in security_groups: security_group_lookup[security_group['id']] = security_group ret = [] for port in ports['ports']: for security_group in port.get('security_groups', []): try: if detailed: ret.append(self._convert_to_nova_security_group_format( security_group_lookup[security_group])) else: name = security_group_lookup[security_group].get( 'name') # Since the name is optional for # quantum security groups if not name: name = security_group ret.append({'name': name}) except KeyError: # This should only happen due to a race condition # if the security group on a port was deleted after the # ports were returned. We pass since this security # group is no longer on the port. pass return ret
def _get_available_networks(self, context, project_id, net_ids=None): """Return only specified networks if provided. Standard implementation uses public nets if empty list provided, this is not desirable behavior.""" if net_ids is None: return super(QuantumUdpApi, self)._get_available_networks(context, project_id) elif not net_ids: return [] # If user has specified to attach instance only to specific # networks, add them to **search_opts quantum = quantumv2.get_client(context) search_opts = {"tenant_id": project_id, 'shared': False, 'id': net_ids} nets = quantum.list_networks(**search_opts).get('networks', []) found_nets = map(lambda x: x['id'], nets) if len(nets) != len(found_nets): set(net_ids).difference(found_nets) raise exception.NetworkNotFound(network_id=found_nets) _ensure_requested_network_ordering(lambda x: x['id'], nets, net_ids) LOG.debug("Nets for instance: %s" % nets) return nets
def get(self, context, network_uuid): client = quantumv2.get_client(context) return client.show_network(network_uuid)
def setUp(self): super(TestQuantumv2, self).setUp() self.mox.StubOutWithMock(quantumv2, 'get_client') self.moxed_client = self.mox.CreateMock(client.Client) quantumv2.get_client(mox.IgnoreArg()).MultipleTimes().AndReturn( self.moxed_client) self.context = context.RequestContext('userid', 'my_tenantid') setattr(self.context, 'auth_token', 'bff4a5a6b9eb4ea2a6efec6eefb77936') self.instance = { 'project_id': '9d049e4b60b64716978ab415e6fbd5c0', 'uuid': str(utils.gen_uuid()), 'display_name': 'test_instance', 'security_groups': [] } self.nets1 = [{ 'id': 'my_netid1', 'name': 'my_netname1', 'tenant_id': 'my_tenantid' }] self.nets2 = [] self.nets2.append(self.nets1[0]) self.nets2.append({ 'id': 'my_netid2', 'name': 'my_netname2', 'tenant_id': 'my_tenantid' }) self.nets3 = self.nets2 + [{ 'id': 'my_netid3', 'name': 'my_netname3', 'tenant_id': 'my_tenantid' }] self.nets4 = [{ 'id': 'his_netid4', 'name': 'his_netname4', 'tenant_id': 'his_tenantid' }] self.nets = [self.nets1, self.nets2, self.nets3, self.nets4] self.port_address = '10.0.1.2' self.port_data1 = [{ 'network_id': 'my_netid1', 'device_id': 'device_id1', 'device_owner': 'compute:nova', 'id': 'my_portid1', 'fixed_ips': [{ 'ip_address': self.port_address, 'subnet_id': 'my_subid1' }], 'mac_address': 'my_mac1', }] self.dhcp_port_data1 = [{ 'fixed_ips': [{ 'ip_address': '10.0.1.9', 'subnet_id': 'my_subid1' }] }] self.port_data2 = [] self.port_data2.append(self.port_data1[0]) self.port_data2.append({ 'network_id': 'my_netid2', 'device_id': 'device_id2', 'device_owner': 'compute:nova', 'id': 'my_portid2', 'fixed_ips': [{ 'ip_address': '10.0.2.2', 'subnet_id': 'my_subid2' }], 'mac_address': 'my_mac2', }) self.port_data3 = [{ 'network_id': 'my_netid1', 'device_id': 'device_id3', 'device_owner': 'compute:nova', 'id': 'my_portid3', 'fixed_ips': [], # no fixed ip 'mac_address': 'my_mac3', }] self.subnet_data1 = [{ 'id': 'my_subid1', 'cidr': '10.0.1.0/24', 'network_id': 'my_netid1', 'gateway_ip': '10.0.1.1', 'dns_nameservers': ['8.8.1.1', '8.8.1.2'] }] self.subnet_data2 = [] self.subnet_data2.append({ 'id': 'my_subid2', 'cidr': '10.0.2.0/24', 'network_id': 'my_netid2', 'gateway_ip': '10.0.2.1', 'dns_nameservers': ['8.8.2.1', '8.8.2.2'] })
def get_all(self, context): client = quantumv2.get_client(context) return client.list_networks()
def _build_network_info_model(self, context, instance, networks=None): search_opts = { 'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } client = quantumv2.get_client(context, admin=True) data = client.list_ports(**search_opts) ports = data.get('ports', []) if networks is None: networks = self._get_available_networks(context, instance['project_id']) # ensure ports are in preferred network order, and filter out # those not attached to one of the provided list of networks net_ids = [n['id'] for n in networks] ports = [port for port in ports if port['network_id'] in net_ids] _ensure_requested_network_ordering(lambda x: x['network_id'], ports, net_ids) nw_info = network_model.NetworkInfo() for port in ports: # NOTE(danms): This loop can't fail to find a network since we # filtered ports to only the ones matching networks above. for net in networks: if port['network_id'] == net['id']: network_name = net['name'] break network_IPs = [] for fixed_ip in port['fixed_ips']: fixed = network_model.FixedIP(address=fixed_ip['ip_address']) floats = self._get_floating_ips_by_fixed_and_port( client, fixed_ip['ip_address'], port['id']) for ip in floats: fip = network_model.IP(address=ip['floating_ip_address'], type='floating') fixed.add_floating_ip(fip) network_IPs.append(fixed) subnets = self._get_subnets_from_port(context, port) for subnet in subnets: subnet['ips'] = [ fixed_ip for fixed_ip in network_IPs if fixed_ip.is_in_subnet(subnet) ] bridge = None ovs_interfaceid = None # Network model metadata should_create_bridge = None vif_type = port.get('binding:vif_type') # TODO(berrange) Quantum should pass the bridge name # in another binding metadata field if vif_type == network_model.VIF_TYPE_OVS: bridge = CONF.quantum_ovs_bridge ovs_interfaceid = port['id'] elif vif_type == network_model.VIF_TYPE_BRIDGE: bridge = "brq" + port['network_id'] should_create_bridge = True if bridge is not None: bridge = bridge[:network_model.NIC_NAME_LEN] devname = "tap" + port['id'] devname = devname[:network_model.NIC_NAME_LEN] network = network_model.Network(id=port['network_id'], bridge=bridge, injected=CONF.flat_injected, label=network_name, tenant_id=net['tenant_id']) network['subnets'] = subnets if should_create_bridge is not None: network['should_create_bridge'] = should_create_bridge nw_info.append( network_model.VIF(id=port['id'], address=port['mac_address'], network=network, type=port.get('binding:vif_type'), ovs_interfaceid=ovs_interfaceid, devname=devname)) return nw_info
def allocate_for_instance(self, context, instance, **kwargs): """Allocate all network resources for the instance. TODO(someone): document the rest of these parameters. :param macs: None or a set of MAC addresses that the instance should use. macs is supplied by the hypervisor driver (contrast with requested_networks which is user supplied). NB: QuantumV2 currently assigns hypervisor supplied MAC addresses to arbitrary networks, which requires openflow switches to function correctly if more than one network is being used with the bare metal hypervisor (which is the only one known to limit MAC addresses). """ hypervisor_macs = kwargs.get('macs', None) available_macs = None if hypervisor_macs is not None: # Make a copy we can mutate: records macs that have not been used # to create a port on a network. If we find a mac with a # pre-allocated port we also remove it from this set. available_macs = set(hypervisor_macs) quantum = quantumv2.get_client(context) LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) if not instance['project_id']: msg = _('empty project id for instance %s') raise exception.InvalidInput(reason=msg % instance['display_name']) requested_networks = kwargs.get('requested_networks') ports = {} fixed_ips = {} net_ids = [] if requested_networks: for network_id, fixed_ip, port_id in requested_networks: if port_id: port = quantum.show_port(port_id)['port'] if hypervisor_macs is not None: if port['mac_address'] not in hypervisor_macs: raise exception.PortNotUsable( port_id=port_id, instance=instance['display_name']) else: # Don't try to use this MAC if we need to create a # port on the fly later. Identical MACs may be # configured by users into multiple ports so we # discard rather than popping. available_macs.discard(port['mac_address']) network_id = port['network_id'] ports[network_id] = port elif fixed_ip: fixed_ips[network_id] = fixed_ip net_ids.append(network_id) nets = self._get_available_networks(context, instance['project_id'], net_ids) touched_port_ids = [] created_port_ids = [] for network in nets: network_id = network['id'] zone = 'compute:%s' % instance['availability_zone'] port_req_body = { 'port': { 'device_id': instance['uuid'], 'device_owner': zone } } try: port = ports.get(network_id) if port: quantum.update_port(port['id'], port_req_body) touched_port_ids.append(port['id']) else: if fixed_ips.get(network_id): port_req_body['port']['fixed_ips'] = [{ 'ip_address': fixed_ip }] port_req_body['port']['network_id'] = network_id port_req_body['port']['admin_state_up'] = True port_req_body['port']['tenant_id'] = instance['project_id'] if available_macs is not None: if not available_macs: raise exception.PortNotFree( instance=instance['display_name']) mac_address = available_macs.pop() port_req_body['port']['mac_address'] = mac_address created_port_ids.append( quantum.create_port(port_req_body)['port']['id']) except Exception: with excutils.save_and_reraise_exception(): for port_id in touched_port_ids: port_in_server = quantum.show_port(port_id).get('port') if not port_in_server: raise Exception(_('Port not found')) port_req_body = {'port': {'device_id': None}} quantum.update_port(port_id, port_req_body) for port_id in created_port_ids: try: quantum.delete_port(port_id) except Exception as ex: msg = _("Fail to delete port %(portid)s with" " failure: %(exception)s") LOG.debug(msg, { 'portid': port_id, 'exception': ex }) self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_add_security_group_refresh(context, instance) return self.get_instance_nw_info(context, instance, networks=nets)
def show_port(self, context, port_id): """Return the port for the client given the port id.""" return quantumv2.get_client(context).show_port(port_id)
def test_get_instance_nw_info_1(self): # Test to get one port in one network and subnet. quantumv2.get_client(mox.IgnoreArg(), admin=True).MultipleTimes().AndReturn( self.moxed_client) self._get_instance_nw_info(1)
def list_ports(self, context, **search_opts): return quantumv2.get_client(context).list_ports(**search_opts)
def test_get_instance_nw_info_2(self): """Test to get one port in each of two networks and subnets.""" quantumv2.get_client(mox.IgnoreArg(), admin=True).MultipleTimes().AndReturn( self.moxed_client) self._get_instance_nw_info(2)
def get_all(self, context): client = quantumv2.get_client(context) networks = client.list_networks().get('networks') or {} for network in networks: network['label'] = network['name'] return networks
def show_port(self, context, port_id): return quantumv2.get_client(context).show_port(port_id)
def _build_network_info_model(self, context, instance, networks=None): search_opts = { 'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } data = quantumv2.get_client(context, admin=True).list_ports(**search_opts) ports = data.get('ports', []) if networks is None: networks = self._get_available_networks(context, instance['project_id']) else: # ensure ports are in preferred network order _ensure_requested_network_ordering(lambda x: x['network_id'], ports, [n['id'] for n in networks]) nw_info = network_model.NetworkInfo() for port in ports: network_name = None for net in networks: if port['network_id'] == net['id']: network_name = net['name'] break if network_name is None: raise exception.NotFound( _('Network %(net)s for ' 'port %(port_id)s not found!') % { 'net': port['network_id'], 'port': port['id'] }) network_IPs = [ network_model.FixedIP(address=ip_address) for ip_address in [ip['ip_address'] for ip in port['fixed_ips']] ] # TODO(gongysh) get floating_ips for each fixed_ip subnets = self._get_subnets_from_port(context, port) for subnet in subnets: subnet['ips'] = [ fixed_ip for fixed_ip in network_IPs if fixed_ip.is_in_subnet(subnet) ] bridge = None ovs_interfaceid = None # Network model metadata should_create_bridge = None vif_type = port.get('binding:vif_type') # TODO(berrange) Quantum should pass the bridge name # in another binding metadata field if vif_type == network_model.VIF_TYPE_OVS: bridge = CONF.quantum_ovs_bridge ovs_interfaceid = port['id'] elif vif_type == network_model.VIF_TYPE_BRIDGE: bridge = "brq" + port['network_id'] should_create_bridge = True if bridge is not None: bridge = bridge[:network_model.NIC_NAME_LEN] devname = "tap" + port['id'] devname = devname[:network_model.NIC_NAME_LEN] network = network_model.Network(id=port['network_id'], bridge=bridge, injected=CONF.flat_injected, label=network_name, tenant_id=net['tenant_id']) network['subnets'] = subnets if should_create_bridge is not None: network['should_create_bridge'] = should_create_bridge nw_info.append( network_model.VIF(id=port['id'], address=port['mac_address'], network=network, type=port.get('binding:vif_type'), ovs_interfaceid=ovs_interfaceid, devname=devname)) return nw_info
def list_ports(self, context, **search_opts): """List ports for the client based on search options.""" return quantumv2.get_client(context).list_ports(**search_opts)
def setUp(self): super(TestQuantumv2, self).setUp() self.mox.StubOutWithMock(quantumv2, 'get_client') self.moxed_client = self.mox.CreateMock(client.Client) quantumv2.get_client(mox.IgnoreArg()).MultipleTimes().AndReturn( self.moxed_client) self.context = context.RequestContext('userid', 'my_tenantid') setattr(self.context, 'auth_token', 'bff4a5a6b9eb4ea2a6efec6eefb77936') self.instance = { 'project_id': '9d049e4b60b64716978ab415e6fbd5c0', 'uuid': str(uuid.uuid4()), 'display_name': 'test_instance', 'security_groups': [] } self.nets1 = [{ 'id': 'my_netid1', 'name': 'my_netname1', 'tenant_id': 'my_tenantid' }] self.nets2 = [] self.nets2.append(self.nets1[0]) self.nets2.append({ 'id': 'my_netid2', 'name': 'my_netname2', 'tenant_id': 'my_tenantid' }) self.nets3 = self.nets2 + [{ 'id': 'my_netid3', 'name': 'my_netname3', 'tenant_id': 'my_tenantid' }] self.nets4 = [{ 'id': 'his_netid4', 'name': 'his_netname4', 'tenant_id': 'his_tenantid' }] self.nets = [self.nets1, self.nets2, self.nets3, self.nets4] self.port_address = '10.0.1.2' self.port_data1 = [{ 'network_id': 'my_netid1', 'device_id': 'device_id1', 'device_owner': 'compute:nova', 'id': 'my_portid1', 'fixed_ips': [{ 'ip_address': self.port_address, 'subnet_id': 'my_subid1' }], 'mac_address': 'my_mac1', }] self.dhcp_port_data1 = [{ 'fixed_ips': [{ 'ip_address': '10.0.1.9', 'subnet_id': 'my_subid1' }] }] self.port_data2 = [] self.port_data2.append(self.port_data1[0]) self.port_data2.append({ 'network_id': 'my_netid2', 'device_id': 'device_id2', 'device_owner': 'compute:nova', 'id': 'my_portid2', 'fixed_ips': [{ 'ip_address': '10.0.2.2', 'subnet_id': 'my_subid2' }], 'mac_address': 'my_mac2', }) self.port_data3 = [{ 'network_id': 'my_netid1', 'device_id': 'device_id3', 'device_owner': 'compute:nova', 'id': 'my_portid3', 'fixed_ips': [], # no fixed ip 'mac_address': 'my_mac3', }] self.subnet_data1 = [{ 'id': 'my_subid1', 'cidr': '10.0.1.0/24', 'network_id': 'my_netid1', 'gateway_ip': '10.0.1.1', 'dns_nameservers': ['8.8.1.1', '8.8.1.2'] }] self.subnet_data2 = [] self.subnet_data2.append({ 'id': 'my_subid2', 'cidr': '10.0.2.0/24', 'network_id': 'my_netid2', 'gateway_ip': '10.0.2.1', 'dns_nameservers': ['8.8.2.1', '8.8.2.2'] }) self.fip_pool = { 'id': '4fdbfd74-eaf8-4884-90d9-00bd6f10c2d3', 'name': 'ext_net', 'router:external': True, 'tenant_id': 'admin_tenantid' } self.fip_pool_nova = { 'id': '435e20c3-d9f1-4f1b-bee5-4611a1dd07db', 'name': 'nova', 'router:external': True, 'tenant_id': 'admin_tenantid' } self.fip_unassociated = { 'tenant_id': 'my_tenantid', 'id': 'fip_id1', 'floating_ip_address': '172.24.4.227', 'floating_network_id': self.fip_pool['id'], 'port_id': None, 'fixed_ip_address': None, 'router_id': None } fixed_ip_address = self.port_data2[1]['fixed_ips'][0]['ip_address'] self.fip_associated = { 'tenant_id': 'my_tenantid', 'id': 'fip_id2', 'floating_ip_address': '172.24.4.228', 'floating_network_id': self.fip_pool['id'], 'port_id': self.port_data2[1]['id'], 'fixed_ip_address': fixed_ip_address, 'router_id': 'router_id1' }
def get_floating_ip_pools(self, context): client = quantumv2.get_client(context) pools = self._get_floating_ip_pools(client) return [{'name': n['name'] or n['id']} for n in pools]
def get(self, context, network_uuid): """Get specific network for client.""" client = quantumv2.get_client(context) network = client.show_network(network_uuid).get('network') or {} network['label'] = network['name'] return network
def allocate_for_instance(self, context, instance, **kwargs): """Allocate all network resources for the instance.""" quantum = quantumv2.get_client(context) LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) if not instance['project_id']: msg = _('empty project id for instance %s') raise exception.InvalidInput(reason=msg % instance['display_name']) requested_networks = kwargs.get('requested_networks') ports = {} fixed_ips = {} net_ids = [] if requested_networks: for network_id, fixed_ip, port_id in requested_networks: if port_id: port = quantum.show_port(port_id).get('port') network_id = port['network_id'] ports[network_id] = port elif fixed_ip: fixed_ips[network_id] = fixed_ip net_ids.append(network_id) nets = self._get_available_networks(context, instance['project_id'], net_ids) touched_port_ids = [] created_port_ids = [] for network in nets: network_id = network['id'] zone = 'compute:%s' % CONF.node_availability_zone port_req_body = { 'port': { 'device_id': instance['uuid'], 'device_owner': zone } } try: port = ports.get(network_id) if port: quantum.update_port(port['id'], port_req_body) touched_port_ids.append(port['id']) else: if fixed_ips.get(network_id): port_req_body['port']['fixed_ip'] = fixed_ip port_req_body['port']['network_id'] = network_id port_req_body['port']['admin_state_up'] = True port_req_body['port']['tenant_id'] = instance['project_id'] created_port_ids.append( quantum.create_port(port_req_body)['port']['id']) except Exception: with excutils.save_and_reraise_exception(): for port_id in touched_port_ids: port_in_server = quantum.show_port(port_id).get('port') if not port_in_server: raise Exception(_('Port not found')) port_req_body = {'port': {'device_id': None}} quantum.update_port(port_id, port_req_body) for port_id in created_port_ids: try: quantum.delete_port(port_id) except Exception as ex: msg = _("Fail to delete port %(portid)s with" " failure: %(exception)s") LOG.debug(msg, { 'portid': port_id, 'exception': ex }) self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_add_security_group_refresh(context, instance) return self.get_instance_nw_info(context, instance, networks=nets)
def allocate_for_instance(self, context, instance, **kwargs): """Allocate network resources for the instance. :param requested_networks: optional value containing network_id, fixed_ip, and port_id :param security_groups: security groups to allocate for instance :param macs: None or a set of MAC addresses that the instance should use. macs is supplied by the hypervisor driver (contrast with requested_networks which is user supplied). NB: QuantumV2 currently assigns hypervisor supplied MAC addresses to arbitrary networks, which requires openflow switches to function correctly if more than one network is being used with the bare metal hypervisor (which is the only one known to limit MAC addresses). """ hypervisor_macs = kwargs.get('macs', None) available_macs = None if hypervisor_macs is not None: # Make a copy we can mutate: records macs that have not been used # to create a port on a network. If we find a mac with a # pre-allocated port we also remove it from this set. available_macs = set(hypervisor_macs) quantum = quantumv2.get_client(context) LOG.debug(_('allocate_for_instance() for %s'), instance['display_name']) if not instance['project_id']: msg = _('empty project id for instance %s') raise exception.InvalidInput(reason=msg % instance['display_name']) requested_networks = kwargs.get('requested_networks') ports = {} fixed_ips = {} net_ids = [] if requested_networks: for network_id, fixed_ip, port_id in requested_networks: if port_id: port = quantum.show_port(port_id)['port'] if hypervisor_macs is not None: if port['mac_address'] not in hypervisor_macs: raise exception.PortNotUsable( port_id=port_id, instance=instance['display_name']) else: # Don't try to use this MAC if we need to create a # port on the fly later. Identical MACs may be # configured by users into multiple ports so we # discard rather than popping. available_macs.discard(port['mac_address']) network_id = port['network_id'] ports[network_id] = port elif fixed_ip and network_id: fixed_ips[network_id] = fixed_ip if network_id: net_ids.append(network_id) nets = self._get_available_networks(context, instance['project_id'], net_ids) security_groups = kwargs.get('security_groups', []) security_group_ids = [] # TODO(arosen) Should optimize more to do direct query for security # group if len(security_groups) == 1 if len(security_groups): search_opts = {'tenant_id': instance['project_id']} user_security_groups = quantum.list_security_groups( **search_opts).get('security_groups') for security_group in security_groups: name_match = None uuid_match = None for user_security_group in user_security_groups: if user_security_group['name'] == security_group: if name_match: msg = (_("Multiple security groups found matching" " '%s'. Use an ID to be more specific."), security_group) raise exception.NoUniqueMatch(msg) name_match = user_security_group['id'] if user_security_group['id'] == security_group: uuid_match = user_security_group['id'] # If a user names the security group the same as # another's security groups uuid, the name takes priority. if not name_match and not uuid_match: raise exception.SecurityGroupNotFound( security_group_id=security_group) security_group_ids.append(name_match) elif name_match: security_group_ids.append(name_match) elif uuid_match: security_group_ids.append(uuid_match) touched_port_ids = [] created_port_ids = [] for network in nets: # If security groups are requested on an instance then the # network must has a subnet associated with it. Some plugins # implement the port-security extension which requires # 'port_security_enabled' to be True for security groups. # That is why True is returned if 'port_security_enabled' # is not found. if (security_groups and not (network['subnets'] and network.get('port_security_enabled', True))): raise exception.SecurityGroupCannotBeApplied() network_id = network['id'] zone = 'compute:%s' % instance['availability_zone'] port_req_body = { 'port': { 'device_id': instance['uuid'], 'device_owner': zone } } try: port = ports.get(network_id) if port: quantum.update_port(port['id'], port_req_body) touched_port_ids.append(port['id']) else: fixed_ip = fixed_ips.get(network_id) if fixed_ip: port_req_body['port']['fixed_ips'] = [{ 'ip_address': fixed_ip }] port_req_body['port']['network_id'] = network_id port_req_body['port']['admin_state_up'] = True port_req_body['port']['tenant_id'] = instance['project_id'] if security_group_ids: port_req_body['port']['security_groups'] = ( security_group_ids) if available_macs is not None: if not available_macs: raise exception.PortNotFree( instance=instance['display_name']) mac_address = available_macs.pop() port_req_body['port']['mac_address'] = mac_address self._populate_quantum_extension_values( instance, port_req_body) created_port_ids.append( quantum.create_port(port_req_body)['port']['id']) except Exception: with excutils.save_and_reraise_exception(): for port_id in touched_port_ids: port_in_server = quantum.show_port(port_id).get('port') if not port_in_server: raise Exception(_('Port not found')) port_req_body = {'port': {'device_id': None}} quantum.update_port(port_id, port_req_body) for port_id in created_port_ids: try: quantum.delete_port(port_id) except Exception as ex: msg = _("Fail to delete port %(portid)s with" " failure: %(exception)s") LOG.debug(msg, { 'portid': port_id, 'exception': ex }) nw_info = self._get_instance_nw_info(context, instance, networks=nets) # NOTE(danms): Only return info about ports we created in this run. # In the initial allocation case, this will be everything we created, # and in later runs will only be what was created that time. Thus, # this only affects the attach case, not the original use for this # method. return network_model.NetworkInfo([ port for port in nw_info if port['id'] in created_port_ids + touched_port_ids ])