# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
#    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 functools

import nova.api.openstack
from nova.api.openstack.compute import admin_actions
from nova.api.openstack.compute import admin_password
from nova.api.openstack.compute import agents
from nova.api.openstack.compute import aggregates
from nova.api.openstack.compute import assisted_volume_snapshots
from nova.api.openstack.compute import attach_interfaces
from nova.api.openstack.compute import availability_zone
from nova.api.openstack.compute import baremetal_nodes
from nova.api.openstack.compute import cells
from nova.api.openstack.compute import certificates
from nova.api.openstack.compute import cloudpipe
from nova.api.openstack.compute import console_auth_tokens
from nova.api.openstack.compute import console_output
from nova.api.openstack.compute import consoles
from nova.api.openstack.compute import create_backup
from nova.api.openstack.compute import deferred_delete
from nova.api.openstack.compute import evacuate
from nova.api.openstack.compute import extension_info
from nova.api.openstack.compute import fixed_ips
from nova.api.openstack.compute import flavor_access
from nova.api.openstack.compute import flavor_manage
from nova.api.openstack.compute import flavors
from nova.api.openstack.compute import flavors_extraspecs
from nova.api.openstack.compute import floating_ip_dns
from nova.api.openstack.compute import floating_ip_pools
from nova.api.openstack.compute import floating_ips
from nova.api.openstack.compute import floating_ips_bulk
from nova.api.openstack.compute import fping
from nova.api.openstack.compute import hosts
from nova.api.openstack.compute import hypervisors
from nova.api.openstack.compute import image_metadata
from nova.api.openstack.compute import images
from nova.api.openstack.compute import instance_actions
from nova.api.openstack.compute import instance_usage_audit_log
from nova.api.openstack.compute import ips
from nova.api.openstack.compute import keypairs
from nova.api.openstack.compute import limits
from nova.api.openstack.compute import lock_server
from nova.api.openstack.compute import migrate_server
from nova.api.openstack.compute import migrations
from nova.api.openstack.compute import multinic
from nova.api.openstack.compute import networks
from nova.api.openstack.compute import networks_associate
from nova.api.openstack.compute import pause_server
from nova.api.openstack.compute import quota_classes
from nova.api.openstack.compute import quota_sets
from nova.api.openstack.compute import remote_consoles
from nova.api.openstack.compute import rescue
from nova.api.openstack.compute import security_group_default_rules
from nova.api.openstack.compute import security_groups
from nova.api.openstack.compute import server_diagnostics
from nova.api.openstack.compute import server_external_events
from nova.api.openstack.compute import server_groups
from nova.api.openstack.compute import server_metadata
from nova.api.openstack.compute import server_migrations
from nova.api.openstack.compute import server_password
from nova.api.openstack.compute import server_tags
from nova.api.openstack.compute import server_topology
from nova.api.openstack.compute import servers
from nova.api.openstack.compute import services
from nova.api.openstack.compute import shelve
from nova.api.openstack.compute import simple_tenant_usage
from nova.api.openstack.compute import suspend_server
from nova.api.openstack.compute import tenant_networks
from nova.api.openstack.compute import versionsV21
from nova.api.openstack.compute import virtual_interfaces
from nova.api.openstack.compute import volumes
from nova.api.openstack import wsgi
from nova.api import wsgi as base_wsgi


def _create_controller(main_controller, action_controller_list):
    """This is a helper method to create controller with a
    list of action controller.
    """

    controller = wsgi.Resource(main_controller())
    for ctl in action_controller_list:
        controller.register_actions(ctl())
    return controller


agents_controller = functools.partial(
    _create_controller, agents.AgentController, [])


aggregates_controller = functools.partial(
    _create_controller, aggregates.AggregateController, [])


assisted_volume_snapshots_controller = functools.partial(
    _create_controller,
    assisted_volume_snapshots.AssistedVolumeSnapshotsController, [])


availability_zone_controller = functools.partial(
    _create_controller, availability_zone.AvailabilityZoneController, [])


baremetal_nodes_controller = functools.partial(
    _create_controller, baremetal_nodes.BareMetalNodeController, [])


cells_controller = functools.partial(
    _create_controller, cells.CellsController, [])


certificates_controller = functools.partial(
    _create_controller, certificates.CertificatesController, [])


