Add credentials and profile support to Neutron client

Add support to the Neutron client for credentials and profiles to allow
for working with Nexus 1000V. These are in support of the Nexus 1000V
Cisco plugin work.

Change-Id: I63e7ea09b1da027e308e32ae9a8e0400ab5965f2
Implements: blueprint cisco-n1k-neutron-client
This commit is contained in:
Abhishek Raut
2013-07-11 17:46:39 -07:00
parent be936c5562
commit f146fa0cd5
9 changed files with 625 additions and 1 deletions

View File

@@ -0,0 +1,81 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import logging
from neutronclient.neutron import v2_0 as neutronV20
class ListCredential(neutronV20.ListCommand):
"""List credentials that belong to a given tenant."""
resource = 'credential'
log = logging.getLogger(__name__ + '.ListCredential')
_formatters = {}
list_columns = ['credential_id', 'credential_name', 'user_name',
'password', 'type']
class ShowCredential(neutronV20.ShowCommand):
"""Show information of a given credential."""
resource = 'credential'
log = logging.getLogger(__name__ + '.ShowCredential')
allow_names = False
class CreateCredential(neutronV20.CreateCommand):
"""Creates a credential."""
resource = 'credential'
log = logging.getLogger(__name__ + '.CreateCredential')
def add_known_arguments(self, parser):
parser.add_argument(
'credential_name',
help='Name/Ip address for Credential')
parser.add_argument(
'credential_type',
help='Type of the Credential')
parser.add_argument(
'--username',
help='Username for the credential')
parser.add_argument(
'--password',
help='Password for the credential')
def args2body(self, parsed_args):
body = {'credential': {
'credential_name': parsed_args.credential_name}}
if parsed_args.credential_type:
body['credential'].update({'type':
parsed_args.credential_type})
if parsed_args.username:
body['credential'].update({'user_name':
parsed_args.username})
if parsed_args.password:
body['credential'].update({'password':
parsed_args.password})
return body
class DeleteCredential(neutronV20.DeleteCommand):
"""Delete a given credential."""
log = logging.getLogger(__name__ + '.DeleteCredential')
resource = 'credential'
allow_names = False

View File

@@ -0,0 +1,127 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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 Abhishek Raut, Cisco Systems
#@author Sergey Sudakovich, Cisco Systems
import logging
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import parse_args_to_dict
from neutronclient.openstack.common.gettextutils import _
RESOURCE = 'network_profile'
SEGMENT_TYPE_CHOICES = ['vlan', 'vxlan']
class ListNetworkProfile(neutronV20.ListCommand):
"""List network profiles that belong to a given tenant."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.ListNetworkProfile')
_formatters = {}
list_columns = ['id', 'name', 'segment_type', 'segment_range',
'physical_network', 'multicast_ip_index',
'multicast_ip_range']
class ShowNetworkProfile(neutronV20.ShowCommand):
"""Show information of a given network profile."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.ShowNetworkProfile')
allow_names = True
class CreateNetworkProfile(neutronV20.CreateCommand):
"""Creates a network profile."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.CreateNetworkProfile')
def add_known_arguments(self, parser):
parser.add_argument('name',
help='Name for Network Profile')
parser.add_argument('segment_type',
choices=SEGMENT_TYPE_CHOICES,
help='Segment type')
parser.add_argument('--segment_range',
help='Range for the Segment')
parser.add_argument('--physical_network',
help='Name for the Physical Network')
parser.add_argument('--multicast_ip_range',
help='Multicast IPv4 Range')
parser.add_argument("--add-tenant",
help="Add tenant to the network profile")
def args2body(self, parsed_args):
body = {'network_profile': {'name': parsed_args.name}}
if parsed_args.segment_type:
body['network_profile'].update({'segment_type':
parsed_args.segment_type})
if parsed_args.segment_range:
body['network_profile'].update({'segment_range':
parsed_args.segment_range})
if parsed_args.physical_network:
body['network_profile'].update({'physical_network':
parsed_args.physical_network})
if parsed_args.multicast_ip_range:
body['network_profile'].update({'multicast_ip_range':
parsed_args.multicast_ip_range})
if parsed_args.add_tenant:
body['network_profile'].update({'add_tenant':
parsed_args.add_tenant})
return body
class DeleteNetworkProfile(neutronV20.DeleteCommand):
"""Delete a given network profile."""
log = logging.getLogger(__name__ + '.DeleteNetworkProfile')
resource = RESOURCE
allow_names = True
class UpdateNetworkProfile(neutronV20.UpdateCommand):
"""Update network profile's information."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.UpdateNetworkProfile')
class UpdateNetworkProfileV2(neutronV20.NeutronCommand):
api = 'network'
log = logging.getLogger(__name__ + '.UpdateNetworkProfileV2')
resource = RESOURCE
def get_parser(self, prog_name):
parser = super(UpdateNetworkProfileV2, self).get_parser(prog_name)
parser.add_argument("--remove-tenant",
help="Remove tenant from the network profile")
return parser
def run(self, parsed_args):
self.log.debug('run(%s)' % parsed_args)
neutron_client = self.get_client()
neutron_client.format = parsed_args.request_format
data = {self.resource: parse_args_to_dict(parsed_args)}
if parsed_args.remove_tenant:
data[self.resource]['remove_tenant'] = parsed_args.remove_tenant
neutron_client.update_network_profile(parsed_args.id,
{self.resource: data})
print >>self.app.stdout, (
_('Updated %(resource)s: %(id)s') %
{'id': parsed_args.id, 'resource': self.resource})
return

View File

@@ -0,0 +1,79 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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 Abhishek Raut, Cisco Systems
#@author Sergey Sudakovich, Cisco Systems
import logging
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import parse_args_to_dict
from neutronclient.openstack.common.gettextutils import _
RESOURCE = 'policy_profile'
class ListPolicyProfile(neutronV20.ListCommand):
"""List policy profiles that belong to a given tenant."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.ListProfile')
_formatters = {}
list_columns = ['id', 'name']
class ShowPolicyProfile(neutronV20.ShowCommand):
"""Show information of a given policy profile."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.ShowProfile')
allow_names = True
class UpdatePolicyProfile(neutronV20.UpdateCommand):
"""Update policy profile's information."""
resource = RESOURCE
log = logging.getLogger(__name__ + '.UpdatePolicyProfile')
class UpdatePolicyProfileV2(neutronV20.UpdateCommand):
"""Update policy profile's information."""
api = 'network'
log = logging.getLogger(__name__ + '.UpdatePolicyProfileV2')
resource = RESOURCE
def get_parser(self, prog_name):
parser = super(UpdatePolicyProfileV2, self).get_parser(prog_name)
parser.add_argument("--add-tenant",
help="Add tenant to the policy profile")
parser.add_argument("--remove-tenant",
help="Remove tenant from the policy profile")
return parser
def run(self, parsed_args):
self.log.debug('run(%s)' % parsed_args)
neutron_client = self.get_client()
neutron_client.format = parsed_args.request_format
data = {self.resource: parse_args_to_dict(parsed_args)}
if parsed_args.add_tenant:
data[self.resource]['add_tenant'] = parsed_args.add_tenant
if parsed_args.remove_tenant:
data[self.resource]['remove_tenant'] = parsed_args.remove_tenant
neutron_client.update_policy_profile(parsed_args.id,
{self.resource: data})
print >>self.app.stdout, (
_('Updated %(resource)s: %(id)s') %
{'id': parsed_args.id, 'resource': self.resource})
return

View File

@@ -32,6 +32,7 @@ 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
@@ -42,8 +43,10 @@ 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 network
from neutronclient.neutron.v2_0 import networkprofile
from neutronclient.neutron.v2_0 import nvp_qos_queue
from neutronclient.neutron.v2_0 import nvpnetworkgateway
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
@@ -201,6 +204,18 @@ COMMAND_V2 = {
'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,
}
COMMANDS = {'2.0': COMMAND_V2}

View File

@@ -184,6 +184,14 @@ class Client(object):
network_gateways_path = "/network-gateways"
network_gateway_path = "/network-gateways/%s"
service_providers_path = "/service-providers"
credentials_path = "/credentials"
credential_path = "/credentials/%s"
network_profiles_path = "/network_profiles"
network_profile_path = "/network_profiles/%s"
network_profile_bindings_path = "/network_profile_bindings"
policy_profiles_path = "/policy_profiles"
policy_profile_path = "/policy_profiles/%s"
policy_profile_bindings_path = "/policy_profile_bindings"
DHCP_NETS = '/dhcp-networks'
DHCP_AGENTS = '/dhcp-agents'
@@ -852,6 +860,79 @@ class Client(object):
return self.list('service_providers', self.service_providers_path,
retrieve_all, **_params)
def list_credentials(self, **_params):
"""Fetch a list of all credentials for a tenant."""
return self.get(self.credentials_path, params=_params)
@APIParamsCall
def show_credential(self, credential, **_params):
"""Fetch a credential."""
return self.get(self.credential_path % (credential), params=_params)
@APIParamsCall
def create_credential(self, body=None):
"""Create a new credential."""
return self.post(self.credentials_path, body=body)
@APIParamsCall
def update_credential(self, credential, body=None):
"""Update a credential."""
return self.put(self.credential_path % (credential), body=body)
@APIParamsCall
def delete_credential(self, credential):
"""Delete the specified credential."""
return self.delete(self.credential_path % (credential))
def list_network_profile_bindings(self, **params):
"""Fetch a list of all tenants associated for a network profile."""
return self.get(self.network_profile_bindings_path, params=params)
@APIParamsCall
def list_network_profiles(self, **params):
"""Fetch a list of all network profiles for a tenant."""
return self.get(self.network_profiles_path, params=params)
@APIParamsCall
def show_network_profile(self, profile, **params):
"""Fetch a network profile."""
return self.get(self.network_profile_path % (profile), params=params)
@APIParamsCall
def create_network_profile(self, body=None):
"""Create a network profile."""
return self.post(self.network_profiles_path, body=body)
@APIParamsCall
def update_network_profile(self, profile, body=None):
"""Update a network profile."""
return self.put(self.network_profile_path % (profile), body=body)
@APIParamsCall
def delete_network_profile(self, profile):
"""Delete the network profile."""
return self.delete(self.network_profile_path % profile)
@APIParamsCall
def list_policy_profile_bindings(self, **params):
"""Fetch a list of all tenants associated for a policy profile."""
return self.get(self.policy_profile_bindings_path, params=params)
@APIParamsCall
def list_policy_profiles(self, **params):
"""Fetch a list of all network profiles for a tenant."""
return self.get(self.policy_profiles_path, params=params)
@APIParamsCall
def show_policy_profile(self, profile, **params):
"""Fetch a network profile."""
return self.get(self.policy_profile_path % (profile), params=params)
@APIParamsCall
def update_policy_profile(self, profile, body=None):
"""Update a policy profile."""
return self.put(self.policy_profile_path % (profile), body=body)
def __init__(self, **kwargs):
"""Initialize a new client for the Neutron v2.0 API."""
super(Client, self).__init__()

View File

@@ -187,7 +187,8 @@ class CLITestV20Base(testtools.TestCase):
cmd.get_client().MultipleTimes().AndReturn(self.client)
non_admin_status_resources = ['subnet', 'floatingip', 'security_group',
'security_group_rule', 'qos_queue',
'network_gateway']
'network_gateway', 'credential',
'network_profile', 'policy_profile']
if (resource in non_admin_status_resources):
body = {resource: {}, }
else:

View File

@@ -0,0 +1,80 @@
# Copyright 2013 Cisco Systems Inc.
# 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: Kyle Mestery, Cisco Systems, Inc.
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import sys
from neutronclient.neutron.v2_0 import credential
from tests.unit import test_cli20
class CLITestV20Credential(test_cli20.CLITestV20Base):
def test_create_credential(self):
"""Create credential: myid."""
resource = 'credential'
cmd = credential.CreateCredential(test_cli20.MyApp(sys.stdout), None)
name = 'myname'
myid = 'myid'
type = 'mytype'
args = [name, type]
position_names = ['credential_name', 'type']
position_values = [name, type]
self._test_create_resource(resource, cmd, name, myid, args,
position_names, position_values)
def test_list_credentials_detail(self):
"""List credentials: -D."""
resources = 'credentials'
cmd = credential.ListCredential(test_cli20.MyApp(sys.stdout), None)
contents = [{'credential_name': 'myname', 'type': 'mytype'}]
self._test_list_resources(resources, cmd, True,
response_contents=contents)
def test_list_credential_known_option_after_unknown(self):
"""List credential: -- --tags a b --request-format xml."""
resources = 'credentials'
cmd = credential.ListCredential(test_cli20.MyApp(sys.stdout), None)
contents = [{'credential_name': 'myname', 'type': 'mytype'}]
self._test_list_resources(resources, cmd, tags=['a', 'b'],
response_contents=contents)
def test_list_credential_fields(self):
"""List credential: --fields a --fields b -- --fields c d."""
resources = 'credentials'
cmd = credential.ListCredential(test_cli20.MyApp(sys.stdout), None)
contents = [{'credential_name': 'myname', 'type': 'mytype'}]
self._test_list_resources(resources, cmd,
fields_1=['a', 'b'], fields_2=['c', 'd'],
response_contents=contents)
def test_show_credential(self):
"""Show credential: --fields id --fields name myid."""
resource = 'credential'
cmd = credential.ShowCredential(test_cli20.MyApp(sys.stdout), None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(resource, cmd, self.test_id, args,
['id', 'name'])
def test_delete_credential(self):
"""Delete credential: myid."""
resource = 'credential'
cmd = credential.DeleteCredential(test_cli20.MyApp(sys.stdout), None)
myid = 'myid'
args = [myid]
self._test_delete_resource(resource, cmd, myid, args)

View File

@@ -0,0 +1,86 @@
# Copyright 2013 Cisco Systems Inc.
# 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: Kyle Mestery, Cisco Systems, Inc.
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import sys
from neutronclient.neutron.v2_0 import networkprofile
from tests.unit import test_cli20
class CLITestV20NetworkProfile(test_cli20.CLITestV20Base):
def test_create_networkprofile(self):
"""Create networkprofile: myid."""
resource = 'network_profile'
cmd = networkprofile.CreateNetworkProfile(test_cli20.
MyApp(sys.stdout), None)
name = 'myname'
myid = 'myid'
segment_type = 'vlan'
args = [name, segment_type]
position_names = ['name', 'segment_type']
position_values = [name, segment_type]
self._test_create_resource(resource, cmd, name, myid, args,
position_names, position_values)
def test_list_networkprofile_detail(self):
"""List networkprofile: -D."""
resources = 'network_profiles'
cmd = networkprofile.ListNetworkProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd, True,
response_contents=contents)
def test_list_networkprofile_known_option_after_unknown(self):
"""List networkprofile: -- --tags a b --request-format xml."""
resources = 'network_profiles'
cmd = networkprofile.ListNetworkProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd, tags=['a', 'b'],
response_contents=contents)
def test_list_networkprofile_fields(self):
"""List networkprofile: --fields a --fields b -- --fields c d."""
resources = 'network_profiles'
cmd = networkprofile.ListNetworkProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd,
fields_1=['a', 'b'], fields_2=['c', 'd'],
response_contents=contents)
def test_show_networkprofile(self):
"""Show networkprofile: --fields id --fields name myid."""
resource = 'network_profile'
cmd = networkprofile.ShowNetworkProfile(test_cli20.MyApp(sys.stdout),
None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(resource, cmd, self.test_id, args,
['id', 'name'])
def test_delete_networkprofile(self):
"""Delete networkprofile: myid."""
resource = 'network_profile'
cmd = networkprofile.DeleteNetworkProfile(test_cli20.
MyApp(sys.stdout), None)
myid = 'myid'
args = [myid]
self._test_delete_resource(resource, cmd, myid, args)

View File

@@ -0,0 +1,74 @@
# Copyright 2013 Cisco Systems Inc.
# 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: Kyle Mestery, Cisco Systems, Inc.
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import sys
from neutronclient.neutron.v2_0 import policyprofile
from tests.unit import test_cli20
class CLITestV20PolicyProfile(test_cli20.CLITestV20Base):
def test_list_policyprofile_detail(self):
"""List policyprofile: -D."""
resources = 'policy_profiles'
cmd = policyprofile.ListPolicyProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd, True,
response_contents=contents)
def test_list_policyprofile_known_option_after_unknown(self):
"""List policyprofile: -- --tags a b --request-format xml."""
resources = 'policy_profiles'
cmd = policyprofile.ListPolicyProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd, tags=['a', 'b'],
response_contents=contents)
def test_list_policyprofile_fields(self):
"""List policyprofile: --fields a --fields b -- --fields c d."""
resources = 'policy_profiles'
cmd = policyprofile.ListPolicyProfile(test_cli20.MyApp(sys.stdout),
None)
contents = [{'name': 'myname', 'segment_type': 'vlan'}]
self._test_list_resources(resources, cmd,
fields_1=['a', 'b'], fields_2=['c', 'd'],
response_contents=contents)
def test_show_policyprofile(self):
"""Show policyprofile: --fields id --fields name myid."""
resource = 'policy_profile'
cmd = policyprofile.ShowPolicyProfile(test_cli20.MyApp(sys.stdout),
None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(resource, cmd, self.test_id, args,
['id', 'name'])
def test_update_policyprofile(self):
"""Update policyprofile: myid --name myname --tags a b."""
resource = 'policy_profile'
cmd = policyprofile.UpdatePolicyProfile(test_cli20.MyApp(sys.stdout),
None)
self._test_update_resource(resource, cmd, 'myid',
['myid', '--name', 'myname',
'--tags', 'a', 'b'],
{'name': 'myname', 'tags': ['a', 'b'], }
)