def _plug_amphora_vip(self, amphora, subnet): # We need a vip port owned by Octavia for Act/Stby and failover try: port = { 'port': { 'name': 'octavia-lb-vrrp-' + amphora.id, 'network_id': subnet.network_id, 'fixed_ips': [{ 'subnet_id': subnet.id }], 'admin_state_up': True, 'device_owner': OCTAVIA_OWNER } } new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) LOG.debug('Created vip port: %(port_id)s for amphora: %(amp)s', { 'port_id': new_port.id, 'amp': amphora.id }) interface = self.plug_port(amphora, new_port) except Exception: message = _('Error plugging amphora (compute_id: {compute_id}) ' 'into vip network {network_id}.').format( compute_id=amphora.compute_id, network_id=subnet.network_id) LOG.exception(message) raise base.PlugVIPException(message) return interface
def allocate_vip(self, load_balancer): if not load_balancer.vip.port_id and not load_balancer.vip.subnet_id: raise base.AllocateVIPException('Cannot allocate a vip ' 'without a port_id or ' 'a subnet_id.') if load_balancer.vip.port_id: LOG.info(_LI('Port %s already exists. Nothing to be done.'), load_balancer.vip.port_id) port = self.get_port(load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) # Must retrieve the network_id from the subnet subnet = self.get_subnet(load_balancer.vip.subnet_id) # It can be assumed that network_id exists port = {'port': {'name': 'octavia-lb-' + load_balancer.id, 'network_id': subnet.network_id, 'admin_state_up': False, 'device_id': 'lb-{0}'.format(load_balancer.id), 'device_owner': OCTAVIA_OWNER}} try: new_port = self.neutron_client.create_port(port) except Exception: message = _LE('Error creating neutron port on network ' '{network_id}.').format( network_id=subnet.network_id) LOG.exception(message) raise base.AllocateVIPException(message) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def create_port(self, network_id, subnet_id=None, fixed_ip=None): new_port = None if not subnet_id: subnet_id = self.get_network(network_id).subnets[0] try: port = { 'port': { 'name': 'octavia-port-' + network_id, 'network_id': network_id, 'admin_state_up': True, 'device_owner': OCTAVIA_OWNER, 'fixed_ips': [{ 'subnet_id': subnet_id }] } } if fixed_ip: port['port']['fixed_ips'][0]['ip_address'] = fixed_ip new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) except Exception: message = "Error creating port in network: {0}".format(network_id) LOG.exception(message) raise exceptions.PortCreationFailedException(message) return new_port
def allocate_vip(self, load_balancer): if load_balancer.vip.port_id: LOG.info('Port %s already exists. Nothing to be done.', load_balancer.vip.port_id) port = self.get_port(load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) # It can be assumed that network_id exists port = { 'port': { 'name': 'octavia-lb-' + load_balancer.id, 'network_id': load_balancer.vip.network_id, 'admin_state_up': False, 'device_id': 'lb-{0}'.format(load_balancer.id), 'device_owner': OCTAVIA_OWNER } } try: new_port = self.neutron_client.create_port(port) except Exception: message = _('Error creating neutron port on network ' '{network_id}.').format( network_id=load_balancer.vip.network_id) LOG.exception(message) raise base.AllocateVIPException(message) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def reserve_subnet_addresses(self, subnet_id, addr_list, amphorae): subnet = self.get_subnet(subnet_id) try: port = { 'port': { 'name': 'octavia-port-' + subnet.network_id, 'network_id': subnet.network_id, 'admin_state_up': True, 'device_owner': a10constants.OCTAVIA_OWNER, 'fixed_ips': [] } } for addr in addr_list: fixed_ip = {'subnet_id': subnet_id, 'ip_address': addr} port['port']['fixed_ips'].append(fixed_ip) new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) if amphorae is not None: for amphora in filter( lambda amp: amp.status == constants.AMPHORA_ALLOCATED, amphorae): interface = self._get_plugged_interface( amphora.compute_id, subnet.network_id, amphora.lb_network_ip) self._add_allowed_address_pair_to_port( interface.port_id, addr_list) except Exception as e: LOG.exception(str(e)) raise e return new_port
def allocate_vip(self, load_balancer): if not load_balancer.vip.port_id and not load_balancer.vip.subnet_id: raise base.AllocateVIPException('Cannot allocate a vip ' 'without a port_id or ' 'a subnet_id.') if load_balancer.vip.port_id: LOG.info(_LI('Port %s already exists. Nothing to be done.'), load_balancer.vip.port_id) port = self.get_port(load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) # Must retrieve the network_id from the subnet subnet = self.get_subnet(load_balancer.vip.subnet_id) # It can be assumed that network_id exists port = { 'port': { 'name': 'octavia-lb-' + load_balancer.id, 'network_id': subnet.network_id, 'admin_state_up': False, 'device_id': 'lb-{0}'.format(load_balancer.id), 'device_owner': OCTAVIA_OWNER } } try: new_port = self.neutron_client.create_port(port) except Exception: message = _LE('Error creating neutron port on network ' '{network_id}.').format(network_id=subnet.network_id) LOG.exception(message) raise base.AllocateVIPException(message) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def test__port_to_vip(self): lb = dmh.generate_load_balancer_tree() lb.vip.subnet_id = t_constants.MOCK_SUBNET_ID port = utils.convert_port_dict_to_model(t_constants.MOCK_NEUTRON_PORT) vip = self.driver._port_to_vip(port, lb) self.assertIsInstance(vip, data_models.Vip) self.assertEqual(t_constants.MOCK_IP_ADDRESS, vip.ip_address) self.assertEqual(t_constants.MOCK_SUBNET_ID, vip.subnet_id) self.assertEqual(t_constants.MOCK_PORT_ID, vip.port_id) self.assertEqual(lb.id, vip.load_balancer_id)
def test__port_to_vip(self): lb = dmh.generate_load_balancer_tree() lb.vip.subnet_id = n_constants.MOCK_SUBNET_ID port = utils.convert_port_dict_to_model(n_constants.MOCK_NEUTRON_PORT) vip = self.driver._port_to_vip(port, lb) self.assertIsInstance(vip, data_models.Vip) self.assertEqual(n_constants.MOCK_IP_ADDRESS, vip.ip_address) self.assertEqual(n_constants.MOCK_SUBNET_ID, vip.subnet_id) self.assertEqual(n_constants.MOCK_PORT_ID, vip.port_id) self.assertEqual(lb.id, vip.load_balancer_id)
def create_port(self, network_id, name=None, fixed_ips=(), secondary_ips=(), security_group_ids=(), admin_state_up=True, qos_policy_id=None): """Creates a network port. fixed_ips = [{'subnet_id': <id>, ('ip_addrss': <IP>')},] ip_address is optional in the fixed_ips dictionary. :param network_id: The network the port should be created on. :param name: The name to apply to the port. :param fixed_ips: A list of fixed IP dicts. :param secondary_ips: A list of secondary IPs to add to the port. :param security_group_ids: A list of security group IDs for the port. :param qos_policy_id: The QoS policy ID to apply to the port. :returns port: A port data model object. """ try: aap_list = [] for ip in secondary_ips: aap_list.append({constants.IP_ADDRESS: ip}) port = { constants.NETWORK_ID: network_id, constants.ADMIN_STATE_UP: admin_state_up, constants.DEVICE_OWNER: OCTAVIA_OWNER } if aap_list: port[constants.ALLOWED_ADDRESS_PAIRS] = aap_list if fixed_ips: port[constants.FIXED_IPS] = fixed_ips if name: port[constants.NAME] = name if qos_policy_id: port[constants.QOS_POLICY_ID] = qos_policy_id if security_group_ids: port[constants.SECURITY_GROUPS] = security_group_ids new_port = self.neutron_client.create_port({constants.PORT: port}) LOG.debug('Created port: %(port)s', {constants.PORT: new_port}) return utils.convert_port_dict_to_model(new_port) except Exception as e: message = _('Error creating a port on network ' '{network_id} due to {error}.').format( network_id=network_id, error=str(e)) LOG.exception(message) raise base.CreatePortException(message)
def allocate_vrid_fip(self, vrid, network_id, amphorae, fixed_ip=None): fixed_ip_json = {} if vrid.subnet_id: fixed_ip_json['subnet_id'] = vrid.subnet_id if fixed_ip: fixed_ip_json['ip_address'] = fixed_ip # Make sure we are backward compatible with older neutron if self._check_extension_enabled(aap.PROJECT_ID_ALIAS): project_id_key = 'project_id' else: project_id_key = 'tenant_id' # It can be assumed that network_id exists port = { 'port': { 'name': 'octavia-vrid-fip-' + vrid.id, 'network_id': network_id, 'admin_state_up': False, 'device_id': 'vrid-{0}'.format(vrid.id), 'device_owner': aap.OCTAVIA_OWNER, project_id_key: vrid.owner } } if fixed_ip_json: port['port']['fixed_ips'] = [fixed_ip_json] try: new_port = self.neutron_client.create_port(port) except Exception as e: message = _('Error creating neutron port on network ' '{network_id}.').format(network_id=network_id) LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, 'message', None), orig_code=getattr(e, 'status_code', None), ) new_port = utils.convert_port_dict_to_model(new_port) fixed_ip = new_port.fixed_ips[0].ip_address for amphora in filter( lambda amp: amp.status == constants.AMPHORA_ALLOCATED, amphorae): interface = self._get_plugged_interface(amphora.compute_id, network_id, amphora.lb_network_ip) self._add_allowed_address_pair_to_port(interface.port_id, fixed_ip) return new_port
def _plug_amphora_vip(self, amphora, subnet): # We need a vip port owned by Octavia for Act/Stby and failover try: port = { constants.PORT: { constants.NAME: 'octavia-lb-vrrp-' + amphora.id, constants.NETWORK_ID: subnet.network_id, constants.FIXED_IPS: [{ 'subnet_id': subnet.id }], constants.ADMIN_STATE_UP: True, constants.DEVICE_OWNER: OCTAVIA_OWNER } } new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) LOG.debug('Created vip port: %(port_id)s for amphora: %(amp)s', { 'port_id': new_port.id, 'amp': amphora.id }) except Exception as e: message = _('Error creating the base (VRRP) port for the VIP with ' 'port details: {}').format(port) LOG.exception(message) raise base.PlugVIPException(message) from e try: interface = self.plug_port(amphora, new_port) except Exception as e: message = _('Error plugging amphora (compute_id: {compute_id}) ' 'into vip network {network_id}.').format( compute_id=amphora.compute_id, network_id=subnet.network_id) LOG.exception(message) try: if new_port: self.neutron_client.delete_port(new_port.id) LOG.debug( 'Deleted base (VRRP) port %s due to plug_port ' 'failure.', new_port.id) except Exception: LOG.exception( 'Failed to delete base (VRRP) port %s after ' 'plug_port failed. This resource is being ' 'abandoned and should be manually deleted when ' 'neutron is functional.', new_port.id) raise base.PlugVIPException(message) from e return interface
def get_port(self, port_id): try: port = self.neutron_client.show_port(port_id) return utils.convert_port_dict_to_model(port) except neutron_client_exceptions.NotFound: message = _LE('Port not found ' '(port id: {port_id}.').format(port_id=port_id) LOG.exception(message) raise base.PortNotFound(message) except Exception: message = _LE('Error retrieving port ' '(port id: {port_id}.').format(port_id=port_id) LOG.exception(message) raise base.NetworkException(message)
def get_port(self, port_id): try: port = self.neutron_client.show_port(port_id) return utils.convert_port_dict_to_model(port) except neutron_client_exceptions.NotFound: message = _LE('Port not found ' '(port id: {port_id}.').format( port_id=port_id) LOG.exception(message) raise base.PortNotFound(message) except Exception: message = _LE('Error retrieving port ' '(port id: {port_id}.').format( port_id=port_id) LOG.exception(message) raise base.NetworkException(message)
def allocate_vip(self, load_balancer): if load_balancer.vip.port_id: LOG.info('Port %s already exists. Nothing to be done.', load_balancer.vip.port_id) port = self.get_port(load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) fixed_ip = {} if load_balancer.vip.subnet_id: fixed_ip['subnet_id'] = load_balancer.vip.subnet_id if load_balancer.vip.ip_address: fixed_ip['ip_address'] = load_balancer.vip.ip_address # Make sure we are backward compatible with older neutron if self._check_extension_enabled(PROJECT_ID_ALIAS): project_id_key = 'project_id' else: project_id_key = 'tenant_id' # It can be assumed that network_id exists port = { 'port': { 'name': 'octavia-lb-' + load_balancer.id, 'network_id': load_balancer.vip.network_id, 'admin_state_up': False, 'device_id': 'lb-{0}'.format(load_balancer.id), 'device_owner': OCTAVIA_OWNER, project_id_key: load_balancer.project_id } } if fixed_ip: port['port']['fixed_ips'] = [fixed_ip] try: new_port = self.neutron_client.create_port(port) except Exception as e: message = _('Error creating neutron port on network ' '{network_id}.').format( network_id=load_balancer.vip.network_id) LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, 'message', None), orig_code=getattr(e, 'status_code', None), ) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def test_convert_port_dict_to_model(self): model_obj = utils.convert_port_dict_to_model( t_constants.MOCK_NEUTRON_PORT) assert_dict = dict( id=t_constants.MOCK_PORT_ID, name=t_constants.MOCK_PORT_NAME, device_id=t_constants.MOCK_DEVICE_ID, device_owner=t_constants.MOCK_DEVICE_OWNER, mac_address=t_constants.MOCK_MAC_ADDR, network_id=t_constants.MOCK_NETWORK_ID, status=t_constants.MOCK_STATUS, project_id=t_constants.MOCK_PROJECT_ID, admin_state_up=t_constants.MOCK_ADMIN_STATE_UP, ) self._compare_ignore_value_none(model_obj.to_dict(), assert_dict) fixed_ips = t_constants.MOCK_NEUTRON_PORT['port']['fixed_ips'] for ip in model_obj.fixed_ips: self._in_ignore_value_none(ip.to_dict(), fixed_ips)
def test_convert_port_dict_to_model(self): model_obj = utils.convert_port_dict_to_model( t_constants.MOCK_NEUTRON_PORT) assert_dict = dict( id=t_constants.MOCK_PORT_ID, name=t_constants.MOCK_PORT_NAME, device_id=t_constants.MOCK_DEVICE_ID, device_owner=t_constants.MOCK_DEVICE_OWNER, mac_address=t_constants.MOCK_MAC_ADDR, network_id=t_constants.MOCK_NETWORK_ID, status=t_constants.MOCK_STATUS, project_id=t_constants.MOCK_PROJECT_ID, admin_state_up=t_constants.MOCK_ADMIN_STATE_UP, ) self._compare_ignore_value_none(model_obj.to_dict(), assert_dict) fixed_ips = t_constants.MOCK_NEUTRON_PORT['port']['fixed_ips'] for ip in model_obj.fixed_ips: self._in_ignore_value_none(ip.to_dict(), fixed_ips)
def allocate_vip(self, load_balancer): if load_balancer.vip.port_id: LOG.info('Port %s already exists. Nothing to be done.', load_balancer.vip.port_id) port = self.get_port(load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) fixed_ip = {} if load_balancer.vip.subnet_id: fixed_ip['subnet_id'] = load_balancer.vip.subnet_id if load_balancer.vip.ip_address: fixed_ip['ip_address'] = load_balancer.vip.ip_address # Make sure we are backward compatible with older neutron if self._check_extension_enabled(PROJECT_ID_ALIAS): project_id_key = 'project_id' else: project_id_key = 'tenant_id' # It can be assumed that network_id exists port = {'port': {'name': 'octavia-lb-' + load_balancer.id, 'network_id': load_balancer.vip.network_id, 'admin_state_up': False, 'device_id': 'lb-{0}'.format(load_balancer.id), 'device_owner': OCTAVIA_OWNER, project_id_key: load_balancer.project_id}} if fixed_ip: port['port']['fixed_ips'] = [fixed_ip] try: new_port = self.neutron_client.create_port(port) except Exception as e: message = _('Error creating neutron port on network ' '{network_id}.').format( network_id=load_balancer.vip.network_id) LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, 'message', None), orig_code=getattr(e, 'status_code', None), ) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def reserve_subnet_addresses(self, subnet_id, addr_list): subnet = self.get_subnet(subnet_id) try: port = { 'port': { 'name': 'octavia-port-' + subnet.network_id, 'network_id': subnet.network_id, 'admin_state_up': True, 'device_owner': OCTAVIA_OWNER, 'fixed_ips': [] } } for addr in addr_list: fixed_ip = {'subnet_id': subnet_id, 'ip_address': addr} port['port']['fixed_ips'].append(fixed_ip) new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) except Exception as e: LOG.exception(str(e)) raise e return new_port
def _plug_amphora_vip(self, amphora, network_id): # We need a vip port owned by Octavia for Act/Stby and failover try: port = {'port': {'name': 'octavia-lb-vrrp-' + amphora.id, 'network_id': network_id, 'admin_state_up': True, 'device_owner': OCTAVIA_OWNER}} new_port = self.neutron_client.create_port(port) new_port = utils.convert_port_dict_to_model(new_port) LOG.debug('Created vip port: {port_id} for amphora: {amp}'.format( port_id=new_port.id, amp=amphora.id)) interface = self.plug_port(amphora, new_port) except Exception: message = _LE('Error plugging amphora (compute_id: {compute_id}) ' 'into vip network {network_id}.').format( compute_id=amphora.compute_id, network_id=network_id) LOG.exception(message) raise base.PlugVIPException(message) return interface
def allocate_vip(self, load_balancer): port_id = load_balancer.vip.port_id if port_id: LOG.info('Port %s already exists. Nothing to be done.', port_id) port = self.get_port(port_id) return self._port_to_vip(port, load_balancer) fixed_ip = {} if load_balancer.vip.subnet_id: fixed_ip['subnet_id'] = load_balancer.vip.subnet_id if load_balancer.vip.ip_address: fixed_ip['ip_address'] = load_balancer.vip.ip_address # Make sure we are backward compatible with older neutron if self._check_extension_enabled(PROJECT_ID_ALIAS): project_id_key = 'project_id' else: project_id_key = 'tenant_id' # select a candidate to schedule to try: session = db_apis.get_session() candidate = self.amp_repo.get_candidates(session)[0] except ValueError as e: message = _('Scheduling failed, no ready candidates found') LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, 'message', None), orig_code=getattr(e, 'status_code', None), ) LOG.debug("Found candidates for new LB %s: %s", load_balancer.id, candidate) # It can be assumed that network_id exists port = { 'port': { 'name': 'loadbalancer-{}'.format(load_balancer.id), 'network_id': load_balancer.vip.network_id, 'admin_state_up': True, 'device_id': load_balancer.id, 'device_owner': constants.DEVICE_OWNER_LISTENER, 'binding:host_id': candidate, project_id_key: load_balancer.project_id } } if fixed_ip: port['port']['fixed_ips'] = [fixed_ip] try: new_port = self.neutron_client.create_port(port) except Exception as e: message = _('Error creating neutron port on network ' '{network_id}.').format( network_id=load_balancer.vip.network_id) LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, 'message', None), orig_code=getattr(e, 'status_code', None), ) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer)
def allocate_vip(self, load_balancer): if load_balancer.vip.port_id: try: port = self.get_port(load_balancer.vip.port_id) fixed_ip_found = self._validate_fixed_ip( port.fixed_ips, load_balancer.vip.subnet_id, load_balancer.vip.ip_address) if (port.network_id == load_balancer.vip.network_id and fixed_ip_found): LOG.info('Port %s already exists. Nothing to be done.', load_balancer.vip.port_id) return self._port_to_vip(port, load_balancer) LOG.error( 'Neutron VIP mis-match. Expected ip %s on ' 'subnet %s in network %s. Neutron has fixed_ips %s ' 'in network %s. Deleting and recreating the VIP ' 'port.', load_balancer.vip.ip_address, load_balancer.vip.subnet_id, load_balancer.vip.network_id, self._fixed_ips_to_list_of_dicts(port.fixed_ips), port.network_id) if load_balancer.vip.octavia_owned: self.delete_port(load_balancer.vip.port_id) else: raise base.AllocateVIPException( 'VIP port {0} is broken, but is owned by project {1} ' 'so will not be recreated. Aborting VIP allocation.'. format(port.id, port.project_id)) except base.AllocateVIPException as e: # Catch this explicitly because otherwise we blame Neutron LOG.error(getattr(e, constants.MESSAGE, None)) raise except base.PortNotFound: LOG.warning('VIP port %s is missing from neutron. Rebuilding.', load_balancer.vip.port_id) except Exception as e: message = _('Neutron is failing to service requests due to: ' '{}. Aborting.').format(str(e)) LOG.error(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, constants.MESSAGE, None), orig_code=getattr(e, constants.STATUS_CODE, None), ) fixed_ip = {} if load_balancer.vip.subnet_id: fixed_ip['subnet_id'] = load_balancer.vip.subnet_id if load_balancer.vip.ip_address: fixed_ip[constants.IP_ADDRESS] = load_balancer.vip.ip_address # Make sure we are backward compatible with older neutron if self._check_extension_enabled(PROJECT_ID_ALIAS): project_id_key = 'project_id' else: project_id_key = 'tenant_id' # It can be assumed that network_id exists port = { constants.PORT: { constants.NAME: 'octavia-lb-' + load_balancer.id, constants.NETWORK_ID: load_balancer.vip.network_id, constants.ADMIN_STATE_UP: False, 'device_id': 'lb-{0}'.format(load_balancer.id), constants.DEVICE_OWNER: OCTAVIA_OWNER, project_id_key: load_balancer.project_id } } if fixed_ip: port[constants.PORT][constants.FIXED_IPS] = [fixed_ip] try: new_port = self.neutron_client.create_port(port) except Exception as e: message = _('Error creating neutron port on network ' '{network_id} due to {e}.').format( network_id=load_balancer.vip.network_id, e=str(e)) LOG.exception(message) raise base.AllocateVIPException( message, orig_msg=getattr(e, constants.MESSAGE, None), orig_code=getattr(e, constants.STATUS_CODE, None), ) new_port = utils.convert_port_dict_to_model(new_port) return self._port_to_vip(new_port, load_balancer, octavia_owned=True)