cloudpipe_controller = functools.partial(
    _create_controller, cloudpipe.CloudpipeController, [])


extensions_controller = functools.partial(
    _create_controller, extension_info.ExtensionInfoController, [])


fixed_ips_controller = functools.partial(_create_controller,
    fixed_ips.FixedIPController, [])


flavor_controller = functools.partial(_create_controller,
    flavors.FlavorsController,
    [
        flavor_manage.FlavorManageController,
        flavor_access.FlavorActionController
    ]
)


flavor_access_controller = functools.partial(_create_controller,
    flavor_access.FlavorAccessController, [])


flavor_extraspec_controller = functools.partial(_create_controller,
    flavors_extraspecs.FlavorExtraSpecsController, [])


floating_ip_dns_controller = functools.partial(_create_controller,
    floating_ip_dns.FloatingIPDNSDomainController, [])


floating_ip_dnsentry_controller = functools.partial(_create_controller,
    floating_ip_dns.FloatingIPDNSEntryController, [])


floating_ip_pools_controller = functools.partial(_create_controller,
    floating_ip_pools.FloatingIPPoolsController, [])


floating_ips_controller = functools.partial(_create_controller,
    floating_ips.FloatingIPController, [])


floating_ips_bulk_controller = functools.partial(_create_controller,
    floating_ips_bulk.FloatingIPBulkController, [])


fping_controller = functools.partial(_create_controller,
    fping.FpingController, [])


hosts_controller = functools.partial(
    _create_controller, hosts.HostController, [])


hypervisors_controller = functools.partial(
    _create_controller, hypervisors.HypervisorsController, [])


images_controller = functools.partial(
    _create_controller, images.ImagesController, [])


image_metadata_controller = functools.partial(
    _create_controller, image_metadata.ImageMetadataController, [])


instance_actions_controller = functools.partial(_create_controller,
    instance_actions.InstanceActionsController, [])


instance_usage_audit_log_controller = functools.partial(_create_controller,
    instance_usage_audit_log.InstanceUsageAuditLogController, [])


ips_controller = functools.partial(_create_controller,
    ips.IPsController, [])


keypairs_controller = functools.partial(
    _create_controller, keypairs.KeypairController, [])


limits_controller = functools.partial(
    _create_controller, limits.LimitsController, [])


migrations_controller = functools.partial(_create_controller,
    migrations.MigrationsController, [])


networks_controller = functools.partial(_create_controller,
    networks.NetworkController,
    [networks_associate.NetworkAssociateActionController])


quota_classes_controller = functools.partial(_create_controller,
    quota_classes.QuotaClassSetsController, [])


quota_set_controller = functools.partial(_create_controller,
    quota_sets.QuotaSetsController, [])


security_group_controller = functools.partial(_create_controller,
    security_groups.SecurityGroupController, [])


security_group_default_rules_controller = functools.partial(_create_controller,
    security_group_default_rules.SecurityGroupDefaultRulesController, [])


security_group_rules_controller = functools.partial(_create_controller,
    security_groups.SecurityGroupRulesController, [])


server_controller = functools.partial(_create_controller,
    servers.ServersController,
    [
        admin_actions.AdminActionsController,
        admin_password.AdminPasswordController,
        console_output.ConsoleOutputController,
        create_backup.CreateBackupController,
        deferred_delete.DeferredDeleteController,
        evacuate.EvacuateController,
        floating_ips.FloatingIPActionController,
        lock_server.LockServerController,
        migrate_server.MigrateServerController,
        multinic.MultinicController,
        pause_server.PauseServerController,
        remote_consoles.RemoteConsolesController,
        rescue.RescueController,
        security_groups.SecurityGroupActionController,
        shelve.ShelveController,
        suspend_server.SuspendServerController
    ]
)


console_auth_tokens_controller = functools.partial(_create_controller,
    console_auth_tokens.ConsoleAuthTokensController, [])


consoles_controller = functools.partial(_create_controller,
    consoles.ConsolesController, [])


server_diagnostics_controller = functools.partial(_create_controller,
    server_diagnostics.ServerDiagnosticsController, [])


server_external_events_controller = functools.partial(_create_controller,
    server_external_events.ServerExternalEventsController, [])


server_groups_controller = functools.partial(_create_controller,
    server_groups.ServerGroupController, [])


server_metadata_controller = functools.partial(_create_controller,
    server_metadata.ServerMetadataController, [])


server_migrations_controller = functools.partial(_create_controller,
    server_migrations.ServerMigrationsController, [])


server_os_interface_controller = functools.partial(_create_controller,
    attach_interfaces.InterfaceAttachmentController, [])


server_password_controller = functools.partial(_create_controller,
    server_password.ServerPasswordController, [])


server_remote_consoles_controller = functools.partial(_create_controller,
    remote_consoles.RemoteConsolesController, [])


server_security_groups_controller = functools.partial(_create_controller,
    security_groups.ServerSecurityGroupController, [])


server_tags_controller = functools.partial(_create_controller,
    server_tags.ServerTagsController, [])

server_topology_controller = functools.partial(_create_controller,
    server_topology.ServerTopologyController, [])

server_volume_attachments_controller = functools.partial(_create_controller,
    volumes.VolumeAttachmentController, [])


services_controller = functools.partial(_create_controller,
    services.ServiceController, [])


simple_tenant_usage_controller = functools.partial(_create_controller,
    simple_tenant_usage.SimpleTenantUsageController, [])


snapshots_controller = functools.partial(_create_controller,
    volumes.SnapshotController, [])


tenant_networks_controller = functools.partial(_create_controller,
    tenant_networks.TenantNetworkController, [])


version_controller = functools.partial(_create_controller,
    versionsV21.VersionsController, [])


virtual_interfaces_controller = functools.partial(_create_controller,
    virtual_interfaces.ServerVirtualInterfaceController, [])


volumes_controller = functools.partial(_create_controller,
    volumes.VolumeController, [])


# NOTE(alex_xu): This is structure of this route list as below:
# (
#     ('Route path', {
#         'HTTP method: [
#             'Controller',
#             'The method of controller is used to handle this route'
#         ],
#         ...
#     }),
#     ...
# )
#
# Also note that this is ordered tuple. For example, the '/servers/detail'
# should be in the front of '/servers/{id}', otherwise the request to
# '/servers/detail' always matches to '/servers/{id}' as the id is 'detail'.
ROUTE_LIST = (
    # NOTE: This is a redirection from '' to '/'. The request to the '/v2.1'
    # or '/2.0' without the ending '/' will get a response with status code
    # '302' returned.
    ('', '/'),
    ('/', {
        'GET': [version_controller, 'show']
    }),
    ('/versions/{id}', {
        'GET': [version_controller, 'show']
    }),
    ('/extensions', {
        'GET': [extensions_controller, 'index'],
    }),
    ('/extensions/{id}', {
        'GET': [extensions_controller, 'show'],
    }),
    ('/flavors', {
        'GET': [flavor_controller, 'index'],
        'POST': [flavor_controller, 'create']
    }),
    ('/flavors/detail', {
        'GET': [flavor_controller, 'detail']
    }),
    ('/flavors/{id}', {
        'GET': [flavor_controller, 'show'],
        'PUT': [flavor_controller, 'update'],
        'DELETE': [flavor_controller, 'delete']
    }),
    ('/flavors/{id}/action', {
        'POST': [flavor_controller, 'action']
    }),
    ('/flavors/{flavor_id}/os-extra_specs', {
        'GET': [flavor_extraspec_controller, 'index'],
        'POST': [flavor_extraspec_controller, 'create']
    }),
    ('/flavors/{flavor_id}/os-extra_specs/{id}', {
        'GET': [flavor_extraspec_controller, 'show'],
        'PUT': [flavor_extraspec_controller, 'update'],
        'DELETE': [flavor_extraspec_controller, 'delete']
    }),
    ('/flavors/{flavor_id}/os-flavor-access', {
        'GET': [flavor_access_controller, 'index']
    }),
    ('/images', {
        'GET': [images_controller, 'index']
    }),
    ('/images/detail', {
        'GET': [images_controller, 'detail'],
    }),
    ('/images/{id}', {
        'GET': [images_controller, 'show'],
        'DELETE': [images_controller, 'delete']
    }),
    ('/images/{image_id}/metadata', {
        'GET': [image_metadata_controller, 'index'],
        'POST': [image_metadata_controller, 'create'],
        'PUT': [image_metadata_controller, 'update_all']
    }),
    ('/images/{image_id}/metadata/{id}', {
        'GET': [image_metadata_controller, 'show'],
        'PUT': [image_metadata_controller, 'update'],
        'DELETE': [image_metadata_controller, 'delete']
    }),
    ('/limits', {
        'GET': [limits_controller, 'index']
    }),
    ('/os-agents', {
        'GET': [agents_controller, 'index'],
        'POST': [agents_controller, 'create']
    }),
    ('/os-agents/{id}', {
        'PUT': [agents_controller, 'update'],
        'DELETE': [agents_controller, 'delete']
    }),
    ('/os-aggregates', {
        'GET': [aggregates_controller, 'index'],
        'POST': [aggregates_controller, 'create']
    }),
    ('/os-aggregates/{id}', {
        'GET': [aggregates_controller, 'show'],
        'PUT': [aggregates_controller, 'update'],
        'DELETE': [aggregates_controller, 'delete']
    }),
    ('/os-aggregates/{id}/action', {
        'POST': [aggregates_controller, 'action'],
    }),
    ('/os-aggregates/{id}/images', {
        'POST': [aggregates_controller, 'images'],
    }),
    ('/os-assisted-volume-snapshots', {
        'POST': [assisted_volume_snapshots_controller, 'create']
    }),
    ('/os-assisted-volume-snapshots/{id}', {
        'DELETE': [assisted_volume_snapshots_controller, 'delete']
    }),
    ('/os-availability-zone', {
        'GET': [availability_zone_controller, 'index']
    }),
    ('/os-availability-zone/detail', {
        'GET': [availability_zone_controller, 'detail'],
    }),
    ('/os-baremetal-nodes', {
        'GET': [baremetal_nodes_controller, 'index'],
        'POST': [baremetal_nodes_controller, 'create']
    }),
    ('/os-baremetal-nodes/{id}', {
        'GET': [baremetal_nodes_controller, 'show'],
        'DELETE': [baremetal_nodes_controller, 'delete']
    }),
    ('/os-baremetal-nodes/{id}/action', {
        'POST': [baremetal_nodes_controller, 'action']
    }),
    ('/os-cells', {
        'POST': [cells_controller, 'create'],
        'GET': [cells_controller, 'index'],
    }),
    ('/os-cells/capacities', {
        'GET': [cells_controller, 'capacities']
    }),
    ('/os-cells/detail', {
        'GET': [cells_controller, 'detail']
    }),
    ('/os-cells/info', {
        'GET': [cells_controller, 'info']
    }),
    ('/os-cells/sync_instances', {
        'POST': [cells_controller, 'sync_instances']
    }),
    ('/os-cells/{id}', {
        'GET': [cells_controller, 'show'],
        'PUT': [cells_controller, 'update'],
        'DELETE': [cells_controller, 'delete']
    }),
    ('/os-cells/{id}/capacities', {
        'GET': [cells_controller, 'capacities']
    }),
    ('/os-certificates', {
        'POST': [certificates_controller, 'create']
    }),
    ('/os-certificates/{id}', {
        'GET': [certificates_controller, 'show']
    }),
    ('/os-cloudpipe', {
        'GET': [cloudpipe_controller, 'index'],
        'POST': [cloudpipe_controller, 'create']
    }),
    ('/os-cloudpipe/{id}', {
        'PUT': [cloudpipe_controller, 'update']
    }),
    ('/os-console-auth-tokens/{id}', {
        'GET': [console_auth_tokens_controller, 'show']
    }),
    ('/os-fixed-ips/{id}', {
        'GET': [fixed_ips_controller, 'show']
    }),
    ('/os-fixed-ips/{id}/action', {
        'POST': [fixed_ips_controller, 'action'],
    }),
    ('/os-floating-ip-dns', {
        'GET': [floating_ip_dns_controller, 'index']
    }),
    ('/os-floating-ip-dns/{id}', {
        'PUT': [floating_ip_dns_controller, 'update'],
        'DELETE': [floating_ip_dns_controller, 'delete']
    }),
    ('/os-floating-ip-dns/{domain_id}/entries/{id}', {
        'GET': [floating_ip_dnsentry_controller, 'show'],
        'PUT': [floating_ip_dnsentry_controller, 'update'],
        'DELETE': [floating_ip_dnsentry_controller, 'delete']
    }),
    ('/os-floating-ip-pools', {
        'GET': [floating_ip_pools_controller, 'index'],
    }),
    ('/os-floating-ips', {
        'GET': [floating_ips_controller, 'index'],
        'POST': [floating_ips_controller, 'create']
    }),
    ('/os-floating-ips/{id}', {
        'GET': [floating_ips_controller, 'show'],
        'DELETE': [floating_ips_controller, 'delete']
    }),
    ('/os-floating-ips-bulk', {
        'GET': [floating_ips_bulk_controller, 'index'],
        'POST': [floating_ips_bulk_controller, 'create']
    }),
    ('/os-floating-ips-bulk/{id}', {
        'GET': [floating_ips_bulk_controller, 'show'],
        'PUT': [floating_ips_bulk_controller, 'update']
    }),
    ('/os-fping', {
        'GET': [fping_controller, 'index']
    }),
    ('/os-fping/{id}', {
        'GET': [fping_controller, 'show']
    }),
    ('/os-hosts', {
        'GET': [hosts_controller, 'index']
    }),
    ('/os-hosts/{id}', {
        'GET': [hosts_controller, 'show'],
        'PUT': [hosts_controller, 'update']
    }),
    ('/os-hosts/{id}/reboot', {
        'GET': [hosts_controller, 'reboot']
    }),
    ('/os-hosts/{id}/shutdown', {
        'GET': [hosts_controller, 'shutdown']
    }),
    ('/os-hosts/{id}/startup', {
        'GET': [hosts_controller, 'startup']
    }),
    ('/os-hypervisors', {
        'GET': [hypervisors_controller, 'index']
    }),
    ('/os-hypervisors/detail', {
        'GET': [hypervisors_controller, 'detail']
    }),
    ('/os-hypervisors/statistics', {
        'GET': [hypervisors_controller, 'statistics']
    }),
    ('/os-hypervisors/{id}', {
        'GET': [hypervisors_controller, 'show']
    }),
    ('/os-hypervisors/{id}/search', {
        'GET': [hypervisors_controller, 'search']
    }),
    ('/os-hypervisors/{id}/servers', {
        'GET': [hypervisors_controller, 'servers']
    }),
    ('/os-hypervisors/{id}/uptime', {
        'GET': [hypervisors_controller, 'uptime']
    }),
    ('/os-instance_usage_audit_log', {
        'GET': [instance_usage_audit_log_controller, 'index']
    }),
    ('/os-instance_usage_audit_log/{id}', {
        'GET': [instance_usage_audit_log_controller, 'show']
    }),
    ('/os-keypairs', {
        'GET': [keypairs_controller, 'index'],
        'POST': [keypairs_controller, 'create']
    }),
    ('/os-keypairs/{id}', {
        'GET': [keypairs_controller, 'show'],
        'DELETE': [keypairs_controller, 'delete']
    }),
    ('/os-migrations', {
        'GET': [migrations_controller, 'index']
    }),
    ('/os-networks', {
        'GET': [networks_controller, 'index'],
        'POST': [networks_controller, 'create']
    }),
    ('/os-networks/add', {
        'POST': [networks_controller, 'add']
    }),
    ('/os-networks/{id}', {
        'GET': [networks_controller, 'show'],
        'DELETE': [networks_controller, 'delete']
    }),
    ('/os-networks/{id}/action', {
        'POST': [networks_controller, 'action'],
    }),
    ('/os-quota-class-sets/{id}', {
        'GET': [quota_classes_controller, 'show'],
        'PUT': [quota_classes_controller, 'update']
    }),
    ('/os-quota-sets/{id}', {
        'GET': [quota_set_controller, 'show'],
        'PUT': [quota_set_controller, 'update'],
        'DELETE': [quota_set_controller, 'delete']
    }),
    ('/os-quota-sets/{id}/detail', {
        'GET': [quota_set_controller, 'detail']
    }),
    ('/os-quota-sets/{id}/defaults', {
        'GET': [quota_set_controller, 'defaults']
    }),
    ('/os-security-group-default-rules', {
        'GET': [security_group_default_rules_controller, 'index'],
        'POST': [security_group_default_rules_controller, 'create']
    }),
    ('/os-security-group-default-rules/{id}', {
        'GET': [security_group_default_rules_controller, 'show'],
        'DELETE': [security_group_default_rules_controller, 'delete']
    }),
    ('/os-security-group-rules', {
        'POST': [security_group_rules_controller, 'create']
    }),
    ('/os-security-group-rules/{id}', {
        'DELETE': [security_group_rules_controller, 'delete']
    }),
    ('/os-security-groups', {
        'GET': [security_group_controller, 'index'],
        'POST': [security_group_controller, 'create']
    }),
    ('/os-security-groups/{id}', {
        'GET': [security_group_controller, 'show'],
        'PUT': [security_group_controller, 'update'],
        'DELETE': [security_group_controller, 'delete']
    }),
    ('/os-server-external-events', {
        'POST': [server_external_events_controller, 'create']
    }),
    ('/os-server-groups', {
        'GET': [server_groups_controller, 'index'],
        'POST': [server_groups_controller, 'create']
    }),
    ('/os-server-groups/{id}', {
        'GET': [server_groups_controller, 'show'],
        'DELETE': [server_groups_controller, 'delete']
    }),
    ('/os-services', {
        'GET': [services_controller, 'index']
    }),
    ('/os-services/{id}', {
        'PUT': [services_controller, 'update'],
        'DELETE': [services_controller, 'delete']
    }),
    ('/os-simple-tenant-usage', {
        'GET': [simple_tenant_usage_controller, 'index']
    }),
    ('/os-simple-tenant-usage/{id}', {
        'GET': [simple_tenant_usage_controller, 'show']
    }),
    ('/os-snapshots', {
        'GET': [snapshots_controller, 'index'],
        'POST': [snapshots_controller, 'create']
    }),
    ('/os-snapshots/detail', {
        'GET': [snapshots_controller, 'detail']
    }),
    ('/os-snapshots/{id}', {
        'GET': [snapshots_controller, 'show'],
        'DELETE': [snapshots_controller, 'delete']
    }),
    ('/os-tenant-networks', {
        'GET': [tenant_networks_controller, 'index'],
        'POST': [tenant_networks_controller, 'create']
    }),
    ('/os-tenant-networks/{id}', {
        'GET': [tenant_networks_controller, 'show'],
        'DELETE': [tenant_networks_controller, 'delete']
    }),
    ('/os-volumes', {
        'GET': [volumes_controller, 'index'],
        'POST': [volumes_controller, 'create'],
    }),
    ('/os-volumes/detail', {
        'GET': [volumes_controller, 'detail'],
    }),
    ('/os-volumes/{id}', {
        'GET': [volumes_controller, 'show'],
        'DELETE': [volumes_controller, 'delete']
    }),
    # NOTE: '/os-volumes_boot' is a clone of '/servers'. We may want to
    # deprecate it in the future.
    ('/os-volumes_boot', {
        'GET': [server_controller, 'index'],
        'POST': [server_controller, 'create']
    }),
    ('/os-volumes_boot/detail', {
        'GET': [server_controller, 'detail']
    }),
    ('/os-volumes_boot/{id}', {
        'GET': [server_controller, 'show'],
        'PUT': [server_controller, 'update'],
        'DELETE': [server_controller, 'delete']
    }),
    ('/os-volumes_boot/{id}/action', {
        'POST': [server_controller, 'action']
    }),
    ('/servers', {
        'GET': [server_controller, 'index'],
        'POST': [server_controller, 'create']
    }),
    ('/servers/detail', {
        'GET': [server_controller, 'detail']
    }),
    ('/servers/{id}', {
        'GET': [server_controller, 'show'],
        'PUT': [server_controller, 'update'],
        'DELETE': [server_controller, 'delete']
    }),
    ('/servers/{id}/action', {
        'POST': [server_controller, 'action']
    }),
    ('/servers/{server_id}/consoles', {
        'GET': [consoles_controller, 'index'],
        'POST': [consoles_controller, 'create']
    }),
    ('/servers/{server_id}/consoles/{id}', {
        'GET': [consoles_controller, 'show'],
        'DELETE': [consoles_controller, 'delete']
    }),
    ('/servers/{server_id}/diagnostics', {
        'GET': [server_diagnostics_controller, 'index']
    }),
    ('/servers/{server_id}/ips', {
        'GET': [ips_controller, 'index']
    }),
    ('/servers/{server_id}/ips/{id}', {
        'GET': [ips_controller, 'show']
    }),
    ('/servers/{server_id}/metadata', {
        'GET': [server_metadata_controller, 'index'],
        'POST': [server_metadata_controller, 'create'],
        'PUT': [server_metadata_controller, 'update_all'],
    }),
    ('/servers/{server_id}/metadata/{id}', {
        'GET': [server_metadata_controller, 'show'],
        'PUT': [server_metadata_controller, 'update'],
        'DELETE': [server_metadata_controller, 'delete'],
    }),
    ('/servers/{server_id}/migrations', {
        'GET': [server_migrations_controller, 'index']
    }),
    ('/servers/{server_id}/migrations/{id}', {
        'GET': [server_migrations_controller, 'show'],
        'DELETE': [server_migrations_controller, 'delete']
    }),
    ('/servers/{server_id}/migrations/{id}/action', {
        'POST': [server_migrations_controller, 'action']
    }),
    ('/servers/{server_id}/os-instance-actions', {
        'GET': [instance_actions_controller, 'index']
    }),
    ('/servers/{server_id}/os-instance-actions/{id}', {
        'GET': [instance_actions_controller, 'show']
    }),
    ('/servers/{server_id}/os-interface', {
        'GET': [server_os_interface_controller, 'index'],
        'POST': [server_os_interface_controller, 'create']
    }),
    ('/servers/{server_id}/os-interface/{id}', {
        'GET': [server_os_interface_controller, 'show'],
        'DELETE': [server_os_interface_controller, 'delete']
    }),
    ('/servers/{server_id}/os-server-password', {
        'GET': [server_password_controller, 'index'],
        'DELETE': [server_password_controller, 'clear']
    }),
    ('/servers/{server_id}/os-virtual-interfaces', {
        'GET': [virtual_interfaces_controller, 'index']
    }),
    ('/servers/{server_id}/os-volume_attachments', {
        'GET': [server_volume_attachments_controller, 'index'],
        'POST': [server_volume_attachments_controller, 'create'],
    }),
    ('/servers/{server_id}/os-volume_attachments/{id}', {
        'GET': [server_volume_attachments_controller, 'show'],
        'PUT': [server_volume_attachments_controller, 'update'],
        'DELETE': [server_volume_attachments_controller, 'delete']
    }),
    ('/servers/{server_id}/remote-consoles', {
        'POST': [server_remote_consoles_controller, 'create']
    }),
    ('/servers/{server_id}/os-security-groups', {
        'GET': [server_security_groups_controller, 'index']
    }),
    ('/servers/{server_id}/tags', {
        'GET': [server_tags_controller, 'index'],
        'PUT': [server_tags_controller, 'update_all'],
        'DELETE': [server_tags_controller, 'delete_all'],
    }),
    ('/servers/{server_id}/tags/{id}', {
        'GET': [server_tags_controller, 'show'],
        'PUT': [server_tags_controller, 'update'],
        'DELETE': [server_tags_controller, 'delete']
    }),
    ('/servers/{server_id}/topology', {
        'GET': [server_topology_controller, 'index']
    }),
)


class APIRouterV21(base_wsgi.Router):
    """Routes requests on the OpenStack API to the appropriate controller
    and method. The URL mapping based on the plain list `ROUTE_LIST` is built
    at here.
    """
    def __init__(self, custom_routes=None):
        """:param custom_routes: the additional routes can be added by this
               parameter. This parameter is used to test on some fake routes
               primarily.
        """
        super(APIRouterV21, self).__init__(nova.api.openstack.ProjectMapper())

        if custom_routes is None:
            custom_routes = tuple()

        for path, methods in ROUTE_LIST + custom_routes:
            # NOTE(alex_xu): The variable 'methods' is a dict in normal, since
            # the dict includes all the methods supported in the path. But
            # if the variable 'method' is a string, it means a redirection.
            # For example, the request to the '' will be redirect to the '/' in
            # the Nova API. To indicate that, using the target path instead of
            # a dict. The route entry just writes as "('', '/)".
            if isinstance(methods, str):
                self.map.redirect(path, methods)
                continue

            for method, controller_info in methods.items():
                # TODO(alex_xu): In the end, I want to create single controller
                # instance instead of create controller instance for each
                # route.
                controller = controller_info[0]()
                action = controller_info[1]
                self.map.create_route(path, method, controller, action)

    @classmethod
    def factory(cls, global_config, **local_config):
        """Simple paste factory, :class:`nova.wsgi.Router` doesn't have one."""
        return cls()
