Add support for keystone v3
Change-Id: I9e37f08f151468bfb49d259649213d11e81575b0
This commit is contained in:
parent
7a76c470fa
commit
880807e455
|
@ -30,35 +30,23 @@ class Credentials(object):
|
|||
dct['username'] = self.rc_username
|
||||
dct['password'] = self.rc_password
|
||||
dct['auth_url'] = self.rc_auth_url
|
||||
dct['tenant_name'] = self.rc_tenant_name
|
||||
dct['cacert'] = self.rc_cacert
|
||||
dct['ca_cert'] = self.rc_cacert
|
||||
return dct
|
||||
|
||||
def get_nova_credentials(self):
|
||||
dct = {}
|
||||
dct['username'] = self.rc_username
|
||||
dct['api_key'] = self.rc_password
|
||||
dct['auth_url'] = self.rc_auth_url
|
||||
dct['project_id'] = self.rc_tenant_name
|
||||
dct['cacert'] = self.rc_cacert
|
||||
return dct
|
||||
|
||||
def get_nova_credentials_v2(self):
|
||||
dct = self.get_nova_credentials()
|
||||
dct['version'] = 2
|
||||
if self.rc_identity_api_version == 3:
|
||||
dct['project_name'] = self.rc_project_name
|
||||
dct['project_domain_id'] = self.rc_project_domain_id
|
||||
dct['user_domain_id'] = self.rc_user_domain_id
|
||||
else:
|
||||
dct['tenant_name'] = self.rc_tenant_name
|
||||
return dct
|
||||
|
||||
def _init_with_openrc_(self, openrc_contents):
|
||||
export_re = re.compile('export OS_([A-Z_]*)="?(.*)')
|
||||
for line in openrc_contents.splitlines():
|
||||
line = line.strip()
|
||||
mstr = export_re.match(line)
|
||||
mstr = export_re.match(line.strip())
|
||||
if mstr:
|
||||
# get rid of posible trailing double quote
|
||||
# get rif of posible trailing double quote
|
||||
# the first one was removed by the re
|
||||
name = mstr.group(1)
|
||||
value = mstr.group(2)
|
||||
name, value = mstr.group(1), mstr.group(2)
|
||||
if value.endswith('"'):
|
||||
value = value[:-1]
|
||||
# get rid of password assignment
|
||||
|
@ -67,6 +55,11 @@ class Credentials(object):
|
|||
# export OS_PASSWORD=$OS_PASSWORD_INPUT
|
||||
if value.startswith('$'):
|
||||
continue
|
||||
# Check if api version is provided
|
||||
# Default is keystone v2
|
||||
if name == 'IDENTITY_API_VERSION':
|
||||
self.rc_identity_api_version = int(value)
|
||||
|
||||
# now match against wanted variable names
|
||||
if name == 'USERNAME':
|
||||
self.rc_username = value
|
||||
|
@ -74,10 +67,18 @@ class Credentials(object):
|
|||
self.rc_auth_url = value
|
||||
elif name == 'TENANT_NAME':
|
||||
self.rc_tenant_name = value
|
||||
elif name == 'CACERT':
|
||||
elif name == "CACERT":
|
||||
self.rc_cacert = value
|
||||
elif name == 'PASSWORD':
|
||||
elif name == "REGION_NAME":
|
||||
self.rc_region_name = value
|
||||
elif name == "PASSWORD":
|
||||
self.rc_password = value
|
||||
elif name == "PROJECT_NAME":
|
||||
self.rc_project_name = value
|
||||
elif name == "PROJECT_DOMAIN_ID" or name == "PROJECT_DOMAIN_NAME":
|
||||
self.rc_project_domain_id = value
|
||||
elif name == "USER_DOMAIN_ID" or name == "USER_DOMAIN_NAME":
|
||||
self.rc_user_domain_id = value
|
||||
|
||||
# Read a openrc file and take care of the password
|
||||
# The 2 args are passed from the command line and can be None
|
||||
|
@ -86,7 +87,12 @@ class Credentials(object):
|
|||
self.rc_username = None
|
||||
self.rc_tenant_name = None
|
||||
self.rc_auth_url = None
|
||||
self.rc_cacert = None
|
||||
self.rc_cacert = False
|
||||
self.rc_region_name = None
|
||||
self.rc_project_name = None
|
||||
self.rc_project_domain_id = None
|
||||
self.rc_user_domain_id = None
|
||||
self.rc_identity_api_version = 2
|
||||
self.openrc_contents = openrc_contents
|
||||
success = True
|
||||
|
||||
|
@ -104,15 +110,37 @@ class Credentials(object):
|
|||
# no openrc file passed - we assume the variables have been
|
||||
# sourced by the calling shell
|
||||
# just check that they are present
|
||||
for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
|
||||
if varname not in os.environ:
|
||||
LOG.warning("%s is missing" % varname)
|
||||
success = False
|
||||
if success:
|
||||
self.rc_username = os.environ['OS_USERNAME']
|
||||
self.rc_auth_url = os.environ['OS_AUTH_URL']
|
||||
self.rc_tenant_name = os.environ['OS_TENANT_NAME']
|
||||
self.rc_cacert = os.environ.get('OS_CACERT', None)
|
||||
if 'OS_IDENTITY_API_VERSION' in os.environ:
|
||||
self.rc_identity_api_version = int(os.environ['OS_IDENTITY_API_VERSION'])
|
||||
|
||||
if self.rc_identity_api_version == 2:
|
||||
for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
|
||||
if varname not in os.environ:
|
||||
LOG.warning('%s is missing', varname)
|
||||
success = False
|
||||
if success:
|
||||
self.rc_username = os.environ['OS_USERNAME']
|
||||
self.rc_auth_url = os.environ['OS_AUTH_URL']
|
||||
self.rc_tenant_name = os.environ['OS_TENANT_NAME']
|
||||
|
||||
if 'OS_REGION_NAME' in os.environ:
|
||||
self.rc_region_name = os.environ['OS_REGION_NAME']
|
||||
|
||||
elif self.rc_identity_api_version == 3:
|
||||
for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_PROJECT_NAME',
|
||||
'OS_PROJECT_DOMAIN_ID', 'OS_USER_DOMAIN_ID']:
|
||||
if varname not in os.environ:
|
||||
LOG.warning('%s is missing', varname)
|
||||
success = False
|
||||
if success:
|
||||
self.rc_username = os.environ['OS_USERNAME']
|
||||
self.rc_auth_url = os.environ['OS_AUTH_URL']
|
||||
self.rc_project_name = os.environ['OS_PROJECT_NAME']
|
||||
self.rc_project_domain_id = os.environ['OS_PROJECT_DOMAIN_ID']
|
||||
self.rc_user_domain_id = os.environ['OS_USER_DOMAIN_ID']
|
||||
|
||||
if 'OS_CACERT' in os.environ:
|
||||
self.rc_cacert = os.environ['OS_CACERT']
|
||||
|
||||
# always override with CLI argument if provided
|
||||
if pwd:
|
||||
|
|
|
@ -56,8 +56,10 @@ import time
|
|||
|
||||
# openstack python clients
|
||||
import cinderclient
|
||||
import keystoneauth1
|
||||
from keystoneclient.v2_0 import client as keystoneclient
|
||||
from keystoneclient.auth.identity import v2 as keystone_v2
|
||||
from keystoneclient.auth.identity import v3 as keystone_v3
|
||||
from keystoneclient import client as keystoneclient
|
||||
from keystoneclient import session
|
||||
import neutronclient
|
||||
from novaclient.exceptions import NotFound
|
||||
from tabulate import tabulate
|
||||
|
@ -137,12 +139,12 @@ class AbstractCleaner(object):
|
|||
pass
|
||||
|
||||
class StorageCleaner(AbstractCleaner):
|
||||
def __init__(self, creds, resources, dryrun):
|
||||
from cinderclient.v2 import client as cclient
|
||||
from novaclient.client import Client as nclient
|
||||
creden_nova = creds.get_nova_credentials_v2()
|
||||
self.nova = nclient(endpoint_type='publicURL', **creden_nova)
|
||||
self.cinder = cclient.Client(endpoint_type='publicURL', **creden_nova)
|
||||
def __init__(self, sess, resources, dryrun):
|
||||
from cinderclient import client as cclient
|
||||
from novaclient import client as nclient
|
||||
|
||||
self.nova = nclient.Client('2', endpoint_type='publicURL', session=sess)
|
||||
self.cinder = cclient.Client('2', endpoint_type='publicURL', session=sess)
|
||||
|
||||
res_desc = {'volumes': [self.cinder.volumes.list, {"all_tenants": 1}]}
|
||||
super(StorageCleaner, self).__init__('Storage', res_desc, resources, dryrun)
|
||||
|
@ -218,13 +220,11 @@ class StorageCleaner(AbstractCleaner):
|
|||
pass
|
||||
|
||||
class ComputeCleaner(AbstractCleaner):
|
||||
def __init__(self, creds, resources, dryrun):
|
||||
from neutronclient.v2_0 import client as nclient
|
||||
from novaclient.client import Client as novaclient
|
||||
creden = creds.get_credentials()
|
||||
creden_nova = creds.get_nova_credentials_v2()
|
||||
self.neutron_client = nclient.Client(endpoint_type='publicURL', **creden)
|
||||
self.nova_client = novaclient(endpoint_type='publicURL', **creden_nova)
|
||||
def __init__(self, sess, resources, dryrun):
|
||||
from neutronclient.neutron import client as nclient
|
||||
from novaclient import client as novaclient
|
||||
self.neutron_client = nclient.Client('2.0', endpoint_type='publicURL', session=sess)
|
||||
self.nova_client = novaclient.Client('2', endpoint_type='publicURL', session=sess)
|
||||
res_desc = {
|
||||
'instances': [self.nova_client.servers.list, {"all_tenants": 1}],
|
||||
'flavors': [self.nova_client.flavors.list],
|
||||
|
@ -321,10 +321,9 @@ class ComputeCleaner(AbstractCleaner):
|
|||
|
||||
class NetworkCleaner(AbstractCleaner):
|
||||
|
||||
def __init__(self, creds, resources, dryrun):
|
||||
from neutronclient.v2_0 import client as nclient
|
||||
creden = creds.get_credentials()
|
||||
self.neutron = nclient.Client(endpoint_type='publicURL', **creden)
|
||||
def __init__(self, sess, resources, dryrun):
|
||||
from neutronclient.neutron import client as nclient
|
||||
self.neutron = nclient.Client('2.0', endpoint_type='publicURL', session=sess)
|
||||
|
||||
# because the response has an extra level of indirection
|
||||
# we need to extract it to present the list of network or router objects
|
||||
|
@ -430,12 +429,13 @@ class NetworkCleaner(AbstractCleaner):
|
|||
|
||||
class KeystoneCleaner(AbstractCleaner):
|
||||
|
||||
def __init__(self, creds, resources, dryrun):
|
||||
crd = creds.get_credentials()
|
||||
self.keystone = keystoneclient.Client(endpoint_type='publicURL', **crd)
|
||||
def __init__(self, sess, resources, dryrun):
|
||||
self.keystone = keystoneclient.Client(endpoint_type='publicURL', session=sess)
|
||||
self.tenant_api = self.keystone.tenants \
|
||||
if self.keystone.version == 'v2.0' else self.keystone.projects
|
||||
res_desc = {
|
||||
'users': [self.keystone.users.list],
|
||||
'tenants': [self.keystone.tenants.list]
|
||||
'tenants': [self.tenant_api.list]
|
||||
}
|
||||
super(KeystoneCleaner, self).__init__('Keystone', res_desc, resources, dryrun)
|
||||
|
||||
|
@ -449,7 +449,7 @@ class KeystoneCleaner(AbstractCleaner):
|
|||
else:
|
||||
self.keystone.users.delete(id)
|
||||
self.report_deletion('USER', name)
|
||||
except keystoneauth1.exceptions.http.NotFound:
|
||||
except keystoneclient.auth.exceptions.http.NotFound:
|
||||
self.report_not_found('USER', name)
|
||||
except KeyError:
|
||||
pass
|
||||
|
@ -458,21 +458,27 @@ class KeystoneCleaner(AbstractCleaner):
|
|||
for id, name in self.resources['tenants'].iteritems():
|
||||
try:
|
||||
if self.dryrun:
|
||||
self.keystone.tenants.get(id)
|
||||
self.tenant_api.get(id)
|
||||
else:
|
||||
self.keystone.tenants.delete(id)
|
||||
self.tenant_api.delete(id)
|
||||
self.report_deletion('TENANT', name)
|
||||
except keystoneauth1.exceptions.http.NotFound:
|
||||
except keystoneclient.auth.exceptions.http.NotFound:
|
||||
self.report_not_found('TENANT', name)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
class KbCleaners(object):
|
||||
|
||||
def __init__(self, cred, resources, dryrun):
|
||||
def __init__(self, creds_obj, resources, dryrun):
|
||||
self.cleaners = []
|
||||
creds = creds_obj.get_credentials()
|
||||
if creds_obj.rc_identity_api_version == 3:
|
||||
auth = keystone_v3.Password(**creds)
|
||||
else:
|
||||
auth = keystone_v2.Password(**creds)
|
||||
sess = session.Session(auth=auth, verify=creds_obj.rc_cacert)
|
||||
for cleaner_type in [StorageCleaner, ComputeCleaner, NetworkCleaner, KeystoneCleaner]:
|
||||
self.cleaners.append(cleaner_type(cred, resources, dryrun))
|
||||
self.cleaners.append(cleaner_type(sess, resources, dryrun))
|
||||
|
||||
def show_resources(self):
|
||||
table = [["Type", "Name", "UUID"]]
|
||||
|
|
|
@ -25,8 +25,8 @@ import webbrowser
|
|||
|
||||
import base_compute
|
||||
import base_network
|
||||
from glanceclient import client as glanceclient
|
||||
import glanceclient.exc as glance_exception
|
||||
from glanceclient.v1 import client as glanceclient
|
||||
from kb_config import KBConfig
|
||||
from kb_res_logger import KBResLogger
|
||||
from kb_runner_base import KBException
|
||||
|
@ -35,9 +35,12 @@ from kb_runner_multicast import KBRunner_Multicast
|
|||
from kb_runner_storage import KBRunner_Storage
|
||||
from kb_scheduler import KBScheduler
|
||||
import kb_vm_agent
|
||||
from keystoneclient.v2_0 import client as keystoneclient
|
||||
from keystoneclient.auth.identity import v2 as keystone_v2
|
||||
from keystoneclient.auth.identity import v3 as keystone_v3
|
||||
from keystoneclient import client as keystoneclient
|
||||
from keystoneclient import session
|
||||
import log as logging
|
||||
from novaclient.client import Client as novaclient
|
||||
from novaclient import client as novaclient
|
||||
from oslo_config import cfg
|
||||
import pbr.version
|
||||
from pkg_resources import resource_filename
|
||||
|
@ -53,12 +56,18 @@ __version__ = pbr.version.VersionInfo('kloudbuster').version_string_with_vcs()
|
|||
class KBVMCreationException(Exception):
|
||||
pass
|
||||
|
||||
def create_keystone_client(creds):
|
||||
def create_auth_session(creds_obj):
|
||||
"""
|
||||
Return the keystone client and auth URL given a credential
|
||||
Return the authenticated session
|
||||
"""
|
||||
creds = creds.get_credentials()
|
||||
return keystoneclient.Client(endpoint_type='publicURL', **creds)
|
||||
creds = creds_obj.get_credentials()
|
||||
if creds_obj.rc_identity_api_version == 3:
|
||||
auth = keystone_v3.Password(**creds)
|
||||
else:
|
||||
auth = keystone_v2.Password(**creds)
|
||||
sess = session.Session(auth=auth, verify=creds_obj.rc_cacert)
|
||||
|
||||
return sess
|
||||
|
||||
class Kloud(object):
|
||||
def __init__(self, scale_cfg, cred, reusing_tenants,
|
||||
|
@ -69,8 +78,7 @@ class Kloud(object):
|
|||
self.reusing_tenants = reusing_tenants
|
||||
self.storage_mode = storage_mode
|
||||
self.multicast_mode = multicast_mode
|
||||
self.cred = cred
|
||||
self.keystone = create_keystone_client(cred)
|
||||
self.osclient_session = create_auth_session(cred)
|
||||
self.flavor_to_use = None
|
||||
self.vm_up_count = 0
|
||||
self.res_logger = KBResLogger()
|
||||
|
@ -85,6 +93,9 @@ class Kloud(object):
|
|||
if scale_cfg['availability_zone'] else None
|
||||
self.exc_info = None
|
||||
|
||||
self.keystone = keystoneclient.Client(session=self.osclient_session,
|
||||
endpoint_type='publicURL')
|
||||
|
||||
LOG.info("Creating kloud: " + self.prefix)
|
||||
if self.placement_az:
|
||||
LOG.info('%s Availability Zone: %s' % (self.name, self.placement_az))
|
||||
|
@ -288,9 +299,9 @@ class KloudBuster(object):
|
|||
|
||||
def get_hypervisor_list(self, cred):
|
||||
ret_list = []
|
||||
creden_nova = cred.get_nova_credentials_v2()
|
||||
nova_client = novaclient(endpoint_type='publicURL',
|
||||
http_log_debug=True, **creden_nova)
|
||||
sess = create_auth_session(cred)
|
||||
nova_client = novaclient('2', endpoint_type='publicURL',
|
||||
http_log_debug=True, session=sess)
|
||||
for hypervisor in nova_client.hypervisors.list():
|
||||
if vars(hypervisor)['status'] == 'enabled':
|
||||
ret_list.append(vars(hypervisor)['hypervisor_hostname'])
|
||||
|
@ -299,9 +310,9 @@ class KloudBuster(object):
|
|||
|
||||
def get_az_list(self, cred):
|
||||
ret_list = []
|
||||
creden_nova = cred.get_nova_credentials_v2()
|
||||
nova_client = novaclient(endpoint_type='publicURL',
|
||||
http_log_debug=True, **creden_nova)
|
||||
sess = create_auth_session(cred)
|
||||
nova_client = novaclient('2', endpoint_type='publicURL',
|
||||
http_log_debug=True, session=sess)
|
||||
for az in nova_client.availability_zones.list():
|
||||
zoneName = vars(az)['zoneName']
|
||||
isAvail = vars(az)['zoneState']['available']
|
||||
|
@ -312,21 +323,14 @@ class KloudBuster(object):
|
|||
|
||||
def check_and_upload_images(self, retry_count=150):
|
||||
retry = 0
|
||||
creds_list = [
|
||||
{'keystone': create_keystone_client(self.server_cred), 'cred': self.server_cred},
|
||||
{'keystone': create_keystone_client(self.client_cred), 'cred': self.client_cred}
|
||||
]
|
||||
creds_list = [create_auth_session(self.server_cred),
|
||||
create_auth_session(self.client_cred)]
|
||||
creds_dict = dict(zip(['Server kloud', 'Client kloud'], creds_list))
|
||||
img_name_dict = dict(zip(['Server kloud', 'Client kloud'],
|
||||
[self.server_cfg.image_name, self.client_cfg.image_name]))
|
||||
|
||||
for kloud, creds in creds_dict.items():
|
||||
keystone = creds['keystone']
|
||||
cacert = creds['cred'].get_credentials()['cacert']
|
||||
glance_endpoint = keystone.service_catalog.url_for(
|
||||
service_type='image', endpoint_type='publicURL')
|
||||
glance_client = glanceclient.Client(
|
||||
glance_endpoint, token=keystone.auth_token, cacert=cacert)
|
||||
for kloud, sess in creds_dict.items():
|
||||
glance_client = glanceclient.Client('1', session=sess)
|
||||
try:
|
||||
# Search for the image
|
||||
img = glance_client.images.list(filters={'name': img_name_dict[kloud]}).next()
|
||||
|
|
|
@ -36,6 +36,8 @@ class Tenant(object):
|
|||
self.kloud = kloud
|
||||
self.res_logger = kloud.res_logger
|
||||
self.tenant_name = tenant_name
|
||||
self.tenant_api = self.kloud.keystone.tenants \
|
||||
if self.kloud.keystone.version == 'v2.0' else self.kloud.keystone.projects
|
||||
if not self.kloud.reusing_tenants:
|
||||
self.tenant_object = self._get_tenant()
|
||||
self.tenant_id = self.tenant_object.id
|
||||
|
@ -58,9 +60,10 @@ class Tenant(object):
|
|||
try:
|
||||
LOG.info("Creating tenant: " + self.tenant_name)
|
||||
tenant_object = \
|
||||
self.kloud.keystone.tenants.create(tenant_name=self.tenant_name,
|
||||
description="KloudBuster tenant",
|
||||
enabled=True)
|
||||
self.tenant_api.create(self.tenant_name,
|
||||
domain="default",
|
||||
description="KloudBuster tenant",
|
||||
enabled=True)
|
||||
return tenant_object
|
||||
except keystone_exception.Conflict as exc:
|
||||
# ost likely the entry already exists:
|
||||
|
@ -68,7 +71,7 @@ class Tenant(object):
|
|||
if exc.http_status != 409:
|
||||
raise exc
|
||||
LOG.info("Tenant %s already present, reusing it" % self.tenant_name)
|
||||
return self.kloud.keystone.tenants.find(name=self.tenant_name)
|
||||
return self.tenant_api.find(name=self.tenant_name)
|
||||
|
||||
# Should never come here
|
||||
raise Exception()
|
||||
|
@ -122,6 +125,6 @@ class Tenant(object):
|
|||
|
||||
if not self.reusing_users:
|
||||
# Delete the tenant (self)
|
||||
self.kloud.keystone.tenants.delete(self.tenant_id)
|
||||
self.tenant_api.delete(self.tenant_id)
|
||||
|
||||
return flag
|
||||
|
|
|
@ -16,10 +16,10 @@ import sys
|
|||
|
||||
import base_compute
|
||||
import base_network
|
||||
from cinderclient.v2 import client as cinderclient
|
||||
from cinderclient import client as cinderclient
|
||||
from keystoneclient import exceptions as keystone_exception
|
||||
import log as logging
|
||||
from neutronclient.v2_0 import client as neutronclient
|
||||
from neutronclient.neutron import client as neutronclient
|
||||
from novaclient import client as novaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -66,9 +66,12 @@ class User(object):
|
|||
if not self.tenant.reusing_users:
|
||||
self.user = self._get_user()
|
||||
current_role = self.tenant.kloud.keystone.roles.find(name=user_role)
|
||||
self.tenant.kloud.keystone.roles.add_user_role(self.user,
|
||||
current_role,
|
||||
tenant.tenant_id)
|
||||
if self.tenant.kloud.keystone.version == 'v2.0':
|
||||
self.tenant.kloud.keystone.roles.add_user_role(
|
||||
self.user, current_role, tenant.tenant_id)
|
||||
else:
|
||||
self.tenant.kloud.keystone.roles.grant(
|
||||
current_role, user=self.user, project=tenant.tenant_id)
|
||||
else:
|
||||
# Only admin can retrive the object via Keystone API
|
||||
self.user = None
|
||||
|
@ -190,24 +193,15 @@ class User(object):
|
|||
1. Creates the routers
|
||||
2. Creates the neutron and nova client objects
|
||||
"""
|
||||
# Create a new neutron client for this User with correct credentials
|
||||
creden = self.tenant.kloud.cred.get_credentials()
|
||||
creden['username'] = self.user_name
|
||||
creden['password'] = self.password
|
||||
creden['tenant_name'] = self.tenant.tenant_name
|
||||
session = self.tenant.kloud.osclient_session
|
||||
|
||||
# Create the neutron client to be used for all operations
|
||||
self.neutron_client = neutronclient.Client(endpoint_type='publicURL', **creden)
|
||||
|
||||
# Create a new nova and cinder client for this User with correct credentials
|
||||
creden_nova = self.tenant.kloud.cred.get_nova_credentials_v2()
|
||||
creden_nova['username'] = self.user_name
|
||||
creden_nova['api_key'] = self.password
|
||||
creden_nova['project_id'] = self.tenant.tenant_name
|
||||
|
||||
self.nova_client = novaclient.Client(endpoint_type='publicURL',
|
||||
http_log_debug=True, **creden_nova)
|
||||
self.cinder_client = cinderclient.Client(endpoint_type='publicURL', **creden_nova)
|
||||
# Create nova/neutron/cinder clients to be used for all operations
|
||||
self.neutron_client = neutronclient.Client('2.0', endpoint_type='publicURL',
|
||||
session=session)
|
||||
self.nova_client = novaclient.Client('2', endpoint_type='publicURL',
|
||||
http_log_debug=True, session=session)
|
||||
self.cinder_client = cinderclient.Client('2', endpoint_type='publicURL',
|
||||
session=session)
|
||||
|
||||
if self.tenant.kloud.reusing_tenants:
|
||||
self.check_resources_quota()
|
||||
|
|
Loading…
Reference in New Issue