implement servicevm related command
Change-Id: Ib606eb3e4721ec9a255092bf4581f3b576c3714a
This commit is contained in:
parent
ffa7a582e5
commit
87a2257477
@ -15,7 +15,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Command-line interface to the Neutron APIs
|
Command-line interface to the Tacker APIs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
@ -28,46 +28,20 @@ import sys
|
|||||||
from cliff import app
|
from cliff import app
|
||||||
from cliff import commandmanager
|
from cliff import commandmanager
|
||||||
|
|
||||||
from neutronclient.common import clientmanager
|
from tackerclient.common import clientmanager
|
||||||
from neutronclient.common import exceptions as exc
|
from tackerclient.common import exceptions as exc
|
||||||
from neutronclient.common import utils
|
from tackerclient.common import utils
|
||||||
from neutronclient.neutron.v2_0 import agent
|
from tackerclient.openstack.common.gettextutils import _
|
||||||
from neutronclient.neutron.v2_0 import agentscheduler
|
from tackerclient.openstack.common import strutils
|
||||||
from neutronclient.neutron.v2_0 import credential
|
from tackerclient.tacker.v1_0 import extension
|
||||||
from neutronclient.neutron.v2_0 import extension
|
from tackerclient.tacker.v1_0.vm import device
|
||||||
from neutronclient.neutron.v2_0 import floatingip
|
from tackerclient.tacker.v1_0.vm import device_template
|
||||||
from neutronclient.neutron.v2_0.fw import firewall
|
from tackerclient.tacker.v1_0.vm import service_instance
|
||||||
from neutronclient.neutron.v2_0.fw import firewallpolicy
|
from tackerclient.version import __version__
|
||||||
from neutronclient.neutron.v2_0.fw import firewallrule
|
|
||||||
from neutronclient.neutron.v2_0.lb import healthmonitor as lb_healthmonitor
|
|
||||||
from neutronclient.neutron.v2_0.lb import member as lb_member
|
|
||||||
from neutronclient.neutron.v2_0.lb import pool as lb_pool
|
|
||||||
from neutronclient.neutron.v2_0.lb import vip as lb_vip
|
|
||||||
from neutronclient.neutron.v2_0 import metering
|
|
||||||
from neutronclient.neutron.v2_0.nec import packetfilter
|
|
||||||
from neutronclient.neutron.v2_0 import netpartition
|
|
||||||
from neutronclient.neutron.v2_0 import network
|
|
||||||
from neutronclient.neutron.v2_0 import networkprofile
|
|
||||||
from neutronclient.neutron.v2_0.nsx import networkgateway
|
|
||||||
from neutronclient.neutron.v2_0.nsx import qos_queue
|
|
||||||
from neutronclient.neutron.v2_0 import policyprofile
|
|
||||||
from neutronclient.neutron.v2_0 import port
|
|
||||||
from neutronclient.neutron.v2_0 import quota
|
|
||||||
from neutronclient.neutron.v2_0 import router
|
|
||||||
from neutronclient.neutron.v2_0 import securitygroup
|
|
||||||
from neutronclient.neutron.v2_0 import servicetype
|
|
||||||
from neutronclient.neutron.v2_0 import subnet
|
|
||||||
from neutronclient.neutron.v2_0.vpn import ikepolicy
|
|
||||||
from neutronclient.neutron.v2_0.vpn import ipsec_site_connection
|
|
||||||
from neutronclient.neutron.v2_0.vpn import ipsecpolicy
|
|
||||||
from neutronclient.neutron.v2_0.vpn import vpnservice
|
|
||||||
from neutronclient.openstack.common.gettextutils import _
|
|
||||||
from neutronclient.openstack.common import strutils
|
|
||||||
from neutronclient.version import __version__
|
|
||||||
|
|
||||||
|
|
||||||
VERSION = '2.0'
|
VERSION = '1.0'
|
||||||
NEUTRON_API_VERSION = '2.0'
|
TACKER_API_VERSION = '1.0'
|
||||||
|
|
||||||
|
|
||||||
def run_command(cmd, cmd_parser, sub_argv):
|
def run_command(cmd, cmd_parser, sub_argv):
|
||||||
@ -97,189 +71,27 @@ def env(*_vars, **kwargs):
|
|||||||
return kwargs.get('default', '')
|
return kwargs.get('default', '')
|
||||||
|
|
||||||
|
|
||||||
COMMAND_V2 = {
|
COMMAND_V1 = {
|
||||||
'net-list': network.ListNetwork,
|
|
||||||
'net-external-list': network.ListExternalNetwork,
|
|
||||||
'net-show': network.ShowNetwork,
|
|
||||||
'net-create': network.CreateNetwork,
|
|
||||||
'net-delete': network.DeleteNetwork,
|
|
||||||
'net-update': network.UpdateNetwork,
|
|
||||||
'subnet-list': subnet.ListSubnet,
|
|
||||||
'subnet-show': subnet.ShowSubnet,
|
|
||||||
'subnet-create': subnet.CreateSubnet,
|
|
||||||
'subnet-delete': subnet.DeleteSubnet,
|
|
||||||
'subnet-update': subnet.UpdateSubnet,
|
|
||||||
'port-list': port.ListPort,
|
|
||||||
'port-show': port.ShowPort,
|
|
||||||
'port-create': port.CreatePort,
|
|
||||||
'port-delete': port.DeletePort,
|
|
||||||
'port-update': port.UpdatePort,
|
|
||||||
'quota-list': quota.ListQuota,
|
|
||||||
'quota-show': quota.ShowQuota,
|
|
||||||
'quota-delete': quota.DeleteQuota,
|
|
||||||
'quota-update': quota.UpdateQuota,
|
|
||||||
'ext-list': extension.ListExt,
|
'ext-list': extension.ListExt,
|
||||||
'ext-show': extension.ShowExt,
|
'ext-show': extension.ShowExt,
|
||||||
'router-list': router.ListRouter,
|
'device-template-create': device_template.CreateDeviceTemplate,
|
||||||
'router-port-list': port.ListRouterPort,
|
'device-template-list': device_template.ListDeviceTemplate,
|
||||||
'router-show': router.ShowRouter,
|
'device-template-show': device_template.ShowDeviceTemplate,
|
||||||
'router-create': router.CreateRouter,
|
'device-template-update': device_template.UpdateDeviceTemplate,
|
||||||
'router-delete': router.DeleteRouter,
|
'device-template-delete': device_template.DeleteDeviceTemplate,
|
||||||
'router-update': router.UpdateRouter,
|
'service-instance-create': service_instance.CreateServiceInstance,
|
||||||
'router-interface-add': router.AddInterfaceRouter,
|
'service-instance-list': service_instance.ListServiceInstance,
|
||||||
'router-interface-delete': router.RemoveInterfaceRouter,
|
'service-instance-show': service_instance.ShowServiceInstance,
|
||||||
'router-gateway-set': router.SetGatewayRouter,
|
'service-instance-update': service_instance.UpdateServiceInstance,
|
||||||
'router-gateway-clear': router.RemoveGatewayRouter,
|
'service-instance-delete': service_instance.DeleteServiceInstance,
|
||||||
'floatingip-list': floatingip.ListFloatingIP,
|
'device-create': device.CreateDevice,
|
||||||
'floatingip-show': floatingip.ShowFloatingIP,
|
'device-list': device.ListDevice,
|
||||||
'floatingip-create': floatingip.CreateFloatingIP,
|
'device-show': device.ShowDevice,
|
||||||
'floatingip-delete': floatingip.DeleteFloatingIP,
|
'device-update': device.UpdateDevice,
|
||||||
'floatingip-associate': floatingip.AssociateFloatingIP,
|
'device-delete': device.DeleteDevice,
|
||||||
'floatingip-disassociate': floatingip.DisassociateFloatingIP,
|
|
||||||
'security-group-list': securitygroup.ListSecurityGroup,
|
|
||||||
'security-group-show': securitygroup.ShowSecurityGroup,
|
|
||||||
'security-group-create': securitygroup.CreateSecurityGroup,
|
|
||||||
'security-group-delete': securitygroup.DeleteSecurityGroup,
|
|
||||||
'security-group-update': securitygroup.UpdateSecurityGroup,
|
|
||||||
'security-group-rule-list': securitygroup.ListSecurityGroupRule,
|
|
||||||
'security-group-rule-show': securitygroup.ShowSecurityGroupRule,
|
|
||||||
'security-group-rule-create': securitygroup.CreateSecurityGroupRule,
|
|
||||||
'security-group-rule-delete': securitygroup.DeleteSecurityGroupRule,
|
|
||||||
'lb-vip-list': lb_vip.ListVip,
|
|
||||||
'lb-vip-show': lb_vip.ShowVip,
|
|
||||||
'lb-vip-create': lb_vip.CreateVip,
|
|
||||||
'lb-vip-update': lb_vip.UpdateVip,
|
|
||||||
'lb-vip-delete': lb_vip.DeleteVip,
|
|
||||||
'lb-pool-list': lb_pool.ListPool,
|
|
||||||
'lb-pool-show': lb_pool.ShowPool,
|
|
||||||
'lb-pool-create': lb_pool.CreatePool,
|
|
||||||
'lb-pool-update': lb_pool.UpdatePool,
|
|
||||||
'lb-pool-delete': lb_pool.DeletePool,
|
|
||||||
'lb-pool-stats': lb_pool.RetrievePoolStats,
|
|
||||||
'lb-member-list': lb_member.ListMember,
|
|
||||||
'lb-member-show': lb_member.ShowMember,
|
|
||||||
'lb-member-create': lb_member.CreateMember,
|
|
||||||
'lb-member-update': lb_member.UpdateMember,
|
|
||||||
'lb-member-delete': lb_member.DeleteMember,
|
|
||||||
'lb-healthmonitor-list': lb_healthmonitor.ListHealthMonitor,
|
|
||||||
'lb-healthmonitor-show': lb_healthmonitor.ShowHealthMonitor,
|
|
||||||
'lb-healthmonitor-create': lb_healthmonitor.CreateHealthMonitor,
|
|
||||||
'lb-healthmonitor-update': lb_healthmonitor.UpdateHealthMonitor,
|
|
||||||
'lb-healthmonitor-delete': lb_healthmonitor.DeleteHealthMonitor,
|
|
||||||
'lb-healthmonitor-associate': lb_healthmonitor.AssociateHealthMonitor,
|
|
||||||
'lb-healthmonitor-disassociate': (
|
|
||||||
lb_healthmonitor.DisassociateHealthMonitor
|
|
||||||
),
|
|
||||||
'queue-create': qos_queue.CreateQoSQueue,
|
|
||||||
'queue-delete': qos_queue.DeleteQoSQueue,
|
|
||||||
'queue-show': qos_queue.ShowQoSQueue,
|
|
||||||
'queue-list': qos_queue.ListQoSQueue,
|
|
||||||
'agent-list': agent.ListAgent,
|
|
||||||
'agent-show': agent.ShowAgent,
|
|
||||||
'agent-delete': agent.DeleteAgent,
|
|
||||||
'agent-update': agent.UpdateAgent,
|
|
||||||
'net-gateway-create': networkgateway.CreateNetworkGateway,
|
|
||||||
'net-gateway-update': networkgateway.UpdateNetworkGateway,
|
|
||||||
'net-gateway-delete': networkgateway.DeleteNetworkGateway,
|
|
||||||
'net-gateway-show': networkgateway.ShowNetworkGateway,
|
|
||||||
'net-gateway-list': networkgateway.ListNetworkGateway,
|
|
||||||
'net-gateway-connect': networkgateway.ConnectNetworkGateway,
|
|
||||||
'net-gateway-disconnect': networkgateway.DisconnectNetworkGateway,
|
|
||||||
'gateway-device-create': networkgateway.CreateGatewayDevice,
|
|
||||||
'gateway-device-update': networkgateway.UpdateGatewayDevice,
|
|
||||||
'gateway-device-delete': networkgateway.DeleteGatewayDevice,
|
|
||||||
'gateway-device-show': networkgateway.ShowGatewayDevice,
|
|
||||||
'gateway-device-list': networkgateway.ListGatewayDevice,
|
|
||||||
'dhcp-agent-network-add': agentscheduler.AddNetworkToDhcpAgent,
|
|
||||||
'dhcp-agent-network-remove': agentscheduler.RemoveNetworkFromDhcpAgent,
|
|
||||||
'net-list-on-dhcp-agent': agentscheduler.ListNetworksOnDhcpAgent,
|
|
||||||
'dhcp-agent-list-hosting-net': agentscheduler.ListDhcpAgentsHostingNetwork,
|
|
||||||
'l3-agent-router-add': agentscheduler.AddRouterToL3Agent,
|
|
||||||
'l3-agent-router-remove': agentscheduler.RemoveRouterFromL3Agent,
|
|
||||||
'router-list-on-l3-agent': agentscheduler.ListRoutersOnL3Agent,
|
|
||||||
'l3-agent-list-hosting-router': agentscheduler.ListL3AgentsHostingRouter,
|
|
||||||
'lb-pool-list-on-agent': agentscheduler.ListPoolsOnLbaasAgent,
|
|
||||||
'lb-agent-hosting-pool': agentscheduler.GetLbaasAgentHostingPool,
|
|
||||||
'service-provider-list': servicetype.ListServiceProvider,
|
|
||||||
'firewall-rule-list': firewallrule.ListFirewallRule,
|
|
||||||
'firewall-rule-show': firewallrule.ShowFirewallRule,
|
|
||||||
'firewall-rule-create': firewallrule.CreateFirewallRule,
|
|
||||||
'firewall-rule-update': firewallrule.UpdateFirewallRule,
|
|
||||||
'firewall-rule-delete': firewallrule.DeleteFirewallRule,
|
|
||||||
'firewall-policy-list': firewallpolicy.ListFirewallPolicy,
|
|
||||||
'firewall-policy-show': firewallpolicy.ShowFirewallPolicy,
|
|
||||||
'firewall-policy-create': firewallpolicy.CreateFirewallPolicy,
|
|
||||||
'firewall-policy-update': firewallpolicy.UpdateFirewallPolicy,
|
|
||||||
'firewall-policy-delete': firewallpolicy.DeleteFirewallPolicy,
|
|
||||||
'firewall-policy-insert-rule': firewallpolicy.FirewallPolicyInsertRule,
|
|
||||||
'firewall-policy-remove-rule': firewallpolicy.FirewallPolicyRemoveRule,
|
|
||||||
'firewall-list': firewall.ListFirewall,
|
|
||||||
'firewall-show': firewall.ShowFirewall,
|
|
||||||
'firewall-create': firewall.CreateFirewall,
|
|
||||||
'firewall-update': firewall.UpdateFirewall,
|
|
||||||
'firewall-delete': firewall.DeleteFirewall,
|
|
||||||
'cisco-credential-list': credential.ListCredential,
|
|
||||||
'cisco-credential-show': credential.ShowCredential,
|
|
||||||
'cisco-credential-create': credential.CreateCredential,
|
|
||||||
'cisco-credential-delete': credential.DeleteCredential,
|
|
||||||
'cisco-network-profile-list': networkprofile.ListNetworkProfile,
|
|
||||||
'cisco-network-profile-show': networkprofile.ShowNetworkProfile,
|
|
||||||
'cisco-network-profile-create': networkprofile.CreateNetworkProfile,
|
|
||||||
'cisco-network-profile-delete': networkprofile.DeleteNetworkProfile,
|
|
||||||
'cisco-network-profile-update': networkprofile.UpdateNetworkProfile,
|
|
||||||
'cisco-policy-profile-list': policyprofile.ListPolicyProfile,
|
|
||||||
'cisco-policy-profile-show': policyprofile.ShowPolicyProfile,
|
|
||||||
'cisco-policy-profile-update': policyprofile.UpdatePolicyProfile,
|
|
||||||
'ipsec-site-connection-list': (
|
|
||||||
ipsec_site_connection.ListIPsecSiteConnection
|
|
||||||
),
|
|
||||||
'ipsec-site-connection-show': (
|
|
||||||
ipsec_site_connection.ShowIPsecSiteConnection
|
|
||||||
),
|
|
||||||
'ipsec-site-connection-create': (
|
|
||||||
ipsec_site_connection.CreateIPsecSiteConnection
|
|
||||||
),
|
|
||||||
'ipsec-site-connection-update': (
|
|
||||||
ipsec_site_connection.UpdateIPsecSiteConnection
|
|
||||||
),
|
|
||||||
'ipsec-site-connection-delete': (
|
|
||||||
ipsec_site_connection.DeleteIPsecSiteConnection
|
|
||||||
),
|
|
||||||
'vpn-service-list': vpnservice.ListVPNService,
|
|
||||||
'vpn-service-show': vpnservice.ShowVPNService,
|
|
||||||
'vpn-service-create': vpnservice.CreateVPNService,
|
|
||||||
'vpn-service-update': vpnservice.UpdateVPNService,
|
|
||||||
'vpn-service-delete': vpnservice.DeleteVPNService,
|
|
||||||
'vpn-ipsecpolicy-list': ipsecpolicy.ListIPsecPolicy,
|
|
||||||
'vpn-ipsecpolicy-show': ipsecpolicy.ShowIPsecPolicy,
|
|
||||||
'vpn-ipsecpolicy-create': ipsecpolicy.CreateIPsecPolicy,
|
|
||||||
'vpn-ipsecpolicy-update': ipsecpolicy.UpdateIPsecPolicy,
|
|
||||||
'vpn-ipsecpolicy-delete': ipsecpolicy.DeleteIPsecPolicy,
|
|
||||||
'vpn-ikepolicy-list': ikepolicy.ListIKEPolicy,
|
|
||||||
'vpn-ikepolicy-show': ikepolicy.ShowIKEPolicy,
|
|
||||||
'vpn-ikepolicy-create': ikepolicy.CreateIKEPolicy,
|
|
||||||
'vpn-ikepolicy-update': ikepolicy.UpdateIKEPolicy,
|
|
||||||
'vpn-ikepolicy-delete': ikepolicy.DeleteIKEPolicy,
|
|
||||||
'meter-label-create': metering.CreateMeteringLabel,
|
|
||||||
'meter-label-list': metering.ListMeteringLabel,
|
|
||||||
'meter-label-show': metering.ShowMeteringLabel,
|
|
||||||
'meter-label-delete': metering.DeleteMeteringLabel,
|
|
||||||
'meter-label-rule-create': metering.CreateMeteringLabelRule,
|
|
||||||
'meter-label-rule-list': metering.ListMeteringLabelRule,
|
|
||||||
'meter-label-rule-show': metering.ShowMeteringLabelRule,
|
|
||||||
'meter-label-rule-delete': metering.DeleteMeteringLabelRule,
|
|
||||||
'nuage-netpartition-list': netpartition.ListNetPartition,
|
|
||||||
'nuage-netpartition-show': netpartition.ShowNetPartition,
|
|
||||||
'nuage-netpartition-create': netpartition.CreateNetPartition,
|
|
||||||
'nuage-netpartition-delete': netpartition.DeleteNetPartition,
|
|
||||||
'nec-packet-filter-list': packetfilter.ListPacketFilter,
|
|
||||||
'nec-packet-filter-show': packetfilter.ShowPacketFilter,
|
|
||||||
'nec-packet-filter-create': packetfilter.CreatePacketFilter,
|
|
||||||
'nec-packet-filter-update': packetfilter.UpdatePacketFilter,
|
|
||||||
'nec-packet-filter-delete': packetfilter.DeletePacketFilter,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMANDS = {'2.0': COMMAND_V2}
|
COMMANDS = {'1.0': COMMAND_V1}
|
||||||
|
|
||||||
|
|
||||||
class HelpAction(argparse.Action):
|
class HelpAction(argparse.Action):
|
||||||
@ -307,7 +119,7 @@ class HelpAction(argparse.Action):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
class NeutronShell(app.App):
|
class TackerShell(app.App):
|
||||||
|
|
||||||
# verbose logging levels
|
# verbose logging levels
|
||||||
WARNING_LEVEL = 0
|
WARNING_LEVEL = 0
|
||||||
@ -318,10 +130,10 @@ class NeutronShell(app.App):
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def __init__(self, apiversion):
|
def __init__(self, apiversion):
|
||||||
super(NeutronShell, self).__init__(
|
super(TackerShell, self).__init__(
|
||||||
description=__doc__.strip(),
|
description=__doc__.strip(),
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
command_manager=commandmanager.CommandManager('neutron.cli'), )
|
command_manager=commandmanager.CommandManager('tacker.cli'), )
|
||||||
self.commands = COMMANDS
|
self.commands = COMMANDS
|
||||||
for k, v in self.commands[apiversion].items():
|
for k, v in self.commands[apiversion].items():
|
||||||
self.command_manager.add_command(k, v)
|
self.command_manager.add_command(k, v)
|
||||||
@ -466,8 +278,8 @@ class NeutronShell(app.App):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--insecure',
|
'--insecure',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
default=env('NEUTRONCLIENT_INSECURE', default=False),
|
default=env('TACKERCLIENT_INSECURE', default=False),
|
||||||
help=_("Explicitly allow neutronclient to perform \"insecure\" "
|
help=_("Explicitly allow tackerclient to perform \"insecure\" "
|
||||||
"SSL (https) requests. The server's certificate will "
|
"SSL (https) requests. The server's certificate will "
|
||||||
"not be verified against any certificate authorities. "
|
"not be verified against any certificate authorities. "
|
||||||
"This option should be used with caution."))
|
"This option should be used with caution."))
|
||||||
@ -650,7 +462,7 @@ class NeutronShell(app.App):
|
|||||||
* validate authentication info
|
* validate authentication info
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super(NeutronShell, self).initialize_app(argv)
|
super(TackerShell, self).initialize_app(argv)
|
||||||
|
|
||||||
self.api_version = {'network': self.api_version}
|
self.api_version = {'network': self.api_version}
|
||||||
|
|
||||||
@ -693,9 +505,9 @@ class NeutronShell(app.App):
|
|||||||
|
|
||||||
def main(argv=sys.argv[1:]):
|
def main(argv=sys.argv[1:]):
|
||||||
try:
|
try:
|
||||||
return NeutronShell(NEUTRON_API_VERSION).run(map(strutils.safe_decode,
|
return TackerShell(TACKER_API_VERSION).run(map(strutils.safe_decode,
|
||||||
argv))
|
argv))
|
||||||
except exc.NeutronClientException:
|
except exc.TackerClientException:
|
||||||
return 1
|
return 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(unicode(e))
|
print(unicode(e))
|
0
tackerclient/tacker/v1_0/vm/__init__.py
Normal file
0
tackerclient/tacker/v1_0/vm/__init__.py
Normal file
137
tackerclient/tacker/v1_0/vm/device.py
Normal file
137
tackerclient/tacker/v1_0/vm/device.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2013 Intel
|
||||||
|
# Copyright 2013 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
from tackerclient.common import exceptions
|
||||||
|
from tackerclient.openstack.common.gettextutils import _
|
||||||
|
from tackerclient.tacker import v1_0 as tackerV10
|
||||||
|
|
||||||
|
|
||||||
|
_DEVICE = 'device'
|
||||||
|
|
||||||
|
|
||||||
|
class ListDevice(tackerV10.ListCommand):
|
||||||
|
"""List device that belong to a given tenant."""
|
||||||
|
|
||||||
|
resource = _DEVICE
|
||||||
|
|
||||||
|
|
||||||
|
class ShowDevice(tackerV10.ShowCommand):
|
||||||
|
"""show information of a given Device."""
|
||||||
|
|
||||||
|
resource = _DEVICE
|
||||||
|
|
||||||
|
|
||||||
|
class CreateDevice(tackerV10.CreateCommand):
|
||||||
|
"""create a Device."""
|
||||||
|
|
||||||
|
resource = _DEVICE
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--device-template-id',
|
||||||
|
required=True,
|
||||||
|
help='device template id to create device based on')
|
||||||
|
parser.add_argument(
|
||||||
|
'--kwargs',
|
||||||
|
metavar='<key>=<value>',
|
||||||
|
action='append',
|
||||||
|
dest='kwargs',
|
||||||
|
default=[],
|
||||||
|
help='instance specific argument')
|
||||||
|
parser.add_argument(
|
||||||
|
'--service-context',
|
||||||
|
metavar='<network-id=network-uuid,subnet-id=subnet-uuid,'
|
||||||
|
'port-id=port-uuid,router-id=router-uuid,'
|
||||||
|
'role=role-string,index=int>',
|
||||||
|
action='append',
|
||||||
|
dest='service_context',
|
||||||
|
default=[],
|
||||||
|
help='service context to insert service')
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {
|
||||||
|
self.resource: {
|
||||||
|
'template_id': parsed_args.device_template_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsed_args.kwargs:
|
||||||
|
try:
|
||||||
|
kwargs = dict(key_value.split('=', 1)
|
||||||
|
for key_value in parsed_args.kwargs)
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --kwargs %s') %
|
||||||
|
parsed_args.kwargs)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
if kwargs:
|
||||||
|
body[self.resource]['kwargs'] = kwargs
|
||||||
|
if parsed_args.service_context:
|
||||||
|
try:
|
||||||
|
service_context = [dict(
|
||||||
|
(k.replace('-', '_'), v)
|
||||||
|
for k, v in (key_value.split('=', 1)
|
||||||
|
for key_value in entry_string.split(',')))
|
||||||
|
for entry_string in parsed_args.service_context]
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --service-context %s') %
|
||||||
|
parsed_args.service_context)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
|
||||||
|
if service_context:
|
||||||
|
body[self.resource]['service_context'] = service_context
|
||||||
|
|
||||||
|
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateDevice(tackerV10.UpdateCommand):
|
||||||
|
"""Update a given Device."""
|
||||||
|
|
||||||
|
resource = _DEVICE
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--kwargs',
|
||||||
|
metavar='<key>=<value>',
|
||||||
|
action='append',
|
||||||
|
dest='kwargs',
|
||||||
|
default=[],
|
||||||
|
help='instance specific argument')
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {self.resource: {}}
|
||||||
|
if parsed_args.kwargs:
|
||||||
|
try:
|
||||||
|
kwargs = dict(key_value.split('=', 1)
|
||||||
|
for key_value in parsed_args.kwargs)
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --kwargs %s') %
|
||||||
|
parsed_args.kwargs)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
if kwargs:
|
||||||
|
body[self.resource]['kwargs'] = kwargs
|
||||||
|
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteDevice(tackerV10.DeleteCommand):
|
||||||
|
"""Delete a given Device."""
|
||||||
|
|
||||||
|
resource = _DEVICE
|
94
tackerclient/tacker/v1_0/vm/device_template.py
Normal file
94
tackerclient/tacker/v1_0/vm/device_template.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2013 Intel
|
||||||
|
# Copyright 2013 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
from tackerclient.tacker import v1_0 as tackerV10
|
||||||
|
|
||||||
|
|
||||||
|
_DEVICE_TEMPLATE = "device_template"
|
||||||
|
|
||||||
|
|
||||||
|
class ListDeviceTemplate(tackerV10.ListCommand):
|
||||||
|
"""List device template that belong to a given tenant."""
|
||||||
|
|
||||||
|
resource = _DEVICE_TEMPLATE
|
||||||
|
|
||||||
|
|
||||||
|
class ShowDeviceTemplate(tackerV10.ShowCommand):
|
||||||
|
"""show information of a given DeviceTemplate."""
|
||||||
|
|
||||||
|
resource = _DEVICE_TEMPLATE
|
||||||
|
|
||||||
|
|
||||||
|
class CreateDeviceTemplate(tackerV10.CreateCommand):
|
||||||
|
"""create a DeviceTemplate."""
|
||||||
|
|
||||||
|
resource = _DEVICE_TEMPLATE
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--name',
|
||||||
|
help='Set a name for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--description',
|
||||||
|
help='Set a description for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--template-service-type',
|
||||||
|
action='append',
|
||||||
|
help='Add a servicetype for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--device-driver',
|
||||||
|
help='Set a device driver name for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--mgmt-driver',
|
||||||
|
help='Set a manegement driver name for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--attribute',
|
||||||
|
nargs=2,
|
||||||
|
action='append',
|
||||||
|
help='Set a servicetypes for the devicetemplate')
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {
|
||||||
|
self.resource: {
|
||||||
|
'service_types': [
|
||||||
|
{'service_type': service_type}
|
||||||
|
for service_type in parsed_args.template_service_type],
|
||||||
|
'device_driver': parsed_args.device_driver,
|
||||||
|
'mgmt_driver': parsed_args.mgmt_driver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsed_args.attribute:
|
||||||
|
body[self.resource]['attributes'] = dict(parsed_args.attribute)
|
||||||
|
tackerV10.update_dict(parsed_args, body[self.resource],
|
||||||
|
['tenant_id', 'name', 'description'])
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateDeviceTemplate(tackerV10.UpdateCommand):
|
||||||
|
"""Update a given DeviceTemplate."""
|
||||||
|
|
||||||
|
resource = _DEVICE_TEMPLATE
|
||||||
|
allow_names = False
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteDeviceTemplate(tackerV10.DeleteCommand):
|
||||||
|
"""Delete a given DeviceTemplate."""
|
||||||
|
resource = _DEVICE_TEMPLATE
|
164
tackerclient/tacker/v1_0/vm/service_instance.py
Normal file
164
tackerclient/tacker/v1_0/vm/service_instance.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2013 Intel
|
||||||
|
# Copyright 2013 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
from tackerclient.common import exceptions
|
||||||
|
from tackerclient.openstack.common.gettextutils import _
|
||||||
|
from tackerclient.tacker import v1_0 as tackerV10
|
||||||
|
|
||||||
|
|
||||||
|
_SERVICE_INSTANCE = 'service_instance'
|
||||||
|
|
||||||
|
|
||||||
|
class ListServiceInstance(tackerV10.ListCommand):
|
||||||
|
"""List service instance that belong to a given tenant."""
|
||||||
|
|
||||||
|
resource = _SERVICE_INSTANCE
|
||||||
|
|
||||||
|
|
||||||
|
class ShowServiceInstance(tackerV10.ShowCommand):
|
||||||
|
"""show information of a given ServiceInstance."""
|
||||||
|
|
||||||
|
resource = _SERVICE_INSTANCE
|
||||||
|
|
||||||
|
|
||||||
|
class CreateServiceInstance(tackerV10.CreateCommand):
|
||||||
|
"""create a ServiceInstance."""
|
||||||
|
|
||||||
|
resource = _SERVICE_INSTANCE
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--name',
|
||||||
|
default=None,
|
||||||
|
help='Set a name for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--service-type-id',
|
||||||
|
required=True,
|
||||||
|
help='service type id to create service instance based on')
|
||||||
|
parser.add_argument(
|
||||||
|
'--service-table-id',
|
||||||
|
required=True,
|
||||||
|
help='service type id to create service instance based on')
|
||||||
|
parser.add_argument(
|
||||||
|
'--mgmt-driver',
|
||||||
|
default=None,
|
||||||
|
help='Set a manegement driver name for the service instance')
|
||||||
|
parser.add_argument(
|
||||||
|
'--service-context',
|
||||||
|
metavar='<network-id=network-uuid,subnet-id=subnet-uuid,'
|
||||||
|
'port-id=port-uuid,router-id=router-uuid,'
|
||||||
|
'role=role-string,index=int>',
|
||||||
|
action='append',
|
||||||
|
dest='service_context',
|
||||||
|
default=[],
|
||||||
|
help='service context to insert service')
|
||||||
|
parser.add_argument(
|
||||||
|
'--device',
|
||||||
|
required=True,
|
||||||
|
help='Set a device for the service instance to create on')
|
||||||
|
parser.add_argument(
|
||||||
|
'--kwargs',
|
||||||
|
metavar='<key>=<value>',
|
||||||
|
action='append',
|
||||||
|
dest='kwargs',
|
||||||
|
default=[],
|
||||||
|
help='instance specific argument')
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {
|
||||||
|
self.resource: {
|
||||||
|
'service_type_id': parsed_args.service_type_id,
|
||||||
|
'service_table_id': parsed_args.service_table_id,
|
||||||
|
'devices': [parsed_args.device],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsed_args.name is not None:
|
||||||
|
body[self.resource]['name'] = parsed_args.name
|
||||||
|
if parsed_args.mgmt_driver is not None:
|
||||||
|
body[self.resource]['mgmt_driver'] = parsed_args.mgmt_driver
|
||||||
|
if parsed_args.kwargs:
|
||||||
|
try:
|
||||||
|
kwargs = dict(key_value.split('=', 1)
|
||||||
|
for key_value in parsed_args.kwargs)
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --kwargs %s') %
|
||||||
|
parsed_args.kwargs)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
if kwargs:
|
||||||
|
body[self.resource]['kwargs'] = kwargs
|
||||||
|
if parsed_args.service_context:
|
||||||
|
try:
|
||||||
|
service_context = [dict(
|
||||||
|
(k.replace('-', '_'), v)
|
||||||
|
for k, v in (key_value.split('=', 1)
|
||||||
|
for key_value in entry_string.split(',')))
|
||||||
|
for entry_string in parsed_args.service_context]
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --service-context %s') %
|
||||||
|
parsed_args.service_context)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
|
||||||
|
if service_context:
|
||||||
|
body[self.resource]['service_context'] = service_context
|
||||||
|
|
||||||
|
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateServiceInstance(tackerV10.UpdateCommand):
|
||||||
|
"""Update a given ServiceInstance."""
|
||||||
|
|
||||||
|
resource = _SERVICE_INSTANCE
|
||||||
|
|
||||||
|
def add_known_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--name',
|
||||||
|
help='Set a name for the devicetemplate')
|
||||||
|
parser.add_argument(
|
||||||
|
'--kwargs',
|
||||||
|
metavar='<key>=<value>',
|
||||||
|
action='append',
|
||||||
|
dest='kwargs',
|
||||||
|
default=[],
|
||||||
|
help='instance specific argument')
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
body = {self.resource: {}}
|
||||||
|
if parsed_args.name:
|
||||||
|
body[self.resource]['name'] = parsed_args.name
|
||||||
|
if parsed_args.kwargs:
|
||||||
|
try:
|
||||||
|
kwargs = dict(key_value.split('=', 1)
|
||||||
|
for key_value in parsed_args.kwargs)
|
||||||
|
except ValueError:
|
||||||
|
msg = (_('invalid argument for --kwargs %s') %
|
||||||
|
parsed_args.kwargs)
|
||||||
|
raise exceptions.TackerCLIError(msg)
|
||||||
|
if kwargs:
|
||||||
|
body[self.resource]['kwargs'] = kwargs
|
||||||
|
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteServiceInstance(tackerV10.DeleteCommand):
|
||||||
|
"""Delete a given ServiceInstance."""
|
||||||
|
|
||||||
|
resource = _SERVICE_INSTANCE
|
0
tackerclient/tests/unit/vm/__init__.py
Normal file
0
tackerclient/tests/unit/vm/__init__.py
Normal file
126
tackerclient/tests/unit/vm/test_cli10_device.py
Normal file
126
tackerclient/tests/unit/vm/test_cli10_device.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2014 Intel
|
||||||
|
# Copyright 2014 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from tackerclient.tacker.v1_0.vm import device
|
||||||
|
from tackerclient.tests.unit import test_cli10
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmDeviceJSON(test_cli10.CLITestV10Base):
|
||||||
|
_RESOURCE = 'device'
|
||||||
|
_RESOURCES = 'devices'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
plurals = {'devices': 'device'}
|
||||||
|
super(CLITestV10VmDeviceJSON, self).setUp(plurals=plurals)
|
||||||
|
|
||||||
|
def test_create_device_all_params(self):
|
||||||
|
cmd = device.CreateDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
template_id = 'template_id'
|
||||||
|
key = 'key'
|
||||||
|
value = 'value'
|
||||||
|
network_id = 'network_id'
|
||||||
|
subnet_id = 'subnet_id'
|
||||||
|
port_id = 'port_id'
|
||||||
|
router_id = 'router_id'
|
||||||
|
role = 'role'
|
||||||
|
index = 1
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'--device-template-id', template_id,
|
||||||
|
'--kwargs', '%s=%s' % (key, value),
|
||||||
|
'--service-context',
|
||||||
|
('network-id=%s,subnet-id=%s,port-id=%s,router-id=%s,'
|
||||||
|
'role=%s,index=%s' % (network_id, subnet_id, port_id, router_id,
|
||||||
|
role, index))
|
||||||
|
]
|
||||||
|
position_names = ['template_id']
|
||||||
|
position_values = [template_id]
|
||||||
|
extra_body = {
|
||||||
|
'kwargs': {
|
||||||
|
key: value
|
||||||
|
},
|
||||||
|
'service_context': [{
|
||||||
|
'network_id': network_id,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'port_id': port_id,
|
||||||
|
'router_id': router_id,
|
||||||
|
'role': role,
|
||||||
|
'index': str(index),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values,
|
||||||
|
extra_body=extra_body)
|
||||||
|
|
||||||
|
def test_create_device_with_mandatory_params(self):
|
||||||
|
cmd = device.CreateDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
template_id = 'template_id'
|
||||||
|
args = [
|
||||||
|
'--device-template-id', template_id,
|
||||||
|
]
|
||||||
|
position_names = ['template_id']
|
||||||
|
position_values = [template_id]
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values)
|
||||||
|
|
||||||
|
def test_list_devices(self):
|
||||||
|
cmd = device.ListDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_list_devices_pagenation(self):
|
||||||
|
cmd = device.ListDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_show_device_id(self):
|
||||||
|
cmd = device.ShowDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
args = ['--fields', 'id', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id, args,
|
||||||
|
['id'])
|
||||||
|
|
||||||
|
def test_show_device_id_name(self):
|
||||||
|
cmd = device.ShowDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
args = ['--fields', 'id', '--fields', 'name', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
|
||||||
|
args, ['id', 'name'])
|
||||||
|
|
||||||
|
def test_update_device(self):
|
||||||
|
cmd = device.UpdateDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
key = 'new-key'
|
||||||
|
value = 'new-value'
|
||||||
|
self._test_update_resource(self._RESOURCE, cmd, my_id,
|
||||||
|
[my_id, '--kwargs', '%s=%s' % (key, value)],
|
||||||
|
{'kwargs': {key: value}})
|
||||||
|
|
||||||
|
def test_delete_device(self):
|
||||||
|
cmd = device.DeleteDevice(test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
args = [my_id]
|
||||||
|
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmDeviceXML(CLITestV10VmDeviceJSON):
|
||||||
|
format = 'xml'
|
132
tackerclient/tests/unit/vm/test_cli10_device_template.py
Normal file
132
tackerclient/tests/unit/vm/test_cli10_device_template.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2014 Intel
|
||||||
|
# Copyright 2014 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from tackerclient.tacker.v1_0.vm import device_template
|
||||||
|
from tackerclient.tests.unit import test_cli10
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmDeviceTemplateJSON(test_cli10.CLITestV10Base):
|
||||||
|
_RESOURCE = 'device_template'
|
||||||
|
_RESOURCES = 'device_templates'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
plurals = {'device_templates': 'device_template'}
|
||||||
|
super(CLITestV10VmDeviceTemplateJSON, self).setUp(plurals=plurals)
|
||||||
|
|
||||||
|
def test_create_device_template_all_params(self):
|
||||||
|
cmd = device_template.CreateDeviceTemplate(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
name = 'my-name'
|
||||||
|
description = 'my-description'
|
||||||
|
service_type = 'MY-SERVICE'
|
||||||
|
device_driver = 'device-driver'
|
||||||
|
mgmt_driver = 'mgmt-driver'
|
||||||
|
attr_key = 'attr-key'
|
||||||
|
attr_val = 'attr-val'
|
||||||
|
args = [
|
||||||
|
'--name', name,
|
||||||
|
'--description', description,
|
||||||
|
'--template-service-type', service_type,
|
||||||
|
'--device-driver', device_driver,
|
||||||
|
'--mgmt-driver', mgmt_driver,
|
||||||
|
'--attribute', attr_key, attr_val,
|
||||||
|
]
|
||||||
|
position_names = ['name', 'description',
|
||||||
|
'device_driver', 'mgmt_driver']
|
||||||
|
position_values = [name, description, device_driver, mgmt_driver]
|
||||||
|
extra_body = {
|
||||||
|
'service_types': [{'service_type': service_type}],
|
||||||
|
'attributes': {attr_key: attr_val},
|
||||||
|
}
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values,
|
||||||
|
extra_body=extra_body)
|
||||||
|
|
||||||
|
def test_create_device_template_with_mandatory_params(self):
|
||||||
|
cmd = device_template.CreateDeviceTemplate(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
service_type = 'MY-SERVICE'
|
||||||
|
device_driver = 'device-driver'
|
||||||
|
mgmt_driver = 'mgmt-driver'
|
||||||
|
args = [
|
||||||
|
'--template-service-type', service_type,
|
||||||
|
'--device-driver', device_driver,
|
||||||
|
'--mgmt-driver', mgmt_driver,
|
||||||
|
]
|
||||||
|
position_names = ['device_driver', 'mgmt_driver']
|
||||||
|
position_values = [device_driver, mgmt_driver]
|
||||||
|
extra_body = {
|
||||||
|
'service_types': [{'service_type': service_type}],
|
||||||
|
}
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values,
|
||||||
|
extra_body=extra_body)
|
||||||
|
|
||||||
|
def test_list_device_templates(self):
|
||||||
|
cmd = device_template.ListDeviceTemplate(test_cli10.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_list_device_templates_pagenation(self):
|
||||||
|
cmd = device_template.ListDeviceTemplate(test_cli10.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_show_device_template_id(self):
|
||||||
|
cmd = device_template.ShowDeviceTemplate(test_cli10.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['--fields', 'id', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id, args,
|
||||||
|
['id'])
|
||||||
|
|
||||||
|
def test_show_device_template_id_name(self):
|
||||||
|
cmd = device_template.ShowDeviceTemplate(test_cli10.MyApp(sys.stdout),
|
||||||
|
None)
|
||||||
|
args = ['--fields', 'id', '--fields', 'name', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
|
||||||
|
args, ['id', 'name'])
|
||||||
|
|
||||||
|
def test_update_device_template(self):
|
||||||
|
cmd = device_template.UpdateDeviceTemplate(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
name = 'new-name'
|
||||||
|
description = 'new-description'
|
||||||
|
self._test_update_resource(self._RESOURCE, cmd, my_id,
|
||||||
|
[my_id, '--name', name,
|
||||||
|
'--description', description],
|
||||||
|
{'name': name, 'description': description})
|
||||||
|
|
||||||
|
def test_delete_device_tempalte(self):
|
||||||
|
cmd = device_template.DeleteDeviceTemplate(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
args = [my_id]
|
||||||
|
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmDeviceTemplateXML(CLITestV10VmDeviceTemplateJSON):
|
||||||
|
format = 'xml'
|
155
tackerclient/tests/unit/vm/test_cli10_service_instance.py
Normal file
155
tackerclient/tests/unit/vm/test_cli10_service_instance.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2014 Intel
|
||||||
|
# Copyright 2014 Isaku Yamahata <isaku.yamahata at intel com>
|
||||||
|
# <isaku.yamahata at gmail com>
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @author: Isaku Yamahata, Intel
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from tackerclient.tacker.v1_0.vm import service_instance
|
||||||
|
from tackerclient.tests.unit import test_cli10
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmServiceInstanceJSON(test_cli10.CLITestV10Base):
|
||||||
|
_RESOURCE = 'service_instance'
|
||||||
|
_RESOURCES = 'service_instances'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
plurals = {'service_instances': 'service_instance'}
|
||||||
|
super(CLITestV10VmServiceInstanceJSON, self).setUp(plurals=plurals)
|
||||||
|
|
||||||
|
def test_create_service_instance_all_params(self):
|
||||||
|
cmd = service_instance.CreateServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
name = 'my-name'
|
||||||
|
service_type_id = 'service-type-id'
|
||||||
|
service_table_id = 'service-table-id'
|
||||||
|
mgmt_driver = 'mgmt-driver'
|
||||||
|
network_id = 'network_id'
|
||||||
|
subnet_id = 'subnet_id'
|
||||||
|
port_id = 'port_id'
|
||||||
|
router_id = 'router_id'
|
||||||
|
role = 'role'
|
||||||
|
index = 1
|
||||||
|
|
||||||
|
device = 'my-device'
|
||||||
|
|
||||||
|
key = 'key'
|
||||||
|
value = 'value'
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'--name', name,
|
||||||
|
'--service-type-id', service_type_id,
|
||||||
|
'--service-table-id', service_table_id,
|
||||||
|
'--mgmt-driver', mgmt_driver,
|
||||||
|
'--service-context',
|
||||||
|
('network-id=%s,subnet-id=%s,port-id=%s,router-id=%s,'
|
||||||
|
'role=%s,index=%s' % (network_id, subnet_id, port_id, router_id,
|
||||||
|
role, index)),
|
||||||
|
'--device', device,
|
||||||
|
'--kwargs', '%s=%s' % (key, value),
|
||||||
|
]
|
||||||
|
position_names = ['name', 'service_type_id', 'service_table_id',
|
||||||
|
'mgmt_driver']
|
||||||
|
position_values = [name, service_type_id, service_table_id,
|
||||||
|
mgmt_driver]
|
||||||
|
extra_body = {
|
||||||
|
'devices': [device],
|
||||||
|
'service_context': [{
|
||||||
|
'network_id': network_id,
|
||||||
|
'subnet_id': subnet_id,
|
||||||
|
'port_id': port_id,
|
||||||
|
'router_id': router_id,
|
||||||
|
'role': role,
|
||||||
|
'index': str(index),
|
||||||
|
}],
|
||||||
|
'kwargs': {
|
||||||
|
key: value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values,
|
||||||
|
extra_body=extra_body)
|
||||||
|
|
||||||
|
def test_create_service_instance_with_mandatory_params(self):
|
||||||
|
cmd = service_instance.CreateServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
service_type_id = 'service-type-id'
|
||||||
|
service_table_id = 'service-table-id'
|
||||||
|
device = 'my-device'
|
||||||
|
args = [
|
||||||
|
'--service-type-id', service_type_id,
|
||||||
|
'--service-table-id', service_table_id,
|
||||||
|
'--device', device,
|
||||||
|
]
|
||||||
|
position_names = ['service_type_id', 'service_table_id']
|
||||||
|
position_values = [service_type_id, service_table_id]
|
||||||
|
extra_body = {
|
||||||
|
'devices': [device],
|
||||||
|
}
|
||||||
|
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
|
||||||
|
args, position_names, position_values,
|
||||||
|
extra_body=extra_body)
|
||||||
|
|
||||||
|
def test_list_service_instances(self):
|
||||||
|
cmd = service_instance.ListServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_list_service_instances_pagenation(self):
|
||||||
|
cmd = service_instance.ListServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
self._test_list_resources(self._RESOURCES, cmd, True)
|
||||||
|
|
||||||
|
def test_show_service_instance_id(self):
|
||||||
|
cmd = service_instance.ShowServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
args = ['--fields', 'id', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id, args,
|
||||||
|
['id'])
|
||||||
|
|
||||||
|
def test_show_service_instance_id_name(self):
|
||||||
|
cmd = service_instance.ShowServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
args = ['--fields', 'id', '--fields', 'name', self.test_id]
|
||||||
|
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
|
||||||
|
args, ['id', 'name'])
|
||||||
|
|
||||||
|
def test_update_service_instance(self):
|
||||||
|
cmd = service_instance.UpdateServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
key = 'new-key'
|
||||||
|
value = 'new-value'
|
||||||
|
self._test_update_resource(self._RESOURCE, cmd, my_id,
|
||||||
|
[my_id, '--kwargs', '%s=%s' % (key, value)],
|
||||||
|
{'kwargs': {key: value}})
|
||||||
|
|
||||||
|
def test_delete_service_instance(self):
|
||||||
|
cmd = service_instance.DeleteServiceInstance(
|
||||||
|
test_cli10.MyApp(sys.stdout), None)
|
||||||
|
my_id = 'my-id'
|
||||||
|
args = [my_id]
|
||||||
|
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV10VmServiceInstanceXML(CLITestV10VmServiceInstanceJSON):
|
||||||
|
format = 'xml'
|
411
tackerclient/v1_0/client.py
Normal file
411
tackerclient/v1_0/client.py
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
# Copyright 2012 OpenStack Foundation.
|
||||||
|
# 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 logging
|
||||||
|
import time
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import six.moves.urllib.parse as urlparse
|
||||||
|
|
||||||
|
from tackerclient import client
|
||||||
|
from tackerclient.common import _
|
||||||
|
from tackerclient.common import constants
|
||||||
|
from tackerclient.common import exceptions
|
||||||
|
from tackerclient.common import serializer
|
||||||
|
from tackerclient.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def exception_handler_v10(status_code, error_content):
|
||||||
|
"""Exception handler for API v1.0 client
|
||||||
|
|
||||||
|
This routine generates the appropriate
|
||||||
|
Tacker exception according to the contents of the
|
||||||
|
response body
|
||||||
|
|
||||||
|
:param status_code: HTTP error status code
|
||||||
|
:param error_content: deserialized body of error response
|
||||||
|
"""
|
||||||
|
error_dict = None
|
||||||
|
if isinstance(error_content, dict):
|
||||||
|
error_dict = error_content.get('TackerError')
|
||||||
|
# Find real error type
|
||||||
|
bad_tacker_error_flag = False
|
||||||
|
if error_dict:
|
||||||
|
# If Tacker key is found, it will definitely contain
|
||||||
|
# a 'message' and 'type' keys?
|
||||||
|
try:
|
||||||
|
error_type = error_dict['type']
|
||||||
|
error_message = error_dict['message']
|
||||||
|
if error_dict['detail']:
|
||||||
|
error_message += "\n" + error_dict['detail']
|
||||||
|
except Exception:
|
||||||
|
bad_tacker_error_flag = True
|
||||||
|
if not bad_tacker_error_flag:
|
||||||
|
# If corresponding exception is defined, use it.
|
||||||
|
client_exc = getattr(exceptions, '%sClient' % error_type, None)
|
||||||
|
# Otherwise look up per status-code client exception
|
||||||
|
if not client_exc:
|
||||||
|
client_exc = exceptions.HTTP_EXCEPTION_MAP.get(status_code)
|
||||||
|
if client_exc:
|
||||||
|
raise client_exc(message=error_message,
|
||||||
|
status_code=status_code)
|
||||||
|
else:
|
||||||
|
raise exceptions.TackerClientException(
|
||||||
|
status_code=status_code, message=error_message)
|
||||||
|
else:
|
||||||
|
raise exceptions.TackerClientException(status_code=status_code,
|
||||||
|
message=error_dict)
|
||||||
|
else:
|
||||||
|
message = None
|
||||||
|
if isinstance(error_content, dict):
|
||||||
|
message = error_content.get('message')
|
||||||
|
if message:
|
||||||
|
raise exceptions.TackerClientException(status_code=status_code,
|
||||||
|
message=message)
|
||||||
|
|
||||||
|
# If we end up here the exception was not a tacker error
|
||||||
|
msg = "%s-%s" % (status_code, error_content)
|
||||||
|
raise exceptions.TackerClientException(status_code=status_code,
|
||||||
|
message=msg)
|
||||||
|
|
||||||
|
|
||||||
|
class APIParamsCall(object):
|
||||||
|
"""A Decorator to add support for format and tenant overriding
|
||||||
|
and filters
|
||||||
|
"""
|
||||||
|
def __init__(self, function):
|
||||||
|
self.function = function
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
def with_params(*args, **kwargs):
|
||||||
|
_format = instance.format
|
||||||
|
if 'format' in kwargs:
|
||||||
|
instance.format = kwargs['format']
|
||||||
|
ret = self.function(instance, *args, **kwargs)
|
||||||
|
instance.format = _format
|
||||||
|
return ret
|
||||||
|
return with_params
|
||||||
|
|
||||||
|
|
||||||
|
class Client(object):
|
||||||
|
"""Client for the OpenStack Tacker v1.0 API.
|
||||||
|
|
||||||
|
:param string username: Username for authentication. (optional)
|
||||||
|
:param string user_id: User ID for authentication. (optional)
|
||||||
|
:param string password: Password for authentication. (optional)
|
||||||
|
:param string token: Token for authentication. (optional)
|
||||||
|
:param string tenant_name: Tenant name. (optional)
|
||||||
|
:param string tenant_id: Tenant id. (optional)
|
||||||
|
:param string auth_url: Keystone service endpoint for authorization.
|
||||||
|
:param string service_type: Network service type to pull from the
|
||||||
|
keystone catalog (e.g. 'network') (optional)
|
||||||
|
:param string endpoint_type: Network service endpoint type to pull from the
|
||||||
|
keystone catalog (e.g. 'publicURL',
|
||||||
|
'internalURL', or 'adminURL') (optional)
|
||||||
|
:param string region_name: Name of a region to select when choosing an
|
||||||
|
endpoint from the service catalog.
|
||||||
|
:param string endpoint_url: A user-supplied endpoint URL for the tacker
|
||||||
|
service. Lazy-authentication is possible for API
|
||||||
|
service calls if endpoint is set at
|
||||||
|
instantiation.(optional)
|
||||||
|
:param integer timeout: Allows customization of the timeout for client
|
||||||
|
http requests. (optional)
|
||||||
|
:param bool insecure: SSL certificate validation. (optional)
|
||||||
|
:param string ca_cert: SSL CA bundle file to use. (optional)
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
from tackerclient.v1_0 import client
|
||||||
|
tacker = client.Client(username=USER,
|
||||||
|
password=PASS,
|
||||||
|
tenant_name=TENANT_NAME,
|
||||||
|
auth_url=KEYSTONE_URL)
|
||||||
|
|
||||||
|
nets = tacker.list_networks()
|
||||||
|
...
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
extensions_path = "/extensions"
|
||||||
|
extension_path = "/extensions/%s"
|
||||||
|
|
||||||
|
device_templates_path = '/device-templates'
|
||||||
|
device_template_path = '/device-templates/%s'
|
||||||
|
service_instances_path = '/service-instances'
|
||||||
|
service_instance_path = '/service-instances/%s'
|
||||||
|
devices_path = '/devices'
|
||||||
|
device_path = '/devices/%s'
|
||||||
|
|
||||||
|
# API has no way to report plurals, so we have to hard code them
|
||||||
|
EXTED_PLURALS = {}
|
||||||
|
# 8192 Is the default max URI len for eventlet.wsgi.server
|
||||||
|
MAX_URI_LEN = 8192
|
||||||
|
|
||||||
|
def get_attr_metadata(self):
|
||||||
|
if self.format == 'json':
|
||||||
|
return {}
|
||||||
|
old_request_format = self.format
|
||||||
|
self.format = 'json'
|
||||||
|
exts = self.list_extensions()['extensions']
|
||||||
|
self.format = old_request_format
|
||||||
|
ns = dict([(ext['alias'], ext['namespace']) for ext in exts])
|
||||||
|
self.EXTED_PLURALS.update(constants.PLURALS)
|
||||||
|
return {'plurals': self.EXTED_PLURALS,
|
||||||
|
'xmlns': constants.XML_NS_V10,
|
||||||
|
constants.EXT_NS: ns}
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_extensions(self, **_params):
|
||||||
|
"""Fetch a list of all exts on server side."""
|
||||||
|
return self.get(self.extensions_path, params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_extension(self, ext_alias, **_params):
|
||||||
|
"""Fetch a list of all exts on server side."""
|
||||||
|
return self.get(self.extension_path % ext_alias, params=_params)
|
||||||
|
|
||||||
|
def list_device_templates(self, retrieve_all=True, **_params):
|
||||||
|
return self.list('device_templates', self.device_templates_path,
|
||||||
|
retrieve_all, **_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_device_template(self, device_template, **_params):
|
||||||
|
return self.get(self.device_template_path % device_template,
|
||||||
|
params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def update_device_template(self, device_template, body=None):
|
||||||
|
return self.put(self.device_template_path % device_template, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_device_template(self, body=None):
|
||||||
|
return self.post(self.device_templates_path, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_device_template(self, device_template):
|
||||||
|
return self.delete(self.device_template_path % device_template)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_service_instances(self, retrieve_all=True, **_params):
|
||||||
|
return self.list('service_instances', self.service_instances_path,
|
||||||
|
retrieve_all, **_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_service_instance(self, service_instance, **_params):
|
||||||
|
return self.get(self.service_instance_path % service_instance,
|
||||||
|
params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def update_service_instance(self, service_instance, body=None):
|
||||||
|
return self.put(self.service_instance_path % service_instance,
|
||||||
|
body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_service_instance(self, body=None):
|
||||||
|
return self.post(self.service_instances_path, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_service_instance(self, service_instance):
|
||||||
|
return self.delete(self.service_instance_path % service_instance)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def list_devices(self, retrieve_all=True, **_params):
|
||||||
|
return self.list('devices', self.devices_path, retrieve_all, **_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def show_device(self, device, **_params):
|
||||||
|
return self.get(self.device_path % device, params=_params)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def update_device(self, device, body=None):
|
||||||
|
return self.put(self.device_path % device, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def create_device(self, body=None):
|
||||||
|
return self.post(self.devices_path, body=body)
|
||||||
|
|
||||||
|
@APIParamsCall
|
||||||
|
def delete_device(self, device):
|
||||||
|
return self.delete(self.device_path % device)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
"""Initialize a new client for the Tacker v1.0 API."""
|
||||||
|
super(Client, self).__init__()
|
||||||
|
self.httpclient = client.HTTPClient(**kwargs)
|
||||||
|
self.version = '1.0'
|
||||||
|
self.format = 'json'
|
||||||
|
self.action_prefix = "/v%s" % (self.version)
|
||||||
|
self.retries = 0
|
||||||
|
self.retry_interval = 1
|
||||||
|
|
||||||
|
def _handle_fault_response(self, status_code, response_body):
|
||||||
|
# Create exception with HTTP status code and message
|
||||||
|
_logger.debug(_("Error message: %s"), response_body)
|
||||||
|
# Add deserialized error message to exception arguments
|
||||||
|
try:
|
||||||
|
des_error_body = self.deserialize(response_body, status_code)
|
||||||
|
except Exception:
|
||||||
|
# If unable to deserialized body it is probably not a
|
||||||
|
# Tacker error
|
||||||
|
des_error_body = {'message': response_body}
|
||||||
|
# Raise the appropriate exception
|
||||||
|
exception_handler_v10(status_code, des_error_body)
|
||||||
|
|
||||||
|
def _check_uri_length(self, action):
|
||||||
|
uri_len = len(self.httpclient.endpoint_url) + len(action)
|
||||||
|
if uri_len > self.MAX_URI_LEN:
|
||||||
|
raise exceptions.RequestURITooLong(
|
||||||
|
excess=uri_len - self.MAX_URI_LEN)
|
||||||
|
|
||||||
|
def do_request(self, method, action, body=None, headers=None, params=None):
|
||||||
|
# Add format and tenant_id
|
||||||
|
action += ".%s" % self.format
|
||||||
|
action = self.action_prefix + action
|
||||||
|
if type(params) is dict and params:
|
||||||
|
params = utils.safe_encode_dict(params)
|
||||||
|
action += '?' + urllib.urlencode(params, doseq=1)
|
||||||
|
# Ensure client always has correct uri - do not guesstimate anything
|
||||||
|
self.httpclient.authenticate_and_fetch_endpoint_url()
|
||||||
|
self._check_uri_length(action)
|
||||||
|
|
||||||
|
if body:
|
||||||
|
body = self.serialize(body)
|
||||||
|
self.httpclient.content_type = self.content_type()
|
||||||
|
resp, replybody = self.httpclient.do_request(action, method, body=body)
|
||||||
|
status_code = self.get_status_code(resp)
|
||||||
|
if status_code in (requests.codes.ok,
|
||||||
|
requests.codes.created,
|
||||||
|
requests.codes.accepted,
|
||||||
|
requests.codes.no_content):
|
||||||
|
return self.deserialize(replybody, status_code)
|
||||||
|
else:
|
||||||
|
if not replybody:
|
||||||
|
replybody = resp.reason
|
||||||
|
self._handle_fault_response(status_code, replybody)
|
||||||
|
|
||||||
|
def get_auth_info(self):
|
||||||
|
return self.httpclient.get_auth_info()
|
||||||
|
|
||||||
|
def get_status_code(self, response):
|
||||||
|
"""Returns the integer status code from the response.
|
||||||
|
|
||||||
|
Either a Webob.Response (used in testing) or requests.Response
|
||||||
|
is returned.
|
||||||
|
"""
|
||||||
|
if hasattr(response, 'status_int'):
|
||||||
|
return response.status_int
|
||||||
|
else:
|
||||||
|
return response.status_code
|
||||||
|
|
||||||
|
def serialize(self, data):
|
||||||
|
"""Serializes a dictionary into either xml or json.
|
||||||
|
|
||||||
|
A dictionary with a single key can be passed and
|
||||||
|
it can contain any structure.
|
||||||
|
"""
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
elif type(data) is dict:
|
||||||
|
return serializer.Serializer(
|
||||||
|
self.get_attr_metadata()).serialize(data, self.content_type())
|
||||||
|
else:
|
||||||
|
raise Exception(_("Unable to serialize object of type = '%s'") %
|
||||||
|
type(data))
|
||||||
|
|
||||||
|
def deserialize(self, data, status_code):
|
||||||
|
"""Deserializes an xml or json string into a dictionary."""
|
||||||
|
if status_code == 204:
|
||||||
|
return data
|
||||||
|
return serializer.Serializer(self.get_attr_metadata()).deserialize(
|
||||||
|
data, self.content_type())['body']
|
||||||
|
|
||||||
|
def content_type(self, _format=None):
|
||||||
|
"""Returns the mime-type for either 'xml' or 'json'.
|
||||||
|
|
||||||
|
Defaults to the currently set format.
|
||||||
|
"""
|
||||||
|
_format = _format or self.format
|
||||||
|
return "application/%s" % (_format)
|
||||||
|
|
||||||
|
def retry_request(self, method, action, body=None,
|
||||||
|
headers=None, params=None):
|
||||||
|
"""Call do_request with the default retry configuration.
|
||||||
|
|
||||||
|
Only idempotent requests should retry failed connection attempts.
|
||||||
|
:raises: ConnectionFailed if the maximum # of retries is exceeded
|
||||||
|
"""
|
||||||
|
max_attempts = self.retries + 1
|
||||||
|
for i in range(max_attempts):
|
||||||
|
try:
|
||||||
|
return self.do_request(method, action, body=body,
|
||||||
|
headers=headers, params=params)
|
||||||
|
except exceptions.ConnectionFailed:
|
||||||
|
# Exception has already been logged by do_request()
|
||||||
|
if i < self.retries:
|
||||||
|
_logger.debug(_('Retrying connection to Tacker service'))
|
||||||
|
time.sleep(self.retry_interval)
|
||||||
|
|
||||||
|
raise exceptions.ConnectionFailed(reason=_("Maximum attempts reached"))
|
||||||
|
|
||||||
|
def delete(self, action, body=None, headers=None, params=None):
|
||||||
|
return self.retry_request("DELETE", action, body=body,
|
||||||
|
headers=headers, params=params)
|
||||||
|
|
||||||
|
def get(self, action, body=None, headers=None, params=None):
|
||||||
|
return self.retry_request("GET", action, body=body,
|
||||||
|
headers=headers, params=params)
|
||||||
|
|
||||||
|
def post(self, action, body=None, headers=None, params=None):
|
||||||
|
# Do not retry POST requests to avoid the orphan objects problem.
|
||||||
|
return self.do_request("POST", action, body=body,
|
||||||
|
headers=headers, params=params)
|
||||||
|
|
||||||
|
def put(self, action, body=None, headers=None, params=None):
|
||||||
|
return self.retry_request("PUT", action, body=body,
|
||||||
|
headers=headers, params=params)
|
||||||
|
|
||||||
|
def list(self, collection, path, retrieve_all=True, **params):
|
||||||
|
if retrieve_all:
|
||||||
|
res = []
|
||||||
|
for r in self._pagination(collection, path, **params):
|
||||||
|
res.extend(r[collection])
|
||||||
|
return {collection: res}
|
||||||
|
else:
|
||||||
|
return self._pagination(collection, path, **params)
|
||||||
|
|
||||||
|
def _pagination(self, collection, path, **params):
|
||||||
|
if params.get('page_reverse', False):
|
||||||
|
linkrel = 'previous'
|
||||||
|
else:
|
||||||
|
linkrel = 'next'
|
||||||
|
next = True
|
||||||
|
while next:
|
||||||
|
res = self.get(path, params=params)
|
||||||
|
yield res
|
||||||
|
next = False
|
||||||
|
try:
|
||||||
|
for link in res['%s_links' % collection]:
|
||||||
|
if link['rel'] == linkrel:
|
||||||
|
query_str = urlparse.urlparse(link['href']).query
|
||||||
|
params = urlparse.parse_qs(query_str)
|
||||||
|
next = True
|
||||||
|
break
|
||||||
|
except KeyError:
|
||||||
|
break
|
Loading…
Reference in New Issue
Block a user