support specifying port_id when attaching interface

Change-Id: I5d3f18a32c357096f5a6090abed1d8d480a93c6f
This commit is contained in:
Xinran 2017-08-16 16:35:41 +08:00
parent 30a16bc608
commit 817748c6b0
11 changed files with 88 additions and 22 deletions

View File

@ -1,3 +1,4 @@
{
"net_id": "a19ffb45-8207-4771-b0ef-f63c91fb46d6"
"port_id": "6cefb080-77bb-4bf9-8695-c10401e86c05"
}

View File

@ -117,6 +117,7 @@ Request
- server_uuid: server_ident
- net_id: network_uuid
- port_id: port_uuid
**Example request to Add (Associate) Interface to a server:**

View File

@ -21,7 +21,11 @@ attach_interface = {
'type': 'object',
'properties': {
'net_id': parameter_types.network_id,
'port_id': parameter_types.network_port_id
},
'required': ['net_id'],
'oneOf': [
{'required': ['net_id']},
{'required': ['port_id']}
],
'additionalProperties': False
}

View File

@ -21,7 +21,6 @@ import pecan
from pecan import rest
import six
from six.moves import http_client
from webob import exc
import wsme
from wsme import types as wtypes
@ -339,15 +338,12 @@ class InterfaceController(ServerControllerBase):
"""
validation.check_schema(interface, interface_schemas.attach_interface)
port_id = interface.get('port_id', None)
net_id = interface.get('net_id', None)
if not net_id:
msg = _("Must input network_id")
raise exc.HTTPBadRequest(explanation=msg)
server = self._resource or self._get_resource(server_uuid)
pecan.request.engine_api.attach_interface(pecan.request.context,
server, net_id)
server, net_id, port_id)
@policy.authorize_wsgi("mogan:server", "detach_interface")
@expose.expose(None, types.uuid, types.uuid,

View File

@ -28,6 +28,7 @@ from mogan.common import ironic
from mogan.common import states
from mogan.conf import CONF
LOG = logging.getLogger(__name__)
_POWER_STATE_MAP = {

View File

@ -546,9 +546,9 @@ class API(object):
return objects.KeyPair.get_by_name(context, user_id, key_name)
@check_server_lock
def attach_interface(self, context, server, net_id):
def attach_interface(self, context, server, net_id, port_id):
LOG.debug('Going to attach interface to server %s', server.uuid)
self.engine_rpcapi.attach_interface(context, server, net_id)
self.engine_rpcapi.attach_interface(context, server, net_id, port_id)
@check_server_lock
def detach_interface(self, context, server, port_id):

View File

@ -530,23 +530,45 @@ class EngineManager(base_manager.BaseEngineManager):
'port': parsed_url.port,
'internal_access_path': None}
def attach_interface(self, context, server, net_id=None):
LOG.debug("Attaching interface %(net_id) to server %(server)s",
{'net_id': net_id, 'server': server})
@wrap_server_fault
def attach_interface(self, context, server, net_id, port_id):
# prepare port to be attached
if port_id:
LOG.debug("Attaching port %(port_id) to server %(server)s",
{'port_id': port_id, 'server': server})
try:
vif_port = self.network_api.show_port(context, port_id)
except Exception:
raise exception.PortNotFound(port_id=port_id)
# self.network_api.check_port_availability(vif_port)
else:
LOG.debug("Attaching network interface %(net_id) to server "
"%(server)s", {'net_id': net_id, 'server': server})
vif_port = self.network_api.create_port(context, net_id,
server.uuid)
try:
port = self.network_api.create_port(context, net_id, server.uuid)
self.driver.plug_vif(server.node_uuid, port['id'])
vif = self.network_api.bind_port(context, vif_port['id'], server)
vif_port = vif['port']
self.driver.plug_vif(server.node_uuid, vif_port['id'])
nics_obj = objects.ServerNics(context)
nic_dict = {'port_id': port['id'],
'network_id': port['network_id'],
'mac_address': port['mac_address'],
'fixed_ips': port['fixed_ips'],
nic_dict = {'port_id': vif_port['id'],
'network_id': vif_port['network_id'],
'mac_address': vif_port['mac_address'],
'fixed_ips': vif_port['fixed_ips'],
'server_uuid': server.uuid}
nics_obj.objects.append(objects.ServerNic(
context, **nic_dict))
server.nics = nics_obj
server.save()
except Exception as e:
if port_id:
self.network_api.unbind_port(context, vif_port)
else:
self.network_api.delete_port(context, vif_port['id'],
server.uuid)
raise exception.InterfaceAttachFailed(message=six.text_type(e))
LOG.info('Attaching interface successfully')
@ -569,6 +591,7 @@ class EngineManager(base_manager.BaseEngineManager):
except exception.PortNotFound:
pass
@wrap_server_fault
def detach_interface(self, context, server, port_id):
LOG.debug("Detaching interface %(port_id) from server %(server)s",
{'port_id': port_id, 'server': server.uuid})

View File

@ -83,10 +83,10 @@ class EngineAPI(object):
return cctxt.call(context, 'get_serial_console',
server=server)
def attach_interface(self, context, server, net_id):
def attach_interface(self, context, server, net_id, port_id):
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
cctxt.call(context, 'attach_interface',
server=server, net_id=net_id)
server=server, net_id=net_id, port_id=port_id)
def detach_interface(self, context, server, port_id):
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)

View File

@ -23,6 +23,9 @@ from mogan.conf import CONF
LOG = logging.getLogger(__name__)
_NEUTRON_SESSION = None
BINDING_PROFILE = 'binding:profile'
BINDING_HOST_ID = 'binding:host_id'
BINDING_VNIC_TYPE = 'binding:vnic_type'
def _get_neutron_session():
@ -205,6 +208,43 @@ class API(object):
return nets
def bind_port(self, context, port, server):
client = get_client(context.auth_token)
req_body = {
'port': {
'device_id': server.uuid,
}
}
try:
port = client.update_port(port, req_body)
except neutron_exceptions.PortNotFoundClient:
LOG.debug('Unable to bind port %s as it no longer exists.', port)
except Exception:
LOG.exception("Unable to add device ID for port '%s'", port)
return port
def unbind_port(self, context, port):
client = get_client(context.auth_token)
port_req_body = {'port': {'device_id': '', 'device_owner': ''}}
if port[BINDING_HOST_ID]:
port_req_body['port'][BINDING_HOST_ID] = None
if port[BINDING_PROFILE]:
port_req_body['port'][BINDING_PROFILE] = {}
if port[BINDING_VNIC_TYPE] != 'normal':
port_req_body['port'][BINDING_VNIC_TYPE] = 'normal'
try:
port = client.update_port(port['id'], port_req_body)
except neutron_exceptions.PortNotFoundClient:
LOG.debug('Unable to unbind port %s as it no longer exists.',
port)
except Exception:
LOG.exception("Unable to clear device ID for port '%s'", port)
def check_port_availability(self, port):
if port['device_id']:
raise exception.PortInUse(port_id=port['id'])
def _get_available_ports(self, port_ids, client):
"""Return a port list available for the tenant."""

View File

@ -172,7 +172,7 @@ class BaremetalComputeAPIServersTest(base.BaseBaremetalComputeTest):
nics_before = self.baremetal_compute_client.server_get_networks(
self.server_ids[0])
self.baremetal_compute_client.server_attach_interface(
self.server_ids[0], net_id=self.net_id)
self.server_ids[0], net_id=self.net_id, port_id=None)
nics_after = self.baremetal_compute_client.server_get_networks(
self.server_ids[0])
self.assertEqual(len(nics_before) + 1, len(nics_after))

View File

@ -191,7 +191,7 @@ class BaremetalComputeClient(rest_client.RestClient):
body = self.deserialize(body)['nics']
return rest_client.ResponseBodyList(resp, body)
def server_attach_interface(self, server_id, net_id):
def server_attach_interface(self, server_id, net_id, port_id):
uri = '%s/servers/%s/networks/interfaces' % (self.uri_prefix,
server_id)
body = {"net_id": net_id}