Use quota fields as per services enabled
There are few quotas such as fixed-ips, floating-ips, sec-group etc.. which can be managed by neutron as well as nova-network based on the service enablement. Use neutron to manage these quota fields if neutron is enabled or else use nova. Added consts.py file to keep track of all the constants required for KB. Change-Id: I7fed28fdc27b5f090e12baf2a25edbc8592f2df1
This commit is contained in:
parent
b0c110d2f3
commit
5285612606
|
@ -0,0 +1,37 @@
|
|||
# Copyright (c) 2016 Ericsson AB.
|
||||
|
||||
# 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.
|
||||
|
||||
NOVA_QUOTA_FIELDS = ("metadata_items",
|
||||
"cores",
|
||||
"instances",
|
||||
"ram",
|
||||
"key_pairs",
|
||||
"floating_ips",
|
||||
"fixed_ips",
|
||||
"security_groups",
|
||||
"security_group_rules",)
|
||||
|
||||
CINDER_QUOTA_FIELDS = ("volumes",
|
||||
"snapshots",
|
||||
"gigabytes",
|
||||
"backups",)
|
||||
|
||||
NEUTRON_QUOTA_FIELDS = ("network",
|
||||
"subnet",
|
||||
"port",
|
||||
"router",
|
||||
"floatingip",
|
||||
"security_group",
|
||||
"security_group_rule",
|
||||
)
|
|
@ -2,5 +2,4 @@
|
|||
OpenStack Drivers
|
||||
================================
|
||||
|
||||
Driver for openstack communication based on python-openstackclient.
|
||||
Implements nova, cinder & neutron clients based on the same.
|
||||
Driver for openstack communication based on python native clients.
|
||||
|
|
|
@ -14,6 +14,7 @@ from oslo_log import log
|
|||
|
||||
from cinderclient.v2 import client as ci_client
|
||||
|
||||
from kingbird.common import exceptions
|
||||
from kingbird.drivers import base
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -22,12 +23,15 @@ LOG = log.getLogger(__name__)
|
|||
class CinderClient(base.DriverBase):
|
||||
'''Cinder V2 driver.'''
|
||||
def __init__(self, region, **kwargs):
|
||||
self.cinder_client = ci_client.Client(
|
||||
auth_url=kwargs['auth_url'],
|
||||
username=kwargs['user_name'],
|
||||
api_key=kwargs['password'],
|
||||
tenant_id=kwargs['tenant_id'],
|
||||
region_name=region)
|
||||
try:
|
||||
self.cinder_client = ci_client.Client(
|
||||
auth_url=kwargs['auth_url'],
|
||||
username=kwargs['user_name'],
|
||||
api_key=kwargs['password'],
|
||||
tenant_id=kwargs['tenant_id'],
|
||||
region_name=region)
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
||||
def get_resource_usages(self, project_id):
|
||||
'''Calcualte resources usage and return the dict'''
|
||||
|
|
|
@ -30,17 +30,32 @@ class KeystoneClient(base.DriverBase):
|
|||
'''Keystone V3 driver.'''
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
auth = v3.Password(
|
||||
auth_url=kwargs['auth_url'],
|
||||
username=kwargs['user_name'],
|
||||
password=kwargs['password'],
|
||||
project_name=kwargs['tenant_name'])
|
||||
sess = session.Session(auth=auth)
|
||||
self.keystone_client = client.Client(session=sess)
|
||||
try:
|
||||
auth = v3.Password(
|
||||
auth_url=kwargs['auth_url'],
|
||||
username=kwargs['user_name'],
|
||||
password=kwargs['password'],
|
||||
project_name=kwargs['tenant_name'],
|
||||
project_domain_name=kwargs['project_domain'],
|
||||
user_domain_name=kwargs['user_domain'])
|
||||
sess = session.Session(auth=auth)
|
||||
self.keystone_client = client.Client(session=sess)
|
||||
self.services_list = self.keystone_client.services.list()
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
||||
def get_enabled_projects(self):
|
||||
try:
|
||||
return [current_project.id for current_project in
|
||||
self.keystone.projects.list() if current_project.enabled]
|
||||
except exceptions.HttpException as ex:
|
||||
raise ex
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
||||
def is_service_enabled(self, service):
|
||||
try:
|
||||
for current_service in self.services_list:
|
||||
if service in current_service.type:
|
||||
return True
|
||||
return False
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
from oslo_log import log
|
||||
|
||||
from kingbird.common import exceptions
|
||||
from kingbird.drivers import base
|
||||
|
||||
from neutronclient.neutron import client
|
||||
|
@ -23,13 +24,17 @@ API_VERSION = '2.0'
|
|||
class NeutronClient(base.DriverBase):
|
||||
'''Neutron V2 driver.'''
|
||||
def __init__(self, region, **kwargs):
|
||||
self.neutron_client = client.Client(
|
||||
API_VERSION,
|
||||
username=kwargs['user_name'],
|
||||
password=kwargs['password'],
|
||||
tenant_name=kwargs['tenant_name'],
|
||||
auth_url=kwargs['auth_url'],
|
||||
region_name=region)
|
||||
try:
|
||||
self.neutron_client = client.Client(
|
||||
API_VERSION,
|
||||
username=kwargs['user_name'],
|
||||
password=kwargs['password'],
|
||||
tenant_name=kwargs['tenant_name'],
|
||||
auth_url=kwargs['auth_url'],
|
||||
region_name=region)
|
||||
self.extension_list = self.neutron_client.list_extensions()
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
||||
def get_resource_usages(self, project_id):
|
||||
'''Calcualte resources usage and return the dict'''
|
||||
|
@ -42,3 +47,9 @@ class NeutronClient(base.DriverBase):
|
|||
def delete_quota_limits(self, project_id):
|
||||
'''Delete/Reset the limits'''
|
||||
pass
|
||||
|
||||
def is_extension_supported(self, extension):
|
||||
for current_extension in self.extension_list['extensions']:
|
||||
if extension in current_extension['alias']:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
from oslo_log import log
|
||||
|
||||
from kingbird.common import consts
|
||||
from kingbird.common import exceptions
|
||||
from kingbird.drivers import base
|
||||
|
||||
from novaclient import client as nv_client
|
||||
|
@ -22,11 +24,16 @@ API_VERSION = '2.1'
|
|||
|
||||
class NovaClient(base.DriverBase):
|
||||
'''Nova V2.1 driver.'''
|
||||
def __init__(self, region, **kwargs):
|
||||
self.nova_client = nv_client.Client(
|
||||
API_VERSION, kwargs['user_name'],
|
||||
kwargs['password'], kwargs['tenant_name'],
|
||||
kwargs['auth_url'], region_name=region)
|
||||
def __init__(self, region, disabled_quotas, **kwargs):
|
||||
try:
|
||||
self.nova_client = nv_client.Client(
|
||||
API_VERSION, kwargs['user_name'],
|
||||
kwargs['password'], kwargs['tenant_name'],
|
||||
kwargs['auth_url'], region_name=region)
|
||||
self.enabled_quotas = list(set(consts.NOVA_QUOTA_FIELDS) -
|
||||
set(disabled_quotas))
|
||||
except exceptions.HttpException:
|
||||
raise
|
||||
|
||||
def get_resource_usages(self, project_id):
|
||||
'''Calcualte resources usage and return the dict'''
|
||||
|
|
|
@ -17,6 +17,7 @@ import collections
|
|||
|
||||
from oslo_log import log
|
||||
|
||||
from kingbird.common import consts
|
||||
from kingbird.common import exceptions
|
||||
from kingbird.common.i18n import _
|
||||
from kingbird.common.i18n import _LE
|
||||
|
@ -33,18 +34,19 @@ LOG = log.getLogger(__name__)
|
|||
|
||||
admin_creds_opts = [
|
||||
cfg.StrOpt('auth_url',
|
||||
default='http://127.0.0.1:5000/v3',
|
||||
help='keystone authorization url'),
|
||||
cfg.StrOpt('identity_url',
|
||||
default='http://127.0.0.1:35357/v3',
|
||||
help='keystone service url'),
|
||||
cfg.StrOpt('admin_username',
|
||||
default='admin',
|
||||
help='username of admin account, needed when'
|
||||
' auto_refresh_endpoint set to True'),
|
||||
cfg.StrOpt('admin_password',
|
||||
default='admin',
|
||||
help='password of admin account, needed when'
|
||||
' auto_refresh_endpoint set to True'),
|
||||
cfg.StrOpt('admin_tenant',
|
||||
default='admin',
|
||||
help='tenant name of admin account, needed when'
|
||||
' auto_refresh_endpoint set to True'),
|
||||
cfg.StrOpt('admin_tenant_id',
|
||||
|
@ -71,6 +73,21 @@ class OpenStackDriver(object):
|
|||
def __init__(self, region_name):
|
||||
# Check if objects are cached and try to use those
|
||||
self.region_name = region_name
|
||||
self.services_list = []
|
||||
admin_kwargs = {
|
||||
'user_name': cfg.CONF.admin_creds.admin_username,
|
||||
'password': cfg.CONF.admin_creds.admin_password,
|
||||
'tenant_name': cfg.CONF.admin_creds.admin_tenant,
|
||||
'auth_url': cfg.CONF.admin_creds.auth_url,
|
||||
'tenant_id': cfg.CONF.admin_creds.admin_tenant_id,
|
||||
'project_domain':
|
||||
cfg.CONF.admin_creds.admin_tenant_domain_name,
|
||||
'user_domain': cfg.CONF.admin_creds.admin_user_domain_name
|
||||
}
|
||||
if 'keystone' in OpenStackDriver.os_clients_dict:
|
||||
self.keystone_client = OpenStackDriver.os_clients_dict['keystone']
|
||||
else:
|
||||
self.keystone_client = KeystoneClient(**admin_kwargs)
|
||||
if region_name in OpenStackDriver.os_clients_dict:
|
||||
LOG.info(_LI('Using cached OS client objects'))
|
||||
self.nova_client = OpenStackDriver.os_clients_dict[
|
||||
|
@ -82,16 +99,11 @@ class OpenStackDriver(object):
|
|||
else:
|
||||
# Create new objects and cache them
|
||||
LOG.debug(_("Creating fresh OS Clients objects"))
|
||||
admin_kwargs = {
|
||||
'user_name': cfg.CONF.admin_creds.admin_username,
|
||||
'password': cfg.CONF.admin_creds.admin_password,
|
||||
'tenant_name': cfg.CONF.admin_creds.admin_tenant,
|
||||
'auth_url': cfg.CONF.admin_creds.auth_url,
|
||||
'tenant_id': cfg.CONF.admin_creds.admin_tenant_id
|
||||
}
|
||||
self.nova_client = NovaClient(region_name, **admin_kwargs)
|
||||
self.cinder_client = CinderClient(region_name, **admin_kwargs)
|
||||
self.neutron_client = NeutronClient(region_name, **admin_kwargs)
|
||||
self.disabled_quotas = self._get_disabled_quotas(region_name)
|
||||
self.nova_client = NovaClient(region_name, self.disabled_quotas,
|
||||
**admin_kwargs)
|
||||
OpenStackDriver.os_clients_dict[
|
||||
region_name] = collections.defaultdict(dict)
|
||||
OpenStackDriver.os_clients_dict[region_name][
|
||||
|
@ -100,11 +112,6 @@ class OpenStackDriver(object):
|
|||
'cinder'] = self.cinder_client
|
||||
OpenStackDriver.os_clients_dict[region_name][
|
||||
'neutron'] = self.neutron_client
|
||||
if 'keystone' in OpenStackDriver.os_clients_dict:
|
||||
self.keystone_client = OpenStackDriver.os_clients_dict['keystone']
|
||||
else:
|
||||
self.keystone_client = KeystoneClient(**admin_kwargs)
|
||||
OpenStackDriver.os_clients_dict['keystone'] = self.keystone_client
|
||||
|
||||
def get_enabled_projects(self):
|
||||
try:
|
||||
|
@ -152,3 +159,27 @@ class OpenStackDriver(object):
|
|||
del OpenStackDriver.os_clients_dict[self.region_name]
|
||||
except Exception as exception:
|
||||
LOG.error(_LE('Error Occurred: %s'), exception.message)
|
||||
|
||||
def _get_disabled_quotas(self, region):
|
||||
disabled_quotas = []
|
||||
# Neutron
|
||||
if not self.keystone_client.is_service_enabled('network'):
|
||||
disabled_quotas.extend(consts.NEUTRON_QUOTA_FIELDS)
|
||||
else:
|
||||
# Remove the nova network quotas
|
||||
disabled_quotas.extend(['floating_ips', 'fixed_ips'])
|
||||
if self.neutron_client.is_extension_supported('security-group'):
|
||||
# If Neutron security group is supported, disable Nova quotas
|
||||
disabled_quotas.extend(['security_groups',
|
||||
'security_group_rules'])
|
||||
else:
|
||||
# If Nova security group is used, disable Neutron quotas
|
||||
disabled_quotas.extend(['security_group',
|
||||
'security_group_rule'])
|
||||
try:
|
||||
if not self.neutron_client.is_extension_supported('quotas'):
|
||||
disabled_quotas.extend(consts.NEUTRON_QUOTA_FIELDS)
|
||||
except Exception:
|
||||
LOG.exception("There was an error checking if the Neutron "
|
||||
"quotas extension is enabled.")
|
||||
return disabled_quotas
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
import mock
|
||||
|
||||
import keystoneclient
|
||||
|
||||
from kingbird.drivers.openstack import keystone_v3
|
||||
from kingbird.tests import base
|
||||
from kingbird.tests import utils
|
||||
|
@ -22,20 +20,28 @@ FAKE_ADMIN_CREDS = {
|
|||
'user_name': 'fake_user',
|
||||
'password': 'pass1234',
|
||||
'tenant_name': 'test_tenant',
|
||||
'auth_url': 'http://127.0.0.1:5000/v3'
|
||||
'auth_url': 'http://127.0.0.1:5000/v3',
|
||||
'project_domain': 'domain1',
|
||||
'user_domain': 'user_dom'
|
||||
}
|
||||
|
||||
FAKE_SERVICE = [
|
||||
'endpoint_volume',
|
||||
'endpoint_network'
|
||||
]
|
||||
|
||||
|
||||
class TestKeystoneClient(base.KingbirdTestCase):
|
||||
def setUp(self):
|
||||
super(TestKeystoneClient, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
|
||||
def test_init(self):
|
||||
@mock.patch.object(keystone_v3, 'KeystoneClient')
|
||||
def test_init(self, mock_keystone):
|
||||
mock_keystone().services_list = FAKE_SERVICE
|
||||
key_client = keystone_v3.KeystoneClient(**FAKE_ADMIN_CREDS)
|
||||
self.assertIsNotNone(key_client.keystone_client)
|
||||
self.assertIsInstance(key_client.keystone_client,
|
||||
keystoneclient.v3.client.Client)
|
||||
self.assertEqual(key_client.services_list,
|
||||
FAKE_SERVICE)
|
||||
|
||||
@mock.patch.object(keystone_v3, 'KeystoneClient')
|
||||
def test_get_enabled_projects(self, mock_key_client):
|
||||
|
@ -46,3 +52,10 @@ class TestKeystoneClient(base.KingbirdTestCase):
|
|||
except Exception:
|
||||
raised = True
|
||||
self.assertFalse(raised, 'get_enabled_projects Failed')
|
||||
|
||||
@mock.patch.object(keystone_v3, 'KeystoneClient')
|
||||
def test_is_service_enabled(self, mock_keystone):
|
||||
key_client = keystone_v3.KeystoneClient(**FAKE_ADMIN_CREDS)
|
||||
mock_keystone().is_service_enabled.return_value = True
|
||||
network_enabled = key_client.is_service_enabled('network')
|
||||
self.assertEqual(network_enabled, True)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import neutronclient
|
||||
import mock
|
||||
|
||||
from kingbird.drivers.openstack import neutron_v2
|
||||
from kingbird.tests import base
|
||||
|
@ -23,18 +23,32 @@ FAKE_ADMIN_CREDS = {
|
|||
'auth_url': 'http://127.0.0.1:5000/v3'
|
||||
}
|
||||
|
||||
FAKE_EXTENSIONS = {
|
||||
'extensions': ['fake_extension1',
|
||||
'fake_extension2']
|
||||
}
|
||||
|
||||
|
||||
class TestNeutronClient(base.KingbirdTestCase):
|
||||
def setUp(self):
|
||||
super(TestNeutronClient, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
|
||||
def test_init(self):
|
||||
@mock.patch.object(neutron_v2, 'NeutronClient')
|
||||
def test_init(self, mock_neutron):
|
||||
mock_neutron().extension_list = FAKE_EXTENSIONS
|
||||
neutron_client = neutron_v2.NeutronClient('fake_region',
|
||||
**FAKE_ADMIN_CREDS)
|
||||
self.assertIsNotNone(neutron_client)
|
||||
self.assertIsInstance(neutron_client.neutron_client,
|
||||
neutronclient.v2_0.client.Client)
|
||||
self.assertEqual(FAKE_EXTENSIONS,
|
||||
neutron_client.extension_list)
|
||||
|
||||
@mock.patch.object(neutron_v2, 'NeutronClient')
|
||||
def test_is_extension_supported(self, mock_neutron):
|
||||
neutron_client = neutron_v2.NeutronClient('fake_region',
|
||||
**FAKE_ADMIN_CREDS)
|
||||
mock_neutron().is_extension_supported.return_value = True
|
||||
extension_enabled = neutron_client.is_extension_supported('quotas')
|
||||
self.assertEqual(extension_enabled, True)
|
||||
|
||||
def test_get_resource_usages(self):
|
||||
pass
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import novaclient
|
||||
|
||||
from kingbird.common import consts
|
||||
from kingbird.drivers.openstack import nova_v2
|
||||
from kingbird.tests import base
|
||||
from kingbird.tests import utils
|
||||
|
@ -22,6 +23,7 @@ FAKE_ADMIN_CREDS = {
|
|||
'tenant_name': 'test_tenant',
|
||||
'auth_url': 'http://127.0.0.1:5000/v3'
|
||||
}
|
||||
DISABLED_QUOTAS = ["floating_ips", "fixed_ips", "security_groups"]
|
||||
|
||||
|
||||
class TestNovaClient(base.KingbirdTestCase):
|
||||
|
@ -30,8 +32,12 @@ class TestNovaClient(base.KingbirdTestCase):
|
|||
self.ctx = utils.dummy_context()
|
||||
|
||||
def test_init(self):
|
||||
nv_client = nova_v2.NovaClient('fake_region', **FAKE_ADMIN_CREDS)
|
||||
nv_client = nova_v2.NovaClient('fake_region', DISABLED_QUOTAS,
|
||||
**FAKE_ADMIN_CREDS)
|
||||
self.assertIsNotNone(nv_client)
|
||||
expected_quotas = list(set(consts.NOVA_QUOTA_FIELDS) -
|
||||
set(DISABLED_QUOTAS))
|
||||
self.assertEqual(nv_client.enabled_quotas, expected_quotas)
|
||||
self.assertIsInstance(nv_client.nova_client,
|
||||
novaclient.v2.client.Client)
|
||||
|
||||
|
|
|
@ -17,6 +17,17 @@ from kingbird.tests import base
|
|||
from kingbird.tests import utils
|
||||
|
||||
|
||||
class FakeService(object):
|
||||
|
||||
'''Fake service class used to test service enable testcase
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, type_service, name):
|
||||
self.type = type_service
|
||||
self.name = name
|
||||
|
||||
|
||||
class TestOpenStackDriver(base.KingbirdTestCase):
|
||||
def setUp(self):
|
||||
super(TestOpenStackDriver, self).setUp()
|
||||
|
@ -132,3 +143,18 @@ class TestOpenStackDriver(base.KingbirdTestCase):
|
|||
self.assertEqual(os_driver_2.cinder_client, os_driver_4.cinder_client)
|
||||
self.assertEqual(os_driver_2.neutron_client,
|
||||
os_driver_4.neutron_client)
|
||||
|
||||
@mock.patch.object(sdk, 'KeystoneClient')
|
||||
@mock.patch.object(sdk, 'NovaClient')
|
||||
@mock.patch.object(sdk, 'NeutronClient')
|
||||
@mock.patch.object(sdk, 'CinderClient')
|
||||
def test_get_disabled_quotas(self, mock_cinder_client,
|
||||
mock_network_client, mock_nova_client,
|
||||
mock_keystone_client):
|
||||
input_disable_quotas = ["floating_ips", "security_groups",
|
||||
"security_group_rules"]
|
||||
os_driver = sdk.OpenStackDriver('fake_region9')
|
||||
output_disabled_quotas = os_driver._get_disabled_quotas('fake_region9')
|
||||
self.assertIn(input_disable_quotas[0], output_disabled_quotas)
|
||||
self.assertIn(input_disable_quotas[1], output_disabled_quotas)
|
||||
self.assertIn(input_disable_quotas[2], output_disabled_quotas)
|
||||
|
|
Loading…
Reference in New Issue