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
|
||||
@ -28,46 +28,20 @@ import sys
|
||||
from cliff import app
|
||||
from cliff import commandmanager
|
||||
|
||||
from neutronclient.common import clientmanager
|
||||
from neutronclient.common import exceptions as exc
|
||||
from neutronclient.common import utils
|
||||
from neutronclient.neutron.v2_0 import agent
|
||||
from neutronclient.neutron.v2_0 import agentscheduler
|
||||
from neutronclient.neutron.v2_0 import credential
|
||||
from neutronclient.neutron.v2_0 import extension
|
||||
from neutronclient.neutron.v2_0 import floatingip
|
||||
from neutronclient.neutron.v2_0.fw import firewall
|
||||
from neutronclient.neutron.v2_0.fw import firewallpolicy
|
||||
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__
|
||||
from tackerclient.common import clientmanager
|
||||
from tackerclient.common import exceptions as exc
|
||||
from tackerclient.common import utils
|
||||
from tackerclient.openstack.common.gettextutils import _
|
||||
from tackerclient.openstack.common import strutils
|
||||
from tackerclient.tacker.v1_0 import extension
|
||||
from tackerclient.tacker.v1_0.vm import device
|
||||
from tackerclient.tacker.v1_0.vm import device_template
|
||||
from tackerclient.tacker.v1_0.vm import service_instance
|
||||
from tackerclient.version import __version__
|
||||
|
||||
|
||||
VERSION = '2.0'
|
||||
NEUTRON_API_VERSION = '2.0'
|
||||
VERSION = '1.0'
|
||||
TACKER_API_VERSION = '1.0'
|
||||
|
||||
|
||||
def run_command(cmd, cmd_parser, sub_argv):
|
||||
@ -97,189 +71,27 @@ def env(*_vars, **kwargs):
|
||||
return kwargs.get('default', '')
|
||||
|
||||
|
||||
COMMAND_V2 = {
|
||||
'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,
|
||||
COMMAND_V1 = {
|
||||
'ext-list': extension.ListExt,
|
||||
'ext-show': extension.ShowExt,
|
||||
'router-list': router.ListRouter,
|
||||
'router-port-list': port.ListRouterPort,
|
||||
'router-show': router.ShowRouter,
|
||||
'router-create': router.CreateRouter,
|
||||
'router-delete': router.DeleteRouter,
|
||||
'router-update': router.UpdateRouter,
|
||||
'router-interface-add': router.AddInterfaceRouter,
|
||||
'router-interface-delete': router.RemoveInterfaceRouter,
|
||||
'router-gateway-set': router.SetGatewayRouter,
|
||||
'router-gateway-clear': router.RemoveGatewayRouter,
|
||||
'floatingip-list': floatingip.ListFloatingIP,
|
||||
'floatingip-show': floatingip.ShowFloatingIP,
|
||||
'floatingip-create': floatingip.CreateFloatingIP,
|
||||
'floatingip-delete': floatingip.DeleteFloatingIP,
|
||||
'floatingip-associate': floatingip.AssociateFloatingIP,
|
||||
'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,
|
||||
'device-template-create': device_template.CreateDeviceTemplate,
|
||||
'device-template-list': device_template.ListDeviceTemplate,
|
||||
'device-template-show': device_template.ShowDeviceTemplate,
|
||||
'device-template-update': device_template.UpdateDeviceTemplate,
|
||||
'device-template-delete': device_template.DeleteDeviceTemplate,
|
||||
'service-instance-create': service_instance.CreateServiceInstance,
|
||||
'service-instance-list': service_instance.ListServiceInstance,
|
||||
'service-instance-show': service_instance.ShowServiceInstance,
|
||||
'service-instance-update': service_instance.UpdateServiceInstance,
|
||||
'service-instance-delete': service_instance.DeleteServiceInstance,
|
||||
'device-create': device.CreateDevice,
|
||||
'device-list': device.ListDevice,
|
||||
'device-show': device.ShowDevice,
|
||||
'device-update': device.UpdateDevice,
|
||||
'device-delete': device.DeleteDevice,
|
||||
}
|
||||
|
||||
COMMANDS = {'2.0': COMMAND_V2}
|
||||
COMMANDS = {'1.0': COMMAND_V1}
|
||||
|
||||
|
||||
class HelpAction(argparse.Action):
|
||||
@ -307,7 +119,7 @@ class HelpAction(argparse.Action):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
class NeutronShell(app.App):
|
||||
class TackerShell(app.App):
|
||||
|
||||
# verbose logging levels
|
||||
WARNING_LEVEL = 0
|
||||
@ -318,10 +130,10 @@ class NeutronShell(app.App):
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def __init__(self, apiversion):
|
||||
super(NeutronShell, self).__init__(
|
||||
super(TackerShell, self).__init__(
|
||||
description=__doc__.strip(),
|
||||
version=VERSION,
|
||||
command_manager=commandmanager.CommandManager('neutron.cli'), )
|
||||
command_manager=commandmanager.CommandManager('tacker.cli'), )
|
||||
self.commands = COMMANDS
|
||||
for k, v in self.commands[apiversion].items():
|
||||
self.command_manager.add_command(k, v)
|
||||
@ -373,8 +185,8 @@ class NeutronShell(app.App):
|
||||
'--os-auth-strategy', metavar='<auth-strategy>',
|
||||
default=env('OS_AUTH_STRATEGY', default='keystone'),
|
||||
help=_('Authentication strategy (Env: OS_AUTH_STRATEGY'
|
||||
', default keystone). For now, any other value will'
|
||||
' disable the authentication'))
|
||||
', default keystone). For now, any other value will'
|
||||
' disable the authentication'))
|
||||
parser.add_argument(
|
||||
'--os_auth_strategy',
|
||||
help=argparse.SUPPRESS)
|
||||
@ -466,8 +278,8 @@ class NeutronShell(app.App):
|
||||
parser.add_argument(
|
||||
'--insecure',
|
||||
action='store_true',
|
||||
default=env('NEUTRONCLIENT_INSECURE', default=False),
|
||||
help=_("Explicitly allow neutronclient to perform \"insecure\" "
|
||||
default=env('TACKERCLIENT_INSECURE', default=False),
|
||||
help=_("Explicitly allow tackerclient to perform \"insecure\" "
|
||||
"SSL (https) requests. The server's certificate will "
|
||||
"not be verified against any certificate authorities. "
|
||||
"This option should be used with caution."))
|
||||
@ -650,7 +462,7 @@ class NeutronShell(app.App):
|
||||
* validate authentication info
|
||||
"""
|
||||
|
||||
super(NeutronShell, self).initialize_app(argv)
|
||||
super(TackerShell, self).initialize_app(argv)
|
||||
|
||||
self.api_version = {'network': self.api_version}
|
||||
|
||||
@ -693,9 +505,9 @@ class NeutronShell(app.App):
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
try:
|
||||
return NeutronShell(NEUTRON_API_VERSION).run(map(strutils.safe_decode,
|
||||
argv))
|
||||
except exc.NeutronClientException:
|
||||
return TackerShell(TACKER_API_VERSION).run(map(strutils.safe_decode,
|
||||
argv))
|
||||
except exc.TackerClientException:
|
||||
return 1
|
||||
except Exception as 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