Merge "High level interface"

This commit is contained in:
Jenkins 2014-10-29 22:57:37 +00:00 committed by Gerrit Code Review
commit 94e83e34a3
29 changed files with 327 additions and 4 deletions

View File

@ -25,12 +25,25 @@ filter to match a service.
from openstack import exceptions from openstack import exceptions
class ValidVersion(object):
def __init__(self, module, path=None):
"""" Valid service version.
:param string module: Module associated with version.
:param string path: URL path version.
"""
self.module = module
self.path = path or module
class ServiceFilter(object): class ServiceFilter(object):
ANY = 'any' ANY = 'any'
PUBLIC = 'public' PUBLIC = 'public'
INTERNAL = 'internal' INTERNAL = 'internal'
ADMIN = 'admin' ADMIN = 'admin'
VISIBILITY = [PUBLIC, INTERNAL, ADMIN] VISIBILITY = [PUBLIC, INTERNAL, ADMIN]
valid_versions = []
def __init__(self, service_type=ANY, visibility=PUBLIC, region=None, def __init__(self, service_type=ANY, visibility=PUBLIC, region=None,
service_name=None, version=None): service_name=None, version=None):
@ -115,3 +128,20 @@ class ServiceFilter(object):
msg = "Visibility <%s> not in %s" % (visibility, self.VISIBILITY) msg = "Visibility <%s> not in %s" % (visibility, self.VISIBILITY)
raise exceptions.SDKException(msg) raise exceptions.SDKException(msg)
self.visibility = visibility self.visibility = visibility
def get_module(self):
"""Get the full module name associated with the service."""
module = self.__class__.__module__.split('.')
module = ".".join(module[:-1])
# NOTE(thowe): Only support for one valid version right now.
module = module + "." + self.valid_versions[0].module
return module
def get_service_module(self):
"""Get the module version of the service name.
This would often be the same as the service type except in cases like
object store where the service type is `object-store` and the module
is `object_store`.
"""
return self.__class__.__module__.split('.')[1]

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class ComputeService(service_filter.ServiceFilter): class ComputeService(service_filter.ServiceFilter):
"""The compute service.""" """The compute service."""
valid_versions = [service_filter.ValidVersion('v2')]
def __init__(self): def __init__(self):
"""Create an compute service.""" """Create an compute service."""
super(ComputeService, self).__init__(service_type='compute') super(ComputeService, self).__init__(service_type='compute')

View File

@ -0,0 +1,22 @@
# 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.
from openstack.compute.v2 import flavor
class Proxy(object):
def __init__(self, session):
self.session = session
def list_flavors(self, **params):
return flavor.Flavor.list(self.session, **params)

View File

@ -58,6 +58,8 @@ try to find it and if that fails, you would create it::
network = conn.network.create_network({"name": "jenkins"}) network = conn.network.create_network({"name": "jenkins"})
""" """
import logging
import sys
from stevedore import driver from stevedore import driver
@ -68,6 +70,7 @@ from openstack import transport as xport
USER_AGENT = 'OSPythonSDK' USER_AGENT = 'OSPythonSDK'
"""Default value for the HTTP User-Agent header""" """Default value for the HTTP User-Agent header"""
_logger = logging.getLogger(__name__)
class Connection(object): class Connection(object):
@ -128,6 +131,7 @@ class Connection(object):
**auth_args) **auth_args)
self.session = session.Session(self.transport, self.authenticator, self.session = session.Session(self.transport, self.authenticator,
preference) preference)
self._open()
def _create_transport(self, transport, verify, user_agent): def _create_transport(self, transport, verify, user_agent):
if transport: if transport:
@ -157,3 +161,21 @@ class Connection(object):
valid_list = plugin.valid_options valid_list = plugin.valid_options
args = dict((n, auth_args[n]) for n in valid_list if n in auth_args) args = dict((n, auth_args[n]) for n in valid_list if n in auth_args)
return plugin(**args) return plugin(**args)
def _open(self):
"""Open the connection.
NOTE(thowe): Have this set up some lazy loader instead.
"""
for service in self.session.get_services():
self._load(service)
def _load(self, service):
attr_name = service.get_service_module()
module = service.get_module() + "._proxy"
try:
__import__(module)
proxy = getattr(sys.modules[module], "Proxy")
setattr(self, attr_name, proxy(self.session))
except Exception as e:
_logger.warn("Unable to load %s: %s" % (module, e))

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class DatabaseService(service_filter.ServiceFilter): class DatabaseService(service_filter.ServiceFilter):
"""The database service.""" """The database service."""
valid_versions = [service_filter.ValidVersion('v1')]
def __init__(self): def __init__(self):
"""Create an database service.""" """Create an database service."""
super(DatabaseService, self).__init__(service_type='database') super(DatabaseService, self).__init__(service_type='database')

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -16,6 +16,11 @@ from openstack.auth import service_filter
class IdentityService(service_filter.ServiceFilter): class IdentityService(service_filter.ServiceFilter):
"""The identity service.""" """The identity service."""
valid_versions = [
service_filter.ValidVersion('v3'),
service_filter.ValidVersion('v2'),
]
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Create an identity service.""" """Create an identity service."""
kwargs['service_type'] = 'identity' kwargs['service_type'] = 'identity'

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -0,0 +1,43 @@
# 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.
from openstack.identity.v3 import project
class Proxy(object):
def __init__(self, session):
self.session = session
def create_project(self, **data):
obj = project.Project(**data)
obj.create(self.session)
return obj
def get_project(self, r_id):
obj = project.Project({'id': r_id})
obj.get(self.session)
return obj
def update_project(self, **data):
obj = project.Project(**data)
obj.update(self.session)
def delete_project(self, r_id):
obj = project.Project({'id': r_id})
obj.delete(self.session)
def list_projects(self, **params):
return project.Project.list(self.session, **params)
def find_project(self, name_or_id):
return project.Project.find(self.session, name_or_id)

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class ImageService(service_filter.ServiceFilter): class ImageService(service_filter.ServiceFilter):
"""The image service.""" """The image service."""
valid_versions = [service_filter.ValidVersion('v1')]
def __init__(self): def __init__(self):
"""Create an image service.""" """Create an image service."""
super(ImageService, self).__init__(service_type='image') super(ImageService, self).__init__(service_type='image')

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class NetworkService(service_filter.ServiceFilter): class NetworkService(service_filter.ServiceFilter):
"""The network service.""" """The network service."""
valid_versions = [service_filter.ValidVersion('v2', 'v2.0')]
def __init__(self): def __init__(self):
"""Create an network service.""" """Create an network service."""
super(NetworkService, self).__init__(service_type='network') super(NetworkService, self).__init__(service_type='network')

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class ObjectStoreService(service_filter.ServiceFilter): class ObjectStoreService(service_filter.ServiceFilter):
"""The object store service.""" """The object store service."""
valid_versions = [service_filter.ValidVersion('v1')]
def __init__(self): def __init__(self):
"""Create an object store service.""" """Create an object store service."""
super(ObjectStoreService, self).__init__(service_type='object-store') super(ObjectStoreService, self).__init__(service_type='object-store')

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class OrchestrationService(service_filter.ServiceFilter): class OrchestrationService(service_filter.ServiceFilter):
"""The orchestration service.""" """The orchestration service."""
valid_versions = [service_filter.ValidVersion('v1')]
def __init__(self): def __init__(self):
"""Create an orchestration service.""" """Create an orchestration service."""
super(OrchestrationService, self).__init__( super(OrchestrationService, self).__init__(

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -16,6 +16,8 @@ from openstack.auth import service_filter
class TelemetryService(service_filter.ServiceFilter): class TelemetryService(service_filter.ServiceFilter):
"""The telemetry service.""" """The telemetry service."""
valid_versions = [service_filter.ValidVersion('v2')]
def __init__(self): def __init__(self):
"""Create a telemetry service.""" """Create a telemetry service."""
super(TelemetryService, self).__init__(service_type='metering') super(TelemetryService, self).__init__(service_type='metering')

View File

@ -0,0 +1,17 @@
# 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.
class Proxy(object):
def __init__(self, session):
self.session = session

View File

@ -15,6 +15,7 @@ import testtools
from openstack.auth import service_filter as filt from openstack.auth import service_filter as filt
from openstack import exceptions from openstack import exceptions
from openstack.identity import identity_service
class TestServiceFilter(testtools.TestCase): class TestServiceFilter(testtools.TestCase):
@ -124,3 +125,15 @@ class TestServiceFilter(testtools.TestCase):
self.assertEqual('internal', sot.visibility) self.assertEqual('internal', sot.visibility)
sot.set_visibility("ADMINURL") sot.set_visibility("ADMINURL")
self.assertEqual('admin', sot.visibility) self.assertEqual('admin', sot.visibility)
def test_get_module(self):
sot = identity_service.IdentityService()
self.assertEqual('openstack.identity.v3', sot.get_module())
self.assertEqual('identity', sot.get_service_module())
class TestValidVersion(testtools.TestCase):
def test_constructor(self):
sot = filt.ValidVersion('v1.0', 'v1')
self.assertEqual('v1.0', sot.module)
self.assertEqual('v1', sot.path)

View File

@ -23,3 +23,6 @@ class TestComputeService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v2', sot.valid_versions[0].module)
self.assertEqual('v2', sot.valid_versions[0].path)

View File

@ -23,3 +23,6 @@ class TestDatabaseService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v1', sot.valid_versions[0].module)
self.assertEqual('v1', sot.valid_versions[0].path)

View File

@ -23,6 +23,11 @@ class TestIdentityService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(2, len(sot.valid_versions))
self.assertEqual('v3', sot.valid_versions[0].module)
self.assertEqual('v3', sot.valid_versions[0].path)
self.assertEqual('v2', sot.valid_versions[1].module)
self.assertEqual('v2', sot.valid_versions[1].path)
def test_admin_service(self): def test_admin_service(self):
sot = identity_service.AdminService() sot = identity_service.AdminService()

View File

@ -23,3 +23,6 @@ class TestImageService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v1', sot.valid_versions[0].module)
self.assertEqual('v1', sot.valid_versions[0].path)

View File

@ -23,3 +23,6 @@ class TestNetworkService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v2', sot.valid_versions[0].module)
self.assertEqual('v2.0', sot.valid_versions[0].path)

View File

@ -23,3 +23,6 @@ class TestObjectStoreService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v1', sot.valid_versions[0].module)
self.assertEqual('v1', sot.valid_versions[0].path)

View File

@ -23,3 +23,6 @@ class TestOrchestrationService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v1', sot.valid_versions[0].module)
self.assertEqual('v1', sot.valid_versions[0].path)

View File

@ -23,3 +23,6 @@ class TestTelemetryService(testtools.TestCase):
self.assertEqual('public', sot.visibility) self.assertEqual('public', sot.visibility)
self.assertIsNone(sot.region) self.assertIsNone(sot.region)
self.assertIsNone(sot.service_name) self.assertIsNone(sot.service_name)
self.assertEqual(1, len(sot.valid_versions))
self.assertEqual('v2', sot.valid_versions[0].module)
self.assertEqual('v2', sot.valid_versions[0].path)

View File

@ -10,12 +10,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from openstack.auth.identity import v2
from openstack import connection from openstack import connection
from openstack import exceptions from openstack import exceptions
from openstack.tests import base from openstack.tests import base
from openstack import transport
from openstack import user_preference
class TestConnection(base.TestCase): class TestConnection(base.TestCase):
def setUp(self):
super(TestConnection, self).setUp()
self.xport = transport.Transport()
self.auth = v2.Auth(auth_url='http://127.0.0.1/v2', token='b')
self.pref = user_preference.UserPreference()
def test_create_transport(self): def test_create_transport(self):
conn = connection.Connection(authenticator='2', verify=True, conn = connection.Connection(authenticator='2', verify=True,
user_agent='1') user_agent='1')
@ -73,8 +82,28 @@ class TestConnection(base.TestCase):
) )
def test_create_session(self): def test_create_session(self):
args = {'transport': '0', 'authenticator': '1', 'preference': '2'} args = {
'transport': self.xport,
'authenticator': self.auth,
'preference': self.pref,
}
conn = connection.Connection(**args) conn = connection.Connection(**args)
self.assertEqual('0', conn.session.transport) self.assertEqual(self.xport, conn.session.transport)
self.assertEqual('1', conn.session.authenticator) self.assertEqual(self.auth, conn.session.authenticator)
self.assertEqual('2', conn.session.preference) self.assertEqual(self.pref, conn.session.preference)
self.assertEqual('openstack.compute.v2._proxy',
conn.compute.__class__.__module__)
self.assertEqual('openstack.database.v1._proxy',
conn.database.__class__.__module__)
self.assertEqual('openstack.identity.v3._proxy',
conn.identity.__class__.__module__)
self.assertEqual('openstack.image.v1._proxy',
conn.image.__class__.__module__)
self.assertEqual('openstack.network.v2._proxy',
conn.network.__class__.__module__)
self.assertEqual('openstack.object_store.v1._proxy',
conn.object_store.__class__.__module__)
self.assertEqual('openstack.orchestration.v1._proxy',
conn.orchestration.__class__.__module__)
self.assertEqual('openstack.telemetry.v2._proxy',
conn.telemetry.__class__.__module__)