def create_ports_if_not_exist(task, macs): """Create ironic ports for the mac addresses. Creates ironic ports for the mac addresses returned with inspection or as requested by operator. :param task: A TaskManager instance. :param macs: A dictionary of port numbers to mac addresses returned by node inspection. """ node = task.node for port_num, mac in macs.items(): # TODO(etingof): detect --pxe-enabled flag port_dict = {'address': mac, 'node_id': node.id} port = objects.Port(task.context, **port_dict) try: port.create() LOG.info( "Port %(port_num)s created for MAC address %(address)s " "for node %(node)s", { 'address': mac, 'node': node.uuid, 'port_num': port_num }) except exception.MACAlreadyExists: LOG.warning( "Port %(port_num)s already exists for " "MAC address %(address)s for node " "%(node)s", { 'address': mac, 'node': node.uuid, 'port_num': port_num })
def _create_ports_if_not_exist(task, macs): """Create ironic ports for the mac addresses. Creates ironic ports for the mac addresses returned with inspection or as requested by operator. :param task: a TaskManager instance. :param macs: A dictionary of port numbers to mac addresses returned by node inspection. """ node = task.node for mac in macs.values(): port_dict = {'address': mac, 'node_id': node.id} port = objects.Port(task.context, **port_dict) try: port.create() LOG.info( _LI("Port created for MAC address %(address)s for node " "%(node)s"), { 'address': mac, 'node': node.uuid }) except exception.MACAlreadyExists: LOG.warning( _LW("Port already exists for MAC address %(address)s " "for node %(node)s"), { 'address': mac, 'node': node.uuid })
def create_ports_if_not_exist(task, macs, get_mac_address=lambda x: x[1]): """Create ironic ports from MAC addresses data dict. Creates ironic ports from MAC addresses data returned with inspection or as requested by operator. Helper argument to detect the MAC address ``get_mac_address`` defaults to 'value' part of MAC address dict key-value pair. :param task: A TaskManager instance. :param macs: A dictionary of MAC addresses returned by node inspection. :param get_mac_address: a function to get the MAC address from mac item. A mac item is the dict key-value pair of the previous ``macs`` argument. """ node = task.node for k_v_pair in macs.items(): mac = get_mac_address(k_v_pair) port_dict = {'address': mac, 'node_id': node.id} port = objects.Port(task.context, **port_dict) try: port.create() LOG.info( "Port created for MAC address %(address)s for node " "%(node)s", { 'address': mac, 'node': node.uuid }) except exception.MACAlreadyExists: LOG.warning( "Port already exists for MAC address %(address)s " "for node %(node)s", { 'address': mac, 'node': node.uuid })
def test_vif_in_extra_in_internal_info(self): vif2 = 'another_uuid' port = objects.Port(self.context, **self.fake_port) port.internal_info['tenant_vif_port_id'] = vif2 port._convert_to_version('1.8', False) # no change self.assertEqual(vif2, port.internal_info['tenant_vif_port_id'])
def post(self, port): """Create a new port. :param port: a port within the request body. :raises: NotAcceptable, HTTPNotFound, Conflict """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:create', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() pdict = port.as_dict() self._check_allowed_port_fields(pdict) extra = pdict.get('extra') vif = extra.get('vif_port_id') if extra else None if vif: common_utils.warn_about_deprecated_extra_vif_port_id() if (pdict.get('portgroup_uuid') and (pdict.get('pxe_enabled') or vif)): rpc_pg = objects.Portgroup.get_by_uuid(context, pdict['portgroup_uuid']) if not rpc_pg.standalone_ports_supported: msg = _("Port group %s doesn't support standalone ports. " "This port cannot be created as a member of that " "port group because either 'extra/vif_port_id' " "was specified or 'pxe_enabled' was set to True.") raise exception.Conflict(msg % pdict['portgroup_uuid']) # NOTE(yuriyz): UUID is mandatory for notifications payload if not pdict.get('uuid'): pdict['uuid'] = uuidutils.generate_uuid() rpc_port = objects.Port(context, **pdict) rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) notify_extra = { 'node_uuid': port.node_uuid, 'portgroup_uuid': port.portgroup_uuid } notify.emit_start_notification(context, rpc_port, 'create', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'create', **notify_extra): # TODO(mgoddard): In RPC API v1.41, port creation was moved to the # conductor service to facilitate validation of the physical # network field of ports in portgroups. Further consideration is # required determine how best to support rolling upgrades from a # release in which ports are created by the API service to one in # which they are created by the conductor service, while ensuring # that all required validation is performed. topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.create_port( context, rpc_port, topic) notify.emit_end_notification(context, new_port, 'create', **notify_extra) # Set the HTTP Location Header pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port)
def post(self, port): """Create a new port. :param port: a port within the request body. :raises: NotAcceptable, HTTPNotFound """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:port:create', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() pdict = port.as_dict() if (not api_utils.allow_port_advanced_net_fields() and set(pdict).intersection(self.advanced_net_fields)): raise exception.NotAcceptable() if (not api_utils.allow_portgroups_subcontrollers() and 'portgroup_uuid' in pdict): raise exception.NotAcceptable() new_port = objects.Port(pecan.request.context, **pdict) new_port.create() # Set the HTTP Location Header pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port)
def inspect_hardware(self, task): """Inspect hardware. Inspect hardware to obtain the essential hardware properties and mac addresses. :param task: a task from TaskManager. :raises: HardwareInspectionFailure, if hardware inspection failed. :returns: states.MANAGEABLE, if hardware inspection succeeded. """ node = task.node kwargs = {} # Inspect additional capabilities task requires node with power on # status old_power_state = task.driver.power.get_power_state(task) if old_power_state == states.POWER_OFF: manager_utils.node_set_boot_device(task, boot_devices.BIOS, False) manager_utils.node_power_action(task, states.POWER_ON) LOG.info("The Node %(node_uuid)s being powered on for inspection", {'node_uuid': task.node.uuid}) kwargs['sleep_flag'] = True (props, macs) = _inspect_hardware(node, **kwargs) node.properties = dict(node.properties, **props) node.save() for mac in macs: try: new_port = objects.Port(task.context, address=mac, node_id=node.id) new_port.create() LOG.info( "Port created for MAC address %(address)s " "for node %(node_uuid)s during inspection", { 'address': mac, 'node_uuid': node.uuid }) except exception.MACAlreadyExists: LOG.warning( "Port already existed for MAC address " "%(address)s for node %(node_uuid)s " "during inspection", { 'address': mac, 'node_uuid': node.uuid }) LOG.info("Node %s inspected", node.uuid) # restore old power state if old_power_state == states.POWER_OFF: manager_utils.node_power_action(task, states.POWER_OFF) LOG.info( "The Node %(node_uuid)s being powered off after " "inspection", {'node_uuid': task.node.uuid}) return states.MANAGEABLE
def test_name_unsupported_missing(self): # name not set, no change required. port = objects.Port(self.context, **self.fake_port) delattr(port, 'name') port.obj_reset_changes() port._convert_to_version("1.9") self.assertNotIn('name', port) self.assertNotIn('name', port.obj_get_changes())
def test_name_unsupported_set_remove(self): # name set, should be removed. port = objects.Port(self.context, **self.fake_port) port.name = 'meow' port.obj_reset_changes() port._convert_to_version("1.9") self.assertNotIn('name', port) self.assertNotIn('name', port.obj_get_changes())
def test_name_supported_set(self): # Physical network set, no change required. port = objects.Port(self.context, **self.fake_port) port.name = 'meow' port.obj_reset_changes() port._convert_to_version("1.10") self.assertEqual('meow', port.name) self.assertNotIn('name', port.obj_get_changes())
def test_physnet_unsupported_set_no_remove_non_default(self): # Physical network set, should be set to default. port = objects.Port(self.context, **self.fake_port) port.physical_network = 'physnet1' port.obj_reset_changes() port._convert_to_version("1.6", False) self.assertIsNone(port.physical_network) self.assertEqual({'physical_network': None}, port.obj_get_changes())
def test_physnet_supported_set(self): # Physical network set, no change required. port = objects.Port(self.context, **self.fake_port) port.physical_network = 'physnet1' port.obj_reset_changes() port._convert_to_version("1.7") self.assertEqual('physnet1', port.physical_network) self.assertEqual({}, port.obj_get_changes())
def test_is_smartnic_unsupported_missing(self): # is_smartnic is not set, no change required. port = objects.Port(self.context, **self.fake_port) delattr(port, 'is_smartnic') port.obj_reset_changes() port._convert_to_version("1.8") self.assertNotIn('is_smartnic', port) self.assertNotIn('is_smartnic', port.obj_get_changes())
def test_is_smartnic_unsupported_set_remove(self): # is_smartnic is set, should be removed. port = objects.Port(self.context, **self.fake_port) port.is_smartnic = False port.obj_reset_changes() port._convert_to_version("1.8") self.assertNotIn('is_smartnic', port) self.assertNotIn('is_smartnic', port.obj_get_changes())
def test_name_unsupported_set_no_remove_default(self): # name set, no change required. port = objects.Port(self.context, **self.fake_port) port.name = None port.obj_reset_changes() port._convert_to_version("1.9", False) self.assertIsNone(port.name) self.assertNotIn('name', port.obj_get_changes())
def test_is_smartnic_supported_set(self): # is_smartnic is set, no change required. port = objects.Port(self.context, **self.fake_port) port.is_smartnic = True port.obj_reset_changes() port._convert_to_version("1.9") self.assertTrue(port.is_smartnic) self.assertNotIn('is_smartnic', port.obj_get_changes())
def test_physnet_unsupported_set_no_remove_default(self): # Physical network set, no change required. port = objects.Port(self.context, **self.fake_port) port.physical_network = None port.obj_reset_changes() port._convert_to_version("1.6", False) self.assertIsNone(port.physical_network) self.assertEqual({}, port.obj_get_changes())
def test_is_smartnic_unsupported_set_no_remove_default(self): # is_smartnic is set, no change required. port = objects.Port(self.context, **self.fake_port) port.is_smartnic = False port.obj_reset_changes() port._convert_to_version("1.8", False) self.assertFalse(port.is_smartnic) self.assertNotIn('is_smartnic', port.obj_get_changes())
def test_physnet_unsupported_set_remove(self): # Physical network set, should be removed. port = objects.Port(self.context, **self.fake_port) port.physical_network = 'physnet1' port.obj_reset_changes() port._convert_to_version("1.6") self.assertNotIn('physical_network', port) self.assertEqual({}, port.obj_get_changes())
def test_physnet_unsupported_missing(self): # Physical network not set, no change required. port = objects.Port(self.context, **self.fake_port) delattr(port, 'physical_network') port.obj_reset_changes() port._convert_to_version("1.6") self.assertNotIn('physical_network', port) self.assertEqual({}, port.obj_get_changes())
def test_physnet_supported_missing(self): # Physical network not set, should be set to default. port = objects.Port(self.context, **self.fake_port) delattr(port, 'physical_network') port.obj_reset_changes() port._convert_to_version("1.7") self.assertIsNone(port.physical_network) self.assertEqual({'physical_network': None}, port.obj_get_changes())
def test_name_supported_missing(self): # name not set, should be set to default. port = objects.Port(self.context, **self.fake_port) delattr(port, 'name') port.obj_reset_changes() port._convert_to_version("1.10") self.assertIsNone(port.name) self.assertIn('name', port.obj_get_changes()) self.assertIsNone(port.obj_get_changes()['name'])
def post(self, port): """Create a new port. :param port: a port within the request body. :raises: NotAcceptable, HTTPNotFound, Conflict """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:create', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() pdict = port.as_dict() if (not api_utils.allow_port_advanced_net_fields() and set(pdict).intersection(self.advanced_net_fields)): raise exception.NotAcceptable() if (not api_utils.allow_portgroups_subcontrollers() and 'portgroup_uuid' in pdict): raise exception.NotAcceptable() extra = pdict.get('extra') vif = extra.get('vif_port_id') if extra else None if vif: common_utils.warn_about_deprecated_extra_vif_port_id() if (pdict.get('portgroup_uuid') and (pdict.get('pxe_enabled') or vif)): rpc_pg = objects.Portgroup.get_by_uuid(context, pdict['portgroup_uuid']) if not rpc_pg.standalone_ports_supported: msg = _("Port group %s doesn't support standalone ports. " "This port cannot be created as a member of that " "port group because either 'extra/vif_port_id' " "was specified or 'pxe_enabled' was set to True.") raise exception.Conflict(msg % pdict['portgroup_uuid']) # NOTE(yuriyz): UUID is mandatory for notifications payload if not pdict.get('uuid'): pdict['uuid'] = uuidutils.generate_uuid() new_port = objects.Port(context, **pdict) notify.emit_start_notification(context, new_port, 'create', node_uuid=port.node_uuid) with notify.handle_error_notification(context, new_port, 'create', node_uuid=port.node_uuid): new_port.create() notify.emit_end_notification(context, new_port, 'create', node_uuid=port.node_uuid) # Set the HTTP Location Header pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port)
def test_is_smartnic_unsupported_set_no_remove_non_default(self): # is_smartnic is set, should be set to default. port = objects.Port(self.context, **self.fake_port) port.is_smartnic = True port.obj_reset_changes() port._convert_to_version("1.8", False) self.assertFalse(port.is_smartnic) self.assertIn('is_smartnic', port.obj_get_changes()) self.assertFalse(port.obj_get_changes()['is_smartnic'])
def test_is_smartnic_supported_missing(self): # is_smartnic is not set, should be set to default. port = objects.Port(self.context, **self.fake_port) delattr(port, 'is_smartnic') port.obj_reset_changes() port._convert_to_version("1.9") self.assertFalse(port.is_smartnic) self.assertIn('is_smartnic', port.obj_get_changes()) self.assertFalse(port.obj_get_changes()['is_smartnic'])
def test_name_unsupported_set_no_remove_non_default(self): # name set, should be set to default. port = objects.Port(self.context, **self.fake_port) port.name = 'meow' port.obj_reset_changes() port._convert_to_version("1.9", False) self.assertIsNone(port.name) self.assertIn('name', port.obj_get_changes()) self.assertIsNone(port.obj_get_changes()['name'])
def test_create(self): port = objects.Port(self.context, **self.fake_port) with mock.patch.object(self.dbapi, 'create_port', autospec=True) as mock_create_port: mock_create_port.return_value = db_utils.get_test_port() port.create() args, _kwargs = mock_create_port.call_args self.assertEqual(objects.Port.VERSION, args[0]['version'])
def get_test_port(ctxt, **kw): """Return a Port object with appropriate attributes. NOTE: The object leaves the attributes marked as changed, such that a create() could be used to commit it to the DB. """ db_port = db_utils.get_test_port(**kw) port = objects.Port(ctxt) for key in db_port: setattr(port, key, db_port[key]) return port
def post(self, port): """Create a new port. :param port: a port within the request body. """ if self.from_nodes: raise exception.OperationNotPermitted new_port = objects.Port(pecan.request.context, **port.as_dict()) new_port.create() # Set the HTTP Location Header pecan.response.location = link.build_url('ports', new_port.uuid) return Port.convert_with_links(new_port)
def get_test_port(ctxt, **kw): """Return a Port object with appropriate attributes. NOTE: The object leaves the attributes marked as changed, such that a create() could be used to commit it to the DB. """ db_port = db_utils.get_test_port(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del db_port['id'] port = objects.Port(ctxt) for key in db_port: setattr(port, key, db_port[key]) return port