Update CIF creation request body

The CIF API got updated in new v3 builds. Here is what changed:
1.  The information like ip, mac, vlan, host_cif_id which was
intially opaque and just provided as a key value pair inside the
context body, now have explicit properties.

2. The context now contains container_host_vif_id, and vlan_tag as
explicit properties. It still has a key_values array but no information
is needed to be passed in that. That's more reserved for future use
cases.

3. The host_vif_id property name is updated to container_host_vif_id.

4. The vlan_id property name is updated to vlan_tag.

5. The IP and mac address of the port are moved out of the context.
This was previously being duplicated as we pass that information in
address bindings already.

Here is the sample request body.

{
  "resource_type": "LogicalPort",
  "attachment": {
    "attachment_type": "CIF",
    "id": "test-2",
    "context": {
      "vlan_tag": 122,
      "container_host_vif_id": "c6f817a0-4e36-421e-98a6-8a2faed880bc",
      "key_values": [],
      "resource_type": "CifAttachmentContext"
    }
  },
  "admin_state": "UP",
  "logical_switch_id": "<logical-switch-id>",
  "address_bindings": [
    {
      "ip_address": "192.168.1.110",
      "mac_address": "aa:bb:cc:dd:ee:ff"
    }
  ],
}

This patch makes the plugin send the expected request body to the
backend.

Also this patch updates default argument in the create_port and
update_port method from parent_name to parent_vif_id

DocImpact

Change-Id: Icf9109839284df9217877342182df4dce4ca2787
This commit is contained in:
Akash Gangil 2016-07-22 07:50:15 -07:00
parent 91fecee67c
commit 47bb0a8a6c
4 changed files with 134 additions and 41 deletions

View File

@ -236,40 +236,31 @@ class LogicalPort(AbstractRESTResource):
return body
def _prepare_attachment(self, vif_uuid, parent_name, parent_tag,
def _prepare_attachment(self, vif_uuid, parent_vif_id, parent_tag,
address_bindings, attachment_type):
# NOTE(arosen): if a parent_name is specified we need to use the
# CIF's attachment.
key_values = None
if parent_name:
attachment_type = nsx_constants.ATTACHMENT_CIF
key_values = [
{'key': 'VLAN_ID', 'value': parent_tag},
{'key': 'Host_VIF_ID', 'value': parent_name},
{'key': 'IP', 'value': address_bindings[0].ip_address},
{'key': 'MAC', 'value': address_bindings[0].mac_address}]
# NOTE(arosen): The above api body structure might change
# in the future
if attachment_type and vif_uuid:
attachment = {'attachment_type': attachment_type,
'id': vif_uuid}
if key_values:
attachment['context'] = {'key_values': key_values}
attachment['context']['resource_type'] = \
nsx_constants.CIF_RESOURCE_TYPE
if parent_vif_id:
context = {'vlan_tag': parent_tag,
'container_host_vif_id': parent_vif_id,
'resource_type': nsx_constants.CIF_RESOURCE_TYPE}
attachment['context'] = context
return attachment
def create(self, lswitch_id, vif_uuid, tags=None,
attachment_type=nsx_constants.ATTACHMENT_VIF,
admin_state=True, name=None, address_bindings=None,
parent_name=None, parent_tag=None,
parent_vif_id=None, parent_tag=None,
switch_profile_ids=None):
tags = tags or []
body = {'logical_switch_id': lswitch_id}
attachment = self._prepare_attachment(vif_uuid, parent_name,
# NOTE(arosen): If parent_vif_id is specified we need to use
# CIF attachment type.
if parent_vif_id:
attachment_type = nsx_constants.ATTACHMENT_CIF
attachment = self._prepare_attachment(vif_uuid, parent_vif_id,
parent_tag, address_bindings,
attachment_type)
body.update(self._build_body_attrs(
@ -294,12 +285,12 @@ class LogicalPort(AbstractRESTResource):
address_bindings=None, switch_profile_ids=None,
tags_update=None,
attachment_type=nsx_constants.ATTACHMENT_VIF,
parent_name=None, parent_tag=None):
parent_vif_id=None, parent_tag=None):
lport = self.get(lport_id)
tags = lport.get('tags', [])
if tags_update:
tags = utils.update_v3_tags(tags, tags_update)
attachment = self._prepare_attachment(vif_uuid, parent_name,
attachment = self._prepare_attachment(vif_uuid, parent_vif_id,
parent_tag, address_bindings,
attachment_type)
lport.update(self._build_body_attrs(

View File

@ -1245,7 +1245,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
admin_state=port_data['admin_state_up'],
address_bindings=address_bindings,
attachment_type=attachment_type,
parent_name=parent_name, parent_tag=tag,
parent_vif_id=parent_name, parent_tag=tag,
switch_profile_ids=profiles)
except nsx_exc.ManagerError as inst:
# we may fail if the QoS is not supported for this port
@ -1754,7 +1754,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
updated_device_id)
vif_uuid = updated_port['id']
parent_name, tag = self._get_data_from_binding_profile(
parent_vif_id, tag = self._get_data_from_binding_profile(
context, updated_port)
attachment_type = nsx_constants.ATTACHMENT_VIF
if (not updated_device_owner or
@ -1803,7 +1803,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
address_bindings=address_bindings,
switch_profile_ids=switch_profile_ids,
tags_update=tags_update,
parent_name=parent_name,
parent_vif_id=parent_vif_id,
parent_tag=tag)
except nsx_exc.ManagerError as inst:
# we may fail if the QoS is not supported for this port

View File

@ -56,6 +56,52 @@ FAKE_PORT = {
]
}
FAKE_CONTAINER_PORT = {
"id": FAKE_PORT_UUID,
"display_name": FAKE_NAME,
"resource_type": "LogicalPort",
"address_bindings": [
{
"ip_address": "192.168.1.110",
"mac_address": "aa:bb:cc:dd:ee:ff"
}
],
"logical_switch_id": FAKE_SWITCH_UUID,
"admin_state": "UP",
"attachment": {
"id": "9ca8d413-f7bf-4276-b4c9-62f42516bdb2",
"attachment_type": "CIF",
"context": {
"vlan_tag": 122,
"container_host_vif_id": "c6f817a0-4e36-421e-98a6-8a2faed880bc",
"key_values": [],
"resource_type": "CifAttachmentContext",
}
},
"switching_profile_ids": [
{
"value": "64814784-7896-3901-9741-badeff705639",
"key": "IpDiscoverySwitchingProfile"
},
{
"value": "fad98876-d7ff-11e4-b9d6-1681e6b88ec1",
"key": "SpoofGuardSwitchingProfile"
},
{
"value": "93b4b7e8-f116-415d-a50c-3364611b5d09",
"key": "PortMirroringSwitchingProfile"
},
{
"value": "fbc4fb17-83d9-4b53-a286-ccdf04301888",
"key": "SwitchSecuritySwitchingProfile"
},
{
"value": "f313290b-eba8-4262-bd93-fab5026e9495",
"key": "QosSwitchingProfile"
}
]
}
FAKE_QOS_PROFILE = {
"resource_type": "QosSwitchingProfile",
"id": uuidutils.generate_uuid(),

View File

@ -235,28 +235,36 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase):
return self.mocked_resource(
resources.LogicalPort, session_response=session_response)
def _get_profile_dicts(self, fake_port):
fake_profile_dicts = []
for profile_id in fake_port['switching_profile_ids']:
fake_profile_dicts.append({'resource_type': profile_id['key'],
'id': profile_id['value']})
return fake_profile_dicts
def _get_pktcls_bindings(self):
fake_pkt_classifiers = []
fake_binding_repr = []
for i in range(0, 3):
ip = "9.10.11.%s" % i
mac = "00:0c:29:35:4a:%sc" % i
fake_pkt_classifiers.append(resources.PacketAddressClassifier(
ip, mac, None))
fake_binding_repr.append({
'ip_address': ip,
'mac_address': mac
})
return fake_pkt_classifiers, fake_binding_repr
def test_create_logical_port(self):
"""
Test creating a port returns the correct response and 200 status
"""
fake_port = test_constants_v3.FAKE_PORT.copy()
profile_dicts = []
for profile_id in fake_port['switching_profile_ids']:
profile_dicts.append({'resource_type': profile_id['key'],
'id': profile_id['value']})
profile_dicts = self._get_profile_dicts(fake_port)
pkt_classifiers = []
binding_repr = []
for i in range(0, 3):
ip = "9.10.11.%s" % i
mac = "00:0c:29:35:4a:%sc" % i
pkt_classifiers.append(resources.PacketAddressClassifier(
ip, mac, None))
binding_repr.append({
'ip_address': ip,
'mac_address': mac
})
pkt_classifiers, binding_repr = self._get_pktcls_bindings()
fake_port['address_bindings'] = binding_repr
@ -286,6 +294,54 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase):
'https://1.2.3.4/api/v1/logical-ports',
data=jsonutils.dumps(resp_body, sort_keys=True))
def test_create_logical_port_with_attachtype_cif(self):
"""
Test creating a port returns the correct response and 200 status
"""
fake_port = test_constants_v3.FAKE_CONTAINER_PORT.copy()
profile_dicts = self._get_profile_dicts(fake_port)
pkt_classifiers, binding_repr = self._get_pktcls_bindings()
fake_port['address_bindings'] = binding_repr
mocked_resource = self._mocked_lport()
switch_profile = resources.SwitchingProfile
fake_port_ctx = fake_port['attachment']['context']
fake_container_host_vif_id = fake_port_ctx['container_host_vif_id']
mocked_resource.create(
fake_port['logical_switch_id'],
fake_port['attachment']['id'],
parent_vif_id=fake_container_host_vif_id,
parent_tag=fake_port_ctx['vlan_tag'],
address_bindings=pkt_classifiers,
switch_profile_ids=switch_profile.build_switch_profile_ids(
mock.Mock(), *profile_dicts))
resp_body = {
'logical_switch_id': fake_port['logical_switch_id'],
'switching_profile_ids': fake_port['switching_profile_ids'],
'attachment': {
'attachment_type': 'CIF',
'id': fake_port['attachment']['id'],
'context': {
'vlan_tag': fake_port_ctx['vlan_tag'],
'container_host_vif_id': fake_container_host_vif_id,
'resource_type': 'CifAttachmentContext'
}
},
'admin_state': 'UP',
'address_bindings': fake_port['address_bindings']
}
test_client.assert_json_call(
'post', mocked_resource,
'https://1.2.3.4/api/v1/logical-ports',
data=jsonutils.dumps(resp_body, sort_keys=True))
def test_create_logical_port_admin_down(self):
"""
Test creating port with admin_state down