def _handle_port_migration_precommit(self, context): """Handles port migration in precommit It updates the port's new host in the DB """ orig_port = context.original orig_host = context.original_host orig_status = context.original_status new_status = context.status new_host = context.host port_id = orig_port['id'] if (new_host != orig_host and orig_status == n_const.PORT_STATUS_ACTIVE and new_status == n_const.PORT_STATUS_DOWN): LOG.debug("Handling port migration for: %s " % orig_port) network_id = orig_port['network_id'] tenant_id = orig_port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) device_id = orig_port['device_id'] with self.eos_sync_lock: port_provisioned = db_lib.is_port_provisioned( port_id, orig_host) if port_provisioned: db_lib.update_port(device_id, new_host, port_id, network_id, tenant_id) return True
def update_port_precommit(self, context): """Update the name of a given port. At the moment we only support port name change. Any other change to port is not supported at this time. We do not store the port names, therefore, no DB store action is performed here. """ new_port = context.current orig_port = context.original if new_port['name'] != orig_port['name']: LOG.info(_LI('Port name changed to %s'), new_port['name']) new_port = context.current device_id = new_port['device_id'] host = context.host # device_id and device_owner are set on VM boot port_id = new_port['id'] network_id = new_port['network_id'] tenant_id = new_port['tenant_id'] or INTERNAL_TENANT_ID with self.eos_sync_lock: port_provisioned = db_lib.is_port_provisioned(port_id) if not port_provisioned: # Create a new port in the DB db_lib.remember_tenant(tenant_id) db_lib.remember_vm(device_id, host, port_id, network_id, tenant_id) else: # Port exists in the DB. Update it db_lib.update_port(device_id, host, port_id, network_id, tenant_id)
def delete_port_precommit(self, context): """Delete information about a VM and host from the DB.""" port = context.current port_id = port['id'] with self.eos_sync_lock: if db_lib.is_port_provisioned(port_id): db_lib.forget_vm_port(port_id)
def create_port_postcommit(self, context): """Plug a physical host into a network. Send provisioning request to Arista Hardware to plug a host into appropriate network. """ port = context.current device_id = port['device_id'] device_owner = port['device_owner'] host = context.host profile = [] vnic_type = port['binding:vnic_type'] binding_profile = port['binding:profile'] if binding_profile: profile = binding_profile['local_link_information'] pretty_log("create_port_postcommit:", port) sg = port['security_groups'] # device_id and device_owner are set on VM boot is_vm_boot = device_id and device_owner if host and is_vm_boot: port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) with self.eos_sync_lock: hostname = self._host_name(host) port_provisioned = db_lib.is_port_provisioned(port_id) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id if port_provisioned and self._network_provisioned(tenant_id, network_id): try: self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner, sg, [], vnic_type, profile=profile) except arista_exc.AristaRpcError as err: LOG.error(_LE('create_port_postcommit: Did not create ' 'port %(port_id)s. Reason: %(err)s'), {'port_id': port_id, 'err': err}) else: LOG.info(_LI('VM %s is not created as it is not found in ' 'Arista DB'), device_id)
def update_port_postcommit(self, context): """Update the name of a given port in EOS. At the moment we only support port name change Any other change to port is not supported at this time. """ port = context.current orig_port = context.original device_id = port['device_id'] device_owner = port['device_owner'] host = context.host is_vm_boot = device_id and device_owner port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID with self.eos_sync_lock: hostname = self._host_name(host) segmentation_id = db_lib.get_segmentation_id(tenant_id, network_id) port_provisioned = db_lib.is_port_provisioned(port_id) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id net_provisioned = ( db_lib.is_network_provisioned(tenant_id, network_id, segmentation_id) or self.ndb.get_shared_network_owner_id(network_id) ) try: orig_host = orig_port['binding:host_id'] if host != orig_host: try: # The port moved to a different host or the VM # connected to the port was deleted. So delete the # old port on the old host. self._delete_port(orig_port, orig_host, tenant_id) except ml2_exc.MechanismDriverError: # If deleting a port fails, then not much can be done # about it. Log a warning and move on. LOG.warn(UNABLE_TO_DELETE_PORT_MSG) if(port_provisioned and net_provisioned and hostname and is_vm_boot): # Plug port into the network only if it exists on a host # and if it has an owner self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner) except arista_exc.AristaRpcError: LOG.info(EOS_UNREACHABLE_MSG) raise ml2_exc.MechanismDriverError()
def delete_port_precommit(self, context): """Delete information about a VM and host from the DB.""" port = context.current pretty_log("delete_port_precommit:", port) port_id = port['id'] host_id = context.host with self.eos_sync_lock: if db_lib.is_port_provisioned(port_id): db_lib.forget_port(port_id, host_id)
def create_port_postcommit(self, context): """Plug a physical host into a network. Send provisioning request to Arista Hardware to plug a host into appropriate network. """ port = context.current device_id = port['device_id'] device_owner = port['device_owner'] host = context.host # device_id and device_owner are set on VM boot is_vm_boot = device_id and device_owner if host and is_vm_boot: port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID with self.eos_sync_lock: hostname = self._host_name(host) port_provisioned = db_lib.is_port_provisioned(port_id) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id net_provisioned = ( db_lib.is_network_provisioned(tenant_id, network_id) or self.ndb.get_shared_network_owner_id(network_id) ) if port_provisioned and net_provisioned: try: self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner) except arista_exc.AristaRpcError: LOG.info(EOS_UNREACHABLE_MSG) raise ml2_exc.MechanismDriverError() else: LOG.info(_LI('VM %s is not created as it is not found in ' 'Arista DB'), device_id)
def update_port_postcommit(self, context): """Update the name of a given port in EOS. At the moment we only support port name change Any other change to port is not supported at this time. """ port = context.current orig_port = context.original device_id = port['device_id'] device_owner = port['device_owner'] host = context.host is_vm_boot = device_id and device_owner vnic_type = port['binding:vnic_type'] binding_profile = port['binding:profile'] bindings = [] if binding_profile: bindings = binding_profile['local_link_information'] port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) sg = port['security_groups'] orig_sg = orig_port['security_groups'] pretty_log("update_port_postcommit: new", port) pretty_log("update_port_postcommit: orig", orig_port) # Check if it is port migration case if self._handle_port_migration_postcommit(context): # Return from here as port migration is already handled. return seg_info = self._bound_segments(context) if not seg_info: LOG.debug("Ignoring the update as the port is not managed by " "Arista switches.") return with self.eos_sync_lock: hostname = self._host_name(host) segmentation_id = seg_info[driver_api.SEGMENTATION_ID] port_host_filter = None if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # <port, host> uniquely identifies a DVR port. Other # ports are identified by just the port id port_host_filter = host port_provisioned = db_lib.is_port_provisioned( port_id, port_host_filter) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id net_provisioned = self._network_provisioned( tenant_id, network_id, segmentation_id=segmentation_id) segments = [] if net_provisioned: if self.rpc.hpb_supported(): for binding_level in context.binding_levels: bound_segment = binding_level.get( driver_api.BOUND_SEGMENT) if bound_segment: segments.append(bound_segment) all_segments = self.ndb.get_all_network_segments( network_id, context=context._plugin_context) try: self.rpc.create_network_segments( tenant_id, network_id, context.network.current['name'], all_segments) except arista_exc.AristaRpcError: LOG.error(_LE("Failed to create network segments")) raise ml2_exc.MechanismDriverError() else: # For non HPB cases, the port is bound to the static # segment segments = self.ndb.get_network_segments(network_id) try: orig_host = context.original_host port_down = False if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE ): # We care about port status only for DVR ports port_down = context.status == n_const.PORT_STATUS_DOWN if orig_host and (port_down or host != orig_host): try: LOG.info("Deleting the port %s" % str(orig_port)) # The port moved to a different host or the VM # connected to the port was deleted or its in DOWN # state. So delete the old port on the old host. self._delete_port(orig_port, orig_host, tenant_id) except ml2_exc.MechanismDriverError: # If deleting a port fails, then not much can be done # about it. Log a warning and move on. LOG.warning(UNABLE_TO_DELETE_PORT_MSG) if (port_provisioned and net_provisioned and hostname and is_vm_boot and not port_down): LOG.info(_LI("Port plugged into network")) # Plug port into the network only if it exists in the db # and is bound to a host and the port is up. self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner, sg, orig_sg, vnic_type, segments=segments, switch_bindings=bindings) else: LOG.info(_LI("Port not plugged into network")) except arista_exc.AristaRpcError as err: LOG.error( _LE('update_port_postcommit: Did not update ' 'port %(port_id)s. Reason: %(err)s'), { 'port_id': port_id, 'err': err })
def update_port_precommit(self, context): """Update the name of a given port. At the moment we only support port name change. Any other change to port is not supported at this time. We do not store the port names, therefore, no DB store action is performed here. """ new_port = context.current orig_port = context.original if new_port['name'] != orig_port['name']: LOG.info(_LI('Port name changed to %s'), new_port['name']) device_id = new_port['device_id'] host = context.host pretty_log("update_port_precommit: new", new_port) pretty_log("update_port_precommit: orig", orig_port) if new_port['device_owner'] == 'compute:probe': return # Check if it is port migration case if self._handle_port_migration_precommit(context): return # Check if the port is part of managed physical network seg_info = self._bound_segments(context) if not seg_info: # Ignoring the update as the port is not managed by # arista mechanism driver. return # device_id and device_owner are set on VM boot port_id = new_port['id'] network_id = new_port['network_id'] tenant_id = new_port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) if not self._network_provisioned(tenant_id, network_id, seg_info[driver_api.SEGMENTATION_ID], seg_info[driver_api.ID]): if not self.rpc.hpb_supported(): LOG.info( _LI("Ignoring port %(port)s conntected to " "%(net_id)s"), { 'port': port_id, 'net_id': network_id }) return LOG.info(_LI("Adding %s to provisioned network database"), seg_info) with self.eos_sync_lock: db_lib.remember_tenant(tenant_id) db_lib.remember_network_segment( tenant_id, network_id, seg_info[driver_api.SEGMENTATION_ID], seg_info[driver_api.ID]) with self.eos_sync_lock: port_down = False if (new_port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE ): # We care about port status only for DVR ports because # for DVR, a single port exists on multiple hosts. If a port # is no longer needed on a host then the driver gets a # port_update notification for that <port, host> with the # port status as PORT_STATUS_DOWN. port_down = context.status == n_const.PORT_STATUS_DOWN if host and not port_down: port_host_filter = None if (new_port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # <port, host> uniquely identifies a DVR port. Other # ports are identified by just the port id port_host_filter = host port_provisioned = db_lib.is_port_provisioned( port_id, port_host_filter) if not port_provisioned: LOG.info("Remembering the port") # Create a new port in the DB db_lib.remember_tenant(tenant_id) db_lib.remember_vm(device_id, host, port_id, network_id, tenant_id) else: if (new_port['device_id'] != orig_port['device_id'] or context.host != context.original_host or new_port['network_id'] != orig_port['network_id'] or new_port['tenant_id'] != orig_port['tenant_id']): LOG.info("Updating the port") # Port exists in the DB. Update it db_lib.update_port(device_id, host, port_id, network_id, tenant_id) else: # Unbound or down port does not concern us orig_host = context.original_host LOG.info("Forgetting the port on %s" % str(orig_host)) db_lib.forget_port(port_id, orig_host)
def update_port_postcommit(self, context): """Update the name of a given port in EOS. At the moment we only support port name change Any other change to port is not supported at this time. """ port = context.current orig_port = context.original device_id = port['device_id'] device_owner = port['device_owner'] host = context.host is_vm_boot = device_id and device_owner vnic_type = port['binding:vnic_type'] binding_profile = port['binding:profile'] profile = [] if binding_profile: profile = binding_profile['local_link_information'] port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID sg = port['security_groups'] orig_sg = orig_port['security_groups'] pretty_log("update_port_postcommit: new", port) pretty_log("update_port_postcommit: orig", orig_port) with self.eos_sync_lock: hostname = self._host_name(host) segmentation_id = db_lib.get_segmentation_id(tenant_id, network_id) port_host_filter = None if(port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # <port, host> uniquely identifies a DVR port. Other # ports are identified by just the port id port_host_filter = host port_provisioned = db_lib.is_port_provisioned(port_id, port_host_filter) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id net_provisioned = self._network_provisioned(tenant_id, network_id, segmentation_id) try: orig_host = context.original_host port_down = False if(port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # We care about port status only for DVR ports port_down = context.status == n_const.PORT_STATUS_DOWN if orig_host and (port_down or host != orig_host): try: LOG.info("Deleting the port %s" % str(orig_port)) # The port moved to a different host or the VM # connected to the port was deleted or its in DOWN # state. So delete the old port on the old host. self._delete_port(orig_port, orig_host, tenant_id) except ml2_exc.MechanismDriverError: # If deleting a port fails, then not much can be done # about it. Log a warning and move on. LOG.warn(UNABLE_TO_DELETE_PORT_MSG) if(port_provisioned and net_provisioned and hostname and is_vm_boot and not port_down): LOG.info(_LI("Port plugged into network")) # Plug port into the network only if it exists in the db # and is bound to a host and the port is up. self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner, sg, orig_sg, vnic_type, profile=profile) else: LOG.info(_LI("Port not plugged into network")) except arista_exc.AristaRpcError as err: LOG.error(_LE('update_port_postcommit: Did not update ' 'port %(port_id)s. Reason: %(err)s'), {'port_id': port_id, 'err': err})
def update_port_precommit(self, context): """Update the name of a given port. At the moment we only support port name change. Any other change to port is not supported at this time. We do not store the port names, therefore, no DB store action is performed here. """ new_port = context.current orig_port = context.original if new_port['name'] != orig_port['name']: LOG.info(_LI('Port name changed to %s'), new_port['name']) new_port = context.current device_id = new_port['device_id'] host = context.host pretty_log("update_port_precommit: new", new_port) pretty_log("update_port_precommit: orig", orig_port) if new_port['device_owner'] == 'compute:probe': return # device_id and device_owner are set on VM boot port_id = new_port['id'] network_id = new_port['network_id'] tenant_id = new_port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) if not self._network_provisioned(tenant_id, network_id): # If the Arista driver does not know about the network, ignore the # port. LOG.info(_LI("Ignoring port connected to %s"), network_id) return with self.eos_sync_lock: port_down = False if(new_port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # We care about port status only for DVR ports because # for DVR, a single port exists on multiple hosts. If a port # is no longer needed on a host then the driver gets a # port_update notification for that <port, host> with the # port status as PORT_STATUS_DOWN. port_down = context.status == n_const.PORT_STATUS_DOWN if host and not port_down: port_host_filter = None if(new_port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # <port, host> uniquely identifies a DVR port. Other # ports are identified by just the port id port_host_filter = host port_provisioned = db_lib.is_port_provisioned( port_id, port_host_filter) if not port_provisioned: LOG.info("Remembering the port") # Create a new port in the DB db_lib.remember_tenant(tenant_id) db_lib.remember_vm(device_id, host, port_id, network_id, tenant_id) else: if(new_port['device_id'] != orig_port['device_id'] or context.host != context.original_host or new_port['network_id'] != orig_port['network_id'] or new_port['tenant_id'] != orig_port['tenant_id']): LOG.info("Updating the port") # Port exists in the DB. Update it db_lib.update_port(device_id, host, port_id, network_id, tenant_id) else: # Unbound or down port does not concern us orig_host = context.original_host LOG.info("Forgetting the port on %s" % str(orig_host)) db_lib.forget_port(port_id, orig_host)