# 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'],
    }

    _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
        self._fake_lswitch_dict = {}
        self._fake_lrouter_dict = {}
        self._fake_lswitch_lport_dict = {}
        self._fake_lrouter_lport_dict = {}
        self._fake_lrouter_nat_dict = {}
        self._fake_lswitch_lportstatus_dict = {}
        self._fake_lrouter_lportstatus_dict = {}
        self._fake_securityprofile_dict = {}
        self._fake_lqueue_dict = {}
        self._fake_gatewayservice_dict = {}

    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, 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]}
        # Handle page length and page cursor parameter
        page_len = params.get('_page_length')
        page_cursor = params.get('_page_cursor')
        if page_len:
            page_len = int(page_len[0])
        else:
            # Explicitly set it to None (avoid 0 or empty list)
            page_len = None
        return (tag_filter, attr_filter, page_len, page_cursor)

    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
        # set status value
        fake_lswitch['status'] = 'true'
        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
        # set status value
        fake_lrouter['status'] = 'true'
        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']
        # set status value
        fake_lport['status'] = 'true'
        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,
         page_len, page_cursor) = self._get_filters(query)
        # result_count attribute in response should appear only when
        # page_cursor is not specified
        do_result_count = not page_cursor
        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 _cursor_match(res_uuid, page_cursor):
                if not page_cursor:
                    return True
                if page_cursor == res_uuid:
                    # always return True once page_cursor has been found
                    page_cursor = None
                    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) and
                         _cursor_match(res_uuid, page_cursor))]
            # Rather inefficient, but hey this is just a mock!
            next_cursor = None
            total_items = len(items)
            if page_len:
                try:
                    next_cursor = items[page_len]['uuid']
                except IndexError:
                    next_cursor = None
                items = items[:page_len]
            response_dict = {'results': items}
            if next_cursor:
                response_dict['page_cursor'] = next_cursor
            if do_result_count:
                response_dict['result_count'] = total_items
            return json.dumps(response_dict)

    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()
