bf40933099
Blueprint nvp-distributed-router This patch adds support for NVP distributed logical routers adding a simple attribute extension. The default router type can be controlled used the default_router_type option in the nvp section of neutron configuration. In order to ensure backward compatibility, pre-existing routers will be treated as centralized routers. Change-Id: Iaab9ffb6071c93990be711ebb56c212230544a7a
617 lines
26 KiB
Python
617 lines
26 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2012 Nicira Networks, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import json
|
|
import urlparse
|
|
|
|
from neutron.openstack.common import log as logging
|
|
from neutron.openstack.common import uuidutils
|
|
from neutron.plugins.nicira import NvpApiClient
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
MAX_NAME_LEN = 40
|
|
|
|
|
|
def _validate_name(name):
|
|
if name and len(name) > MAX_NAME_LEN:
|
|
raise Exception("Logical switch name exceeds %d characters",
|
|
MAX_NAME_LEN)
|
|
|
|
|
|
def _validate_resource(body):
|
|
_validate_name(body.get('display_name'))
|
|
|
|
|
|
class FakeClient:
|
|
|
|
LSWITCH_RESOURCE = 'lswitch'
|
|
LPORT_RESOURCE = 'lport'
|
|
LROUTER_RESOURCE = 'lrouter'
|
|
NAT_RESOURCE = 'nat'
|
|
LQUEUE_RESOURCE = 'lqueue'
|
|
SECPROF_RESOURCE = 'securityprofile'
|
|
LSWITCH_STATUS = 'lswitchstatus'
|
|
LROUTER_STATUS = 'lrouterstatus'
|
|
LSWITCH_LPORT_RESOURCE = 'lswitch_lport'
|
|
LROUTER_LPORT_RESOURCE = 'lrouter_lport'
|
|
LROUTER_NAT_RESOURCE = 'lrouter_nat'
|
|
LSWITCH_LPORT_STATUS = 'lswitch_lportstatus'
|
|
LSWITCH_LPORT_ATT = 'lswitch_lportattachment'
|
|
LROUTER_LPORT_STATUS = 'lrouter_lportstatus'
|
|
LROUTER_LPORT_ATT = 'lrouter_lportattachment'
|
|
GWSERVICE_RESOURCE = 'gatewayservice'
|
|
|
|
RESOURCES = [LSWITCH_RESOURCE, LROUTER_RESOURCE, LQUEUE_RESOURCE,
|
|
LPORT_RESOURCE, NAT_RESOURCE, SECPROF_RESOURCE,
|
|
GWSERVICE_RESOURCE]
|
|
|
|
FAKE_GET_RESPONSES = {
|
|
LSWITCH_RESOURCE: "fake_get_lswitch.json",
|
|
LSWITCH_LPORT_RESOURCE: "fake_get_lswitch_lport.json",
|
|
LSWITCH_LPORT_STATUS: "fake_get_lswitch_lport_status.json",
|
|
LSWITCH_LPORT_ATT: "fake_get_lswitch_lport_att.json",
|
|
LROUTER_RESOURCE: "fake_get_lrouter.json",
|
|
LROUTER_LPORT_RESOURCE: "fake_get_lrouter_lport.json",
|
|
LROUTER_LPORT_STATUS: "fake_get_lrouter_lport_status.json",
|
|
LROUTER_LPORT_ATT: "fake_get_lrouter_lport_att.json",
|
|
LROUTER_STATUS: "fake_get_lrouter_status.json",
|
|
LROUTER_NAT_RESOURCE: "fake_get_lrouter_nat.json",
|
|
SECPROF_RESOURCE: "fake_get_security_profile.json",
|
|
LQUEUE_RESOURCE: "fake_get_lqueue.json",
|
|
GWSERVICE_RESOURCE: "fake_get_gwservice.json"
|
|
}
|
|
|
|
FAKE_POST_RESPONSES = {
|
|
LSWITCH_RESOURCE: "fake_post_lswitch.json",
|
|
LROUTER_RESOURCE: "fake_post_lrouter.json",
|
|
LSWITCH_LPORT_RESOURCE: "fake_post_lswitch_lport.json",
|
|
LROUTER_LPORT_RESOURCE: "fake_post_lrouter_lport.json",
|
|
LROUTER_NAT_RESOURCE: "fake_post_lrouter_nat.json",
|
|
SECPROF_RESOURCE: "fake_post_security_profile.json",
|
|
LQUEUE_RESOURCE: "fake_post_lqueue.json",
|
|
GWSERVICE_RESOURCE: "fake_post_gwservice.json"
|
|
}
|
|
|
|
FAKE_PUT_RESPONSES = {
|
|
LSWITCH_RESOURCE: "fake_post_lswitch.json",
|
|
LROUTER_RESOURCE: "fake_post_lrouter.json",
|
|
LSWITCH_LPORT_RESOURCE: "fake_post_lswitch_lport.json",
|
|
LROUTER_LPORT_RESOURCE: "fake_post_lrouter_lport.json",
|
|
LROUTER_NAT_RESOURCE: "fake_post_lrouter_nat.json",
|
|
LSWITCH_LPORT_ATT: "fake_put_lswitch_lport_att.json",
|
|
LROUTER_LPORT_ATT: "fake_put_lrouter_lport_att.json",
|
|
SECPROF_RESOURCE: "fake_post_security_profile.json",
|
|
LQUEUE_RESOURCE: "fake_post_lqueue.json",
|
|
GWSERVICE_RESOURCE: "fake_post_gwservice.json"
|
|
}
|
|
|
|
MANAGED_RELATIONS = {
|
|
LSWITCH_RESOURCE: [],
|
|
LROUTER_RESOURCE: [],
|
|
LSWITCH_LPORT_RESOURCE: ['LogicalPortAttachment'],
|
|
LROUTER_LPORT_RESOURCE: ['LogicalPortAttachment'],
|
|
}
|
|
|
|
_fake_lswitch_dict = {}
|
|
_fake_lrouter_dict = {}
|
|
_fake_lswitch_lport_dict = {}
|
|
_fake_lrouter_lport_dict = {}
|
|
_fake_lrouter_nat_dict = {}
|
|
_fake_lswitch_lportstatus_dict = {}
|
|
_fake_lrouter_lportstatus_dict = {}
|
|
_fake_securityprofile_dict = {}
|
|
_fake_lqueue_dict = {}
|
|
_fake_gatewayservice_dict = {}
|
|
|
|
_validators = {
|
|
LSWITCH_RESOURCE: _validate_resource,
|
|
LSWITCH_LPORT_RESOURCE: _validate_resource,
|
|
LROUTER_LPORT_RESOURCE: _validate_resource,
|
|
SECPROF_RESOURCE: _validate_resource,
|
|
LQUEUE_RESOURCE: _validate_resource,
|
|
GWSERVICE_RESOURCE: _validate_resource
|
|
}
|
|
|
|
def __init__(self, fake_files_path):
|
|
self.fake_files_path = fake_files_path
|
|
|
|
def _get_tag(self, resource, scope):
|
|
tags = [tag['tag'] for tag in resource['tags']
|
|
if tag['scope'] == scope]
|
|
return len(tags) > 0 and tags[0]
|
|
|
|
def _get_filters(self, querystring):
|
|
if not querystring:
|
|
return (None, None)
|
|
params = urlparse.parse_qs(querystring)
|
|
tag_filter = None
|
|
attr_filter = None
|
|
if 'tag' in params and 'tag_scope' in params:
|
|
tag_filter = {'scope': params['tag_scope'][0],
|
|
'tag': params['tag'][0]}
|
|
elif 'uuid' in params:
|
|
attr_filter = {'uuid': params['uuid'][0]}
|
|
return (tag_filter, attr_filter)
|
|
|
|
def _add_lswitch(self, body):
|
|
fake_lswitch = json.loads(body)
|
|
fake_lswitch['uuid'] = uuidutils.generate_uuid()
|
|
self._fake_lswitch_dict[fake_lswitch['uuid']] = fake_lswitch
|
|
# put the tenant_id and the zone_uuid in the main dict
|
|
# for simplyfying templating
|
|
zone_uuid = fake_lswitch['transport_zones'][0]['zone_uuid']
|
|
fake_lswitch['zone_uuid'] = zone_uuid
|
|
fake_lswitch['tenant_id'] = self._get_tag(fake_lswitch, 'os_tid')
|
|
fake_lswitch['lport_count'] = 0
|
|
return fake_lswitch
|
|
|
|
def _build_lrouter(self, body, uuid=None):
|
|
fake_lrouter = json.loads(body)
|
|
if uuid:
|
|
fake_lrouter['uuid'] = uuid
|
|
fake_lrouter['tenant_id'] = self._get_tag(fake_lrouter, 'os_tid')
|
|
default_nexthop = fake_lrouter['routing_config'].get(
|
|
'default_route_next_hop')
|
|
fake_lrouter['default_next_hop'] = default_nexthop.get(
|
|
'gateway_ip_address', '0.0.0.0')
|
|
# NOTE(salv-orlando): We won't make the Fake NVP API client
|
|
# aware of NVP version. The long term plan is to replace it
|
|
# with behavioral mocking of NVP API requests
|
|
if 'distributed' not in fake_lrouter:
|
|
fake_lrouter['distributed'] = False
|
|
distributed_json = ('"distributed": %s,' %
|
|
str(fake_lrouter['distributed']).lower())
|
|
fake_lrouter['distributed_json'] = distributed_json
|
|
return fake_lrouter
|
|
|
|
def _add_lrouter(self, body):
|
|
fake_lrouter = self._build_lrouter(body,
|
|
uuidutils.generate_uuid())
|
|
self._fake_lrouter_dict[fake_lrouter['uuid']] = fake_lrouter
|
|
fake_lrouter['lport_count'] = 0
|
|
return fake_lrouter
|
|
|
|
def _add_lqueue(self, body):
|
|
fake_lqueue = json.loads(body)
|
|
fake_lqueue['uuid'] = uuidutils.generate_uuid()
|
|
self._fake_lqueue_dict[fake_lqueue['uuid']] = fake_lqueue
|
|
return fake_lqueue
|
|
|
|
def _add_lswitch_lport(self, body, ls_uuid):
|
|
fake_lport = json.loads(body)
|
|
new_uuid = uuidutils.generate_uuid()
|
|
fake_lport['uuid'] = new_uuid
|
|
# put the tenant_id and the ls_uuid in the main dict
|
|
# for simplyfying templating
|
|
fake_lport['ls_uuid'] = ls_uuid
|
|
fake_lport['tenant_id'] = self._get_tag(fake_lport, 'os_tid')
|
|
fake_lport['neutron_port_id'] = self._get_tag(fake_lport,
|
|
'q_port_id')
|
|
fake_lport['neutron_device_id'] = self._get_tag(fake_lport, 'vm_id')
|
|
fake_lport['att_type'] = "NoAttachment"
|
|
fake_lport['att_info_json'] = ''
|
|
self._fake_lswitch_lport_dict[fake_lport['uuid']] = fake_lport
|
|
|
|
fake_lswitch = self._fake_lswitch_dict[ls_uuid]
|
|
fake_lswitch['lport_count'] += 1
|
|
fake_lport_status = fake_lport.copy()
|
|
fake_lport_status['ls_tenant_id'] = fake_lswitch['tenant_id']
|
|
fake_lport_status['ls_uuid'] = fake_lswitch['uuid']
|
|
fake_lport_status['ls_name'] = fake_lswitch['display_name']
|
|
fake_lport_status['ls_zone_uuid'] = fake_lswitch['zone_uuid']
|
|
self._fake_lswitch_lportstatus_dict[new_uuid] = fake_lport_status
|
|
return fake_lport
|
|
|
|
def _build_lrouter_lport(self, body, new_uuid=None, lr_uuid=None):
|
|
fake_lport = json.loads(body)
|
|
if new_uuid:
|
|
fake_lport['uuid'] = new_uuid
|
|
# put the tenant_id and the le_uuid in the main dict
|
|
# for simplyfying templating
|
|
if lr_uuid:
|
|
fake_lport['lr_uuid'] = lr_uuid
|
|
fake_lport['tenant_id'] = self._get_tag(fake_lport, 'os_tid')
|
|
fake_lport['neutron_port_id'] = self._get_tag(fake_lport,
|
|
'q_port_id')
|
|
# replace ip_address with its json dump
|
|
if 'ip_addresses' in fake_lport:
|
|
ip_addresses_json = json.dumps(fake_lport['ip_addresses'])
|
|
fake_lport['ip_addresses_json'] = ip_addresses_json
|
|
return fake_lport
|
|
|
|
def _add_lrouter_lport(self, body, lr_uuid):
|
|
new_uuid = uuidutils.generate_uuid()
|
|
fake_lport = self._build_lrouter_lport(body, new_uuid, lr_uuid)
|
|
self._fake_lrouter_lport_dict[fake_lport['uuid']] = fake_lport
|
|
try:
|
|
fake_lrouter = self._fake_lrouter_dict[lr_uuid]
|
|
except KeyError:
|
|
raise NvpApiClient.ResourceNotFound()
|
|
fake_lrouter['lport_count'] += 1
|
|
fake_lport_status = fake_lport.copy()
|
|
fake_lport_status['lr_tenant_id'] = fake_lrouter['tenant_id']
|
|
fake_lport_status['lr_uuid'] = fake_lrouter['uuid']
|
|
fake_lport_status['lr_name'] = fake_lrouter['display_name']
|
|
self._fake_lrouter_lportstatus_dict[new_uuid] = fake_lport_status
|
|
return fake_lport
|
|
|
|
def _add_securityprofile(self, body):
|
|
fake_securityprofile = json.loads(body)
|
|
fake_securityprofile['uuid'] = uuidutils.generate_uuid()
|
|
fake_securityprofile['tenant_id'] = self._get_tag(
|
|
fake_securityprofile, 'os_tid')
|
|
|
|
fake_securityprofile['nova_spid'] = self._get_tag(fake_securityprofile,
|
|
'nova_spid')
|
|
self._fake_securityprofile_dict[fake_securityprofile['uuid']] = (
|
|
fake_securityprofile)
|
|
return fake_securityprofile
|
|
|
|
def _add_lrouter_nat(self, body, lr_uuid):
|
|
fake_nat = json.loads(body)
|
|
new_uuid = uuidutils.generate_uuid()
|
|
fake_nat['uuid'] = new_uuid
|
|
fake_nat['lr_uuid'] = lr_uuid
|
|
self._fake_lrouter_nat_dict[fake_nat['uuid']] = fake_nat
|
|
if 'match' in fake_nat:
|
|
match_json = json.dumps(fake_nat['match'])
|
|
fake_nat['match_json'] = match_json
|
|
return fake_nat
|
|
|
|
def _add_gatewayservice(self, body):
|
|
fake_gwservice = json.loads(body)
|
|
fake_gwservice['uuid'] = str(uuidutils.generate_uuid())
|
|
fake_gwservice['tenant_id'] = self._get_tag(
|
|
fake_gwservice, 'os_tid')
|
|
# FIXME(salvatore-orlando): For simplicity we're managing only a
|
|
# single device. Extend the fake client for supporting multiple devices
|
|
first_gw = fake_gwservice['gateways'][0]
|
|
fake_gwservice['transport_node_uuid'] = first_gw['transport_node_uuid']
|
|
fake_gwservice['device_id'] = first_gw['device_id']
|
|
self._fake_gatewayservice_dict[fake_gwservice['uuid']] = (
|
|
fake_gwservice)
|
|
return fake_gwservice
|
|
|
|
def _build_relation(self, src, dst, resource_type, relation):
|
|
if relation not in self.MANAGED_RELATIONS[resource_type]:
|
|
return # Relation is not desired in output
|
|
if not '_relations' in src or not src['_relations'].get(relation):
|
|
return # Item does not have relation
|
|
relation_data = src['_relations'].get(relation)
|
|
dst_relations = dst.get('_relations', {})
|
|
dst_relations[relation] = relation_data
|
|
dst['_relations'] = dst_relations
|
|
|
|
def _fill_attachment(self, att_data, ls_uuid=None,
|
|
lr_uuid=None, lp_uuid=None):
|
|
new_data = att_data.copy()
|
|
for k in ('ls_uuid', 'lr_uuid', 'lp_uuid'):
|
|
if locals().get(k):
|
|
new_data[k] = locals()[k]
|
|
|
|
def populate_field(field_name):
|
|
if field_name in att_data:
|
|
new_data['%s_field' % field_name] = ('"%s" : "%s",'
|
|
% (field_name,
|
|
att_data[field_name]))
|
|
del new_data[field_name]
|
|
else:
|
|
new_data['%s_field' % field_name] = ""
|
|
|
|
for field in ['vif_uuid', 'peer_port_href', 'vlan_id',
|
|
'peer_port_uuid', 'l3_gateway_service_uuid']:
|
|
populate_field(field)
|
|
return new_data
|
|
|
|
def _get_resource_type(self, path):
|
|
"""Get resource type.
|
|
|
|
Identifies resource type and relevant uuids in the uri
|
|
|
|
/ws.v1/lswitch/xxx
|
|
/ws.v1/lswitch/xxx/status
|
|
/ws.v1/lswitch/xxx/lport/yyy
|
|
/ws.v1/lswitch/xxx/lport/yyy/status
|
|
/ws.v1/lrouter/zzz
|
|
/ws.v1/lrouter/zzz/status
|
|
/ws.v1/lrouter/zzz/lport/www
|
|
/ws.v1/lrouter/zzz/lport/www/status
|
|
/ws.v1/lqueue/xxx
|
|
"""
|
|
# The first element will always be 'ws.v1' - so we just discard it
|
|
uri_split = path.split('/')[1:]
|
|
# parse uri_split backwards
|
|
suffix = ""
|
|
idx = len(uri_split) - 1
|
|
if 'status' in uri_split[idx]:
|
|
suffix = "status"
|
|
idx = idx - 1
|
|
elif 'attachment' in uri_split[idx]:
|
|
suffix = "attachment"
|
|
idx = idx - 1
|
|
# then check if we have an uuid
|
|
uuids = []
|
|
if uri_split[idx].replace('-', '') not in self.RESOURCES:
|
|
uuids.append(uri_split[idx])
|
|
idx = idx - 1
|
|
resource_type = "%s%s" % (uri_split[idx], suffix)
|
|
if idx > 1:
|
|
uuids.insert(0, uri_split[idx - 1])
|
|
resource_type = "%s_%s" % (uri_split[idx - 2], resource_type)
|
|
return (resource_type.replace('-', ''), uuids)
|
|
|
|
def _list(self, resource_type, response_file,
|
|
parent_uuid=None, query=None, relations=None):
|
|
(tag_filter, attr_filter) = self._get_filters(query)
|
|
with open("%s/%s" % (self.fake_files_path, response_file)) as f:
|
|
response_template = f.read()
|
|
res_dict = getattr(self, '_fake_%s_dict' % resource_type)
|
|
if parent_uuid == '*':
|
|
parent_uuid = None
|
|
|
|
def _attr_match(res_uuid):
|
|
if not attr_filter:
|
|
return True
|
|
item = res_dict[res_uuid]
|
|
for (attr, value) in attr_filter.iteritems():
|
|
if item.get(attr) != value:
|
|
return False
|
|
return True
|
|
|
|
def _tag_match(res_uuid):
|
|
if not tag_filter:
|
|
return True
|
|
return any([x['scope'] == tag_filter['scope'] and
|
|
x['tag'] == tag_filter['tag']
|
|
for x in res_dict[res_uuid]['tags']])
|
|
|
|
def _lswitch_match(res_uuid):
|
|
# verify that the switch exist
|
|
if parent_uuid and not parent_uuid in self._fake_lswitch_dict:
|
|
raise Exception(_("lswitch:%s not found") % parent_uuid)
|
|
if (not parent_uuid
|
|
or res_dict[res_uuid].get('ls_uuid') == parent_uuid):
|
|
return True
|
|
return False
|
|
|
|
def _lrouter_match(res_uuid):
|
|
# verify that the router exist
|
|
if parent_uuid and not parent_uuid in self._fake_lrouter_dict:
|
|
raise Exception(_("lrouter:%s not found") % parent_uuid)
|
|
if (not parent_uuid or
|
|
res_dict[res_uuid].get('lr_uuid') == parent_uuid):
|
|
return True
|
|
return False
|
|
|
|
def _build_item(resource):
|
|
item = json.loads(response_template % resource)
|
|
if relations:
|
|
for relation in relations:
|
|
self._build_relation(resource, item,
|
|
resource_type, relation)
|
|
return item
|
|
|
|
for item in res_dict.itervalues():
|
|
if 'tags' in item:
|
|
item['tags_json'] = json.dumps(item['tags'])
|
|
if resource_type in (self.LSWITCH_LPORT_RESOURCE,
|
|
self.LSWITCH_LPORT_ATT,
|
|
self.LSWITCH_LPORT_STATUS):
|
|
parent_func = _lswitch_match
|
|
elif resource_type in (self.LROUTER_LPORT_RESOURCE,
|
|
self.LROUTER_LPORT_ATT,
|
|
self.LROUTER_NAT_RESOURCE,
|
|
self.LROUTER_LPORT_STATUS):
|
|
parent_func = _lrouter_match
|
|
else:
|
|
parent_func = lambda x: True
|
|
|
|
items = [_build_item(res_dict[res_uuid])
|
|
for res_uuid in res_dict
|
|
if (parent_func(res_uuid) and
|
|
_tag_match(res_uuid) and
|
|
_attr_match(res_uuid))]
|
|
return json.dumps({'results': items,
|
|
'result_count': len(items)})
|
|
|
|
def _show(self, resource_type, response_file,
|
|
uuid1, uuid2=None, relations=None):
|
|
target_uuid = uuid2 or uuid1
|
|
if resource_type.endswith('attachment'):
|
|
resource_type = resource_type[:resource_type.index('attachment')]
|
|
with open("%s/%s" % (self.fake_files_path, response_file)) as f:
|
|
response_template = f.read()
|
|
res_dict = getattr(self, '_fake_%s_dict' % resource_type)
|
|
for item in res_dict.itervalues():
|
|
if 'tags' in item:
|
|
item['tags_json'] = json.dumps(item['tags'])
|
|
|
|
# replace sec prof rules with their json dump
|
|
def jsonify_rules(rule_key):
|
|
if rule_key in item:
|
|
rules_json = json.dumps(item[rule_key])
|
|
item['%s_json' % rule_key] = rules_json
|
|
jsonify_rules('logical_port_egress_rules')
|
|
jsonify_rules('logical_port_ingress_rules')
|
|
|
|
items = [json.loads(response_template % res_dict[res_uuid])
|
|
for res_uuid in res_dict if res_uuid == target_uuid]
|
|
if items:
|
|
return json.dumps(items[0])
|
|
raise NvpApiClient.ResourceNotFound()
|
|
|
|
def handle_get(self, url):
|
|
#TODO(salvatore-orlando): handle field selection
|
|
parsedurl = urlparse.urlparse(url)
|
|
(res_type, uuids) = self._get_resource_type(parsedurl.path)
|
|
relations = urlparse.parse_qs(parsedurl.query).get('relations')
|
|
response_file = self.FAKE_GET_RESPONSES.get(res_type)
|
|
if not response_file:
|
|
raise NvpApiClient.NvpApiException()
|
|
if 'lport' in res_type or 'nat' in res_type:
|
|
if len(uuids) > 1:
|
|
return self._show(res_type, response_file, uuids[0],
|
|
uuids[1], relations=relations)
|
|
else:
|
|
return self._list(res_type, response_file, uuids[0],
|
|
query=parsedurl.query, relations=relations)
|
|
elif ('lswitch' in res_type or
|
|
'lrouter' in res_type or
|
|
self.SECPROF_RESOURCE in res_type or
|
|
self.LQUEUE_RESOURCE in res_type or
|
|
'gatewayservice' in res_type):
|
|
LOG.debug("UUIDS:%s", uuids)
|
|
if uuids:
|
|
return self._show(res_type, response_file, uuids[0],
|
|
relations=relations)
|
|
else:
|
|
return self._list(res_type, response_file,
|
|
query=parsedurl.query,
|
|
relations=relations)
|
|
else:
|
|
raise Exception("unknown resource:%s" % res_type)
|
|
|
|
def handle_post(self, url, body):
|
|
parsedurl = urlparse.urlparse(url)
|
|
(res_type, uuids) = self._get_resource_type(parsedurl.path)
|
|
response_file = self.FAKE_POST_RESPONSES.get(res_type)
|
|
if not response_file:
|
|
raise Exception("resource not found")
|
|
with open("%s/%s" % (self.fake_files_path, response_file)) as f:
|
|
response_template = f.read()
|
|
add_resource = getattr(self, '_add_%s' % res_type)
|
|
body_json = json.loads(body)
|
|
val_func = self._validators.get(res_type)
|
|
if val_func:
|
|
val_func(body_json)
|
|
args = [body]
|
|
if uuids:
|
|
args.append(uuids[0])
|
|
response = response_template % add_resource(*args)
|
|
return response
|
|
|
|
def handle_put(self, url, body):
|
|
parsedurl = urlparse.urlparse(url)
|
|
(res_type, uuids) = self._get_resource_type(parsedurl.path)
|
|
response_file = self.FAKE_PUT_RESPONSES.get(res_type)
|
|
if not response_file:
|
|
raise Exception("resource not found")
|
|
with open("%s/%s" % (self.fake_files_path, response_file)) as f:
|
|
response_template = f.read()
|
|
# Manage attachment operations
|
|
is_attachment = False
|
|
if res_type.endswith('attachment'):
|
|
is_attachment = True
|
|
res_type = res_type[:res_type.index('attachment')]
|
|
res_dict = getattr(self, '_fake_%s_dict' % res_type)
|
|
body_json = json.loads(body)
|
|
val_func = self._validators.get(res_type)
|
|
if val_func:
|
|
val_func(body_json)
|
|
try:
|
|
resource = res_dict[uuids[-1]]
|
|
except KeyError:
|
|
raise NvpApiClient.ResourceNotFound()
|
|
if not is_attachment:
|
|
edit_resource = getattr(self, '_build_%s' % res_type, None)
|
|
if edit_resource:
|
|
body_json = edit_resource(body)
|
|
resource.update(body_json)
|
|
else:
|
|
relations = resource.get("_relations", {})
|
|
body_2 = json.loads(body)
|
|
resource['att_type'] = body_2['type']
|
|
relations['LogicalPortAttachment'] = body_2
|
|
resource['_relations'] = relations
|
|
if body_2['type'] == "PatchAttachment":
|
|
# We need to do a trick here
|
|
if self.LROUTER_RESOURCE in res_type:
|
|
res_type_2 = res_type.replace(self.LROUTER_RESOURCE,
|
|
self.LSWITCH_RESOURCE)
|
|
elif self.LSWITCH_RESOURCE in res_type:
|
|
res_type_2 = res_type.replace(self.LSWITCH_RESOURCE,
|
|
self.LROUTER_RESOURCE)
|
|
res_dict_2 = getattr(self, '_fake_%s_dict' % res_type_2)
|
|
body_2['peer_port_uuid'] = uuids[-1]
|
|
resource_2 = res_dict_2[json.loads(body)['peer_port_uuid']]
|
|
relations_2 = resource_2.get("_relations")
|
|
if not relations_2:
|
|
relations_2 = {}
|
|
relations_2['LogicalPortAttachment'] = body_2
|
|
resource_2['_relations'] = relations_2
|
|
resource['peer_port_uuid'] = body_2['peer_port_uuid']
|
|
resource['att_info_json'] = (
|
|
"\"peer_port_uuid\": \"%s\"," %
|
|
resource_2['uuid'])
|
|
resource_2['att_info_json'] = (
|
|
"\"peer_port_uuid\": \"%s\"," %
|
|
body_2['peer_port_uuid'])
|
|
elif body_2['type'] == "L3GatewayAttachment":
|
|
resource['attachment_gwsvc_uuid'] = (
|
|
body_2['l3_gateway_service_uuid'])
|
|
resource['vlan_id'] = body_2.get('vlan_id')
|
|
elif body_2['type'] == "L2GatewayAttachment":
|
|
resource['attachment_gwsvc_uuid'] = (
|
|
body_2['l2_gateway_service_uuid'])
|
|
elif body_2['type'] == "VifAttachment":
|
|
resource['vif_uuid'] = body_2['vif_uuid']
|
|
resource['att_info_json'] = (
|
|
"\"vif_uuid\": \"%s\"," % body_2['vif_uuid'])
|
|
|
|
if not is_attachment:
|
|
response = response_template % resource
|
|
else:
|
|
if res_type == self.LROUTER_LPORT_RESOURCE:
|
|
lr_uuid = uuids[0]
|
|
ls_uuid = None
|
|
elif res_type == self.LSWITCH_LPORT_RESOURCE:
|
|
ls_uuid = uuids[0]
|
|
lr_uuid = None
|
|
lp_uuid = uuids[1]
|
|
response = response_template % self._fill_attachment(
|
|
json.loads(body), ls_uuid, lr_uuid, lp_uuid)
|
|
return response
|
|
|
|
def handle_delete(self, url):
|
|
parsedurl = urlparse.urlparse(url)
|
|
(res_type, uuids) = self._get_resource_type(parsedurl.path)
|
|
response_file = self.FAKE_PUT_RESPONSES.get(res_type)
|
|
if not response_file:
|
|
raise Exception("resource not found")
|
|
res_dict = getattr(self, '_fake_%s_dict' % res_type)
|
|
try:
|
|
del res_dict[uuids[-1]]
|
|
except KeyError:
|
|
raise NvpApiClient.ResourceNotFound()
|
|
return ""
|
|
|
|
def fake_request(self, *args, **kwargs):
|
|
method = args[0]
|
|
handler = getattr(self, "handle_%s" % method.lower())
|
|
return handler(*args[1:])
|
|
|
|
def reset_all(self):
|
|
self._fake_lswitch_dict.clear()
|
|
self._fake_lrouter_dict.clear()
|
|
self._fake_lswitch_lport_dict.clear()
|
|
self._fake_lrouter_lport_dict.clear()
|
|
self._fake_lswitch_lportstatus_dict.clear()
|
|
self._fake_lrouter_lportstatus_dict.clear()
|
|
self._fake_lqueue_dict.clear()
|
|
self._fake_securityprofile_dict.clear()
|
|
self._fake_gatewayservice_dict.clear()
|