Merge "Migrate away from rackspace_resource"

This commit is contained in:
Jenkins 2013-12-04 06:00:39 +00:00 committed by Gerrit Code Review
commit fde8c4dc55
11 changed files with 223 additions and 217 deletions

View File

@ -18,7 +18,7 @@ Resources for Rackspace Auto Scale.
import copy
from . import rackspace_resource # noqa
from heat.engine import resource
from heat.db.sqlalchemy import api as db_api
from heat.common import exception
@ -31,9 +31,14 @@ except ImportError:
class NotFound(Exception):
"""Dummy pyrax exception - only used for testing."""
def resource_mapping():
return {}
else:
def resource_mapping():
return unprotected_resources()
class Group(rackspace_resource.RackspaceResource):
class Group(resource.Resource):
"""Represents a scaling group."""
# pyrax differs drastically from the actual Auto Scale API. We'll prefer
@ -222,7 +227,7 @@ class Group(rackspace_resource.RackspaceResource):
Create the autoscaling group and set the resulting group's ID as the
resource_id.
"""
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
group = asclient.create(**self._get_create_args())
self.resource_id_set(str(group.id))
@ -230,7 +235,7 @@ class Group(rackspace_resource.RackspaceResource):
"""
Update the group configuration and the launch configuration.
"""
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
if 'groupConfiguration' in prop_diff:
args = self._get_group_config_args(prop_diff['groupConfiguration'])
asclient.replace(self.resource_id, **args)
@ -250,7 +255,7 @@ class Group(rackspace_resource.RackspaceResource):
"""
if self.resource_id is None:
return
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
args = self._get_group_config_args(
self.properties['groupConfiguration'])
args['min_entities'] = 0
@ -265,7 +270,7 @@ class Group(rackspace_resource.RackspaceResource):
if self.resource_id is None:
return True
try:
self.auto_scale().delete(self.resource_id)
self.stack.clients.auto_scale().delete(self.resource_id)
except Forbidden:
return False
except NotFound:
@ -274,7 +279,7 @@ class Group(rackspace_resource.RackspaceResource):
return True
class ScalingPolicy(rackspace_resource.RackspaceResource):
class ScalingPolicy(resource.Resource):
"""Represents a Rackspace Auto Scale scaling policy."""
properties_schema = {
# group isn't in the post body, but it's in the URL to post to.
@ -355,7 +360,7 @@ class ScalingPolicy(rackspace_resource.RackspaceResource):
Create the scaling policy, and initialize the resource ID to
{group_id}:{policy_id}.
"""
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
args = self._get_args(self.properties)
policy = asclient.add_policy(**args)
resource_id = '%s:%s' % (self.properties['group'], policy.id)
@ -365,14 +370,14 @@ class ScalingPolicy(rackspace_resource.RackspaceResource):
return self.resource_id.split(':', 1)[1]
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
args = self._get_args(tmpl_diff['Properties'])
args['policy'] = self._get_policy_id()
asclient.replace_policy(**args)
def handle_delete(self):
"""Delete the policy if it exists."""
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
if self.resource_id is None:
return
policy_id = self._get_policy_id()
@ -382,7 +387,7 @@ class ScalingPolicy(rackspace_resource.RackspaceResource):
pass
class WebHook(rackspace_resource.RackspaceResource):
class WebHook(resource.Resource):
"""
Represents a Rackspace AutoScale webhook.
@ -427,7 +432,7 @@ class WebHook(rackspace_resource.RackspaceResource):
metadata=props.get('metadata'))
def handle_create(self):
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
args = self._get_args(self.properties)
webhook = asclient.add_webhook(**args)
self.resource_id_set(webhook.id)
@ -441,7 +446,7 @@ class WebHook(rackspace_resource.RackspaceResource):
db_api.resource_data_set(self, key, url)
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
args = self._get_args(json_snippet['Properties'])
args['webhook'] = self.resource_id
asclient.replace_webhook(**args)
@ -455,7 +460,7 @@ class WebHook(rackspace_resource.RackspaceResource):
def handle_delete(self):
if self.resource_id is None:
return
asclient = self.auto_scale()
asclient = self.stack.clients.auto_scale()
group_id, policy_id = self.properties['policy'].split(':', 1)
try:
asclient.delete_webhook(group_id, policy_id, self.resource_id)
@ -469,10 +474,3 @@ def unprotected_resources():
'Rackspace::AutoScale::ScalingPolicy': ScalingPolicy,
'Rackspace::AutoScale::WebHook': WebHook
}
def resource_mapping():
if rackspace_resource.PYRAX_INSTALLED:
return unprotected_resources()
else:
return {}

View File

@ -0,0 +1,107 @@
# 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.
from oslo.config import cfg
from heat.openstack.common import log as logging
logger = logging.getLogger(__name__)
from heat.common import exception
from heat.engine import clients
from heat.openstack.common.gettextutils import _
try:
import pyrax
except ImportError:
logger.info('pyrax not available')
try:
from swiftclient import client as swiftclient
except ImportError:
swiftclient = None
logger.info('swiftclient not available')
try:
from ceilometerclient.v2 import client as ceilometerclient
except ImportError:
ceilometerclient = None
logger.info('ceilometerclient not available')
cloud_opts = [
cfg.StrOpt('region_name',
default=None,
help=_('Region for connecting to services'))
]
cfg.CONF.register_opts(cloud_opts)
class Clients(clients.OpenStackClients):
'''
Convenience class to create and cache client instances.
'''
def __init__(self, context):
super(Clients, self).__init__(context)
self.pyrax = None
def _get_client(self, name):
if not self.pyrax:
self.__authenticate()
return self.pyrax.get(name)
def auto_scale(self):
"""Rackspace Auto Scale client."""
return self._get_client("autoscale")
def cloud_db(self):
'''Rackspace cloud database client.'''
return self._get_client("database")
def cloud_lb(self):
'''Rackspace cloud loadbalancer client.'''
return self._get_client("load_balancer")
def cloud_dns(self):
'''Rackspace cloud dns client.'''
return self._get_client("dns")
def nova(self, service_type="compute"):
'''Rackspace cloudservers client. Specifying the service type is to
maintain compatability with clients.OpenStackClients. It is not
actually a valid option to change within pyrax.
'''
if service_type is not "compute":
raise ValueError("service_type should be compute.")
return self._get_client(service_type)
def neutron(self):
'''Rackspace neutron client.'''
return self._get_client("network")
def __authenticate(self):
# current implemenation shown below authenticates using
# username and password. Need make it work with auth-token
pyrax.set_setting("identity_type", "keystone")
pyrax.set_setting("auth_endpoint", self.context.auth_url)
logger.info("Authenticating with username:%s" %
self.context.username)
self.pyrax = pyrax.auth_with_token(self.context.auth_token,
tenant_id=self.context.tenant_id,
tenant_name=self.context.tenant,
region=(cfg.CONF.region_name
or None))
if not self.pyrax:
raise exception.AuthorizationFailure("No services available.")
logger.info("User %s authenticated successfully."
% self.context.username)

View File

@ -17,16 +17,21 @@ except ImportError:
class NotFound(Exception):
pass
def resource_mapping():
return {}
else:
def resource_mapping():
return {'Rackspace::Cloud::DNS': CloudDns}
from heat.common import exception
from heat.engine import resource
from heat.openstack.common import log as logging
from . import rackspace_resource
logger = logging.getLogger(__name__)
class CloudDns(rackspace_resource.RackspaceResource):
class CloudDns(resource.Resource):
record_schema = {
'name': {
@ -119,6 +124,9 @@ class CloudDns(rackspace_resource.RackspaceResource):
update_allowed_keys = ('Properties',)
def cloud_dns(self):
return self.stack.clients.cloud_dns()
def handle_create(self):
"""
Create a Rackspace CloudDns Instance.
@ -171,12 +179,3 @@ class CloudDns(rackspace_resource.RackspaceResource):
except NotFound:
pass
self.resource_id_set(None)
# pyrax module is required to work with Rackspace cloud server provider.
# If it is not installed, don't register cloud server provider
def resource_mapping():
if rackspace_resource.PYRAX_INSTALLED:
return {'Rackspace::Cloud::DNS': CloudDns}
else:
return {}

View File

@ -18,14 +18,20 @@ except ImportError:
class NotFound(Exception):
pass
def resource_mapping():
return {}
else:
def resource_mapping():
return {'Rackspace::Cloud::LoadBalancer': CloudLoadBalancer}
from heat.openstack.common import log as logging
from heat.openstack.common.gettextutils import _
from heat.engine import scheduler
from heat.engine import resource
from heat.engine.properties import Properties
from heat.common import exception
from . import rackspace_resource # noqa
logger = logging.getLogger(__name__)
@ -33,7 +39,7 @@ class LoadbalancerBuildError(exception.HeatException):
msg_fmt = _("There was an error building the loadbalancer:%(lb_name)s.")
class CloudLoadBalancer(rackspace_resource.RackspaceResource):
class CloudLoadBalancer(resource.Resource):
protocol_values = ["DNS_TCP", "DNS_UDP", "FTP", "HTTP", "HTTPS", "IMAPS",
"IMAPv4", "LDAP", "LDAPS", "MYSQL", "POP3", "POP3S",
@ -191,6 +197,9 @@ class CloudLoadBalancer(rackspace_resource.RackspaceResource):
super(CloudLoadBalancer, self).__init__(name, json_snippet, stack)
self.clb = self.cloud_lb()
def cloud_lb(self):
return self.stack.clients.cloud_lb()
def _setup_properties(self, properties, function):
"""Use defined schema properties as kwargs for loadbalancer objects."""
if properties and function:
@ -447,12 +456,3 @@ class CloudLoadBalancer(rackspace_resource.RackspaceResource):
function = attribute_function[key]
logger.info('%s.GetAtt(%s) == %s' % (self.name, key, function))
return unicode(function)
def resource_mapping():
if rackspace_resource.PYRAX_INSTALLED:
return {
'Rackspace::Cloud::LoadBalancer': CloudLoadBalancer
}
else:
return {}

View File

@ -24,7 +24,16 @@ from heat.engine.resources import instance
from heat.engine.resources import nova_utils
from heat.db.sqlalchemy import api as db_api
from . import rackspace_resource # noqa
try:
import pyrax # noqa
except ImportError:
def resource_mapping():
return {}
else:
def resource_mapping():
return {'Rackspace::Cloud::Server': CloudServer}
logger = logging.getLogger(__name__)
@ -170,9 +179,6 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel
self._private_ip = None
self._flavor = None
self._image = None
self.rs = rackspace_resource.RackspaceResource(name,
json_snippet,
stack)
def physical_resource_name(self):
name = self.properties.get('name')
@ -181,12 +187,6 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel
return super(CloudServer, self).physical_resource_name()
def nova(self):
return self.rs.nova() # Override the Instance method
def cinder(self):
return self.rs.cinder()
@property
def server(self):
"""Get the Cloud Server object."""
@ -320,7 +320,6 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel
running, so we have to transfer the user-data file to the
server and then trigger cloud-init.
"""
# Generate SSH public/private keypair
if self._private_key is not None:
rsa = RSA.importKey(self._private_key)
@ -531,12 +530,3 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel
logger.info('%s._resolve_attribute(%s) == %s'
% (self.name, key, function))
return unicode(function)
# pyrax module is required to work with Rackspace cloud server provider.
# If it is not installed, don't register cloud server provider
def resource_mapping():
if rackspace_resource.PYRAX_INSTALLED:
return {'Rackspace::Cloud::Server': CloudServer}
else:
return {}

View File

@ -31,15 +31,21 @@ except ImportError:
return formatted_string
def resource_mapping():
return {}
else:
def resource_mapping():
return {'Rackspace::Cloud::DBInstance': CloudDBInstance}
from heat.common import exception
from heat.openstack.common import log as logging
from . import rackspace_resource # noqa
from heat.engine import resource
logger = logging.getLogger(__name__)
class CloudDBInstance(rackspace_resource.RackspaceResource):
class CloudDBInstance(resource.Resource):
'''
Rackspace cloud database resource.
'''
@ -132,6 +138,9 @@ class CloudDBInstance(rackspace_resource.RackspaceResource):
self.hostname = None
self.href = None
def cloud_db(self):
return self.stack.clients.cloud_db()
def handle_create(self):
'''
Create Rackspace Cloud DB Instance.
@ -263,14 +272,3 @@ class CloudDBInstance(rackspace_resource.RackspaceResource):
return self._href()
else:
return None
# pyrax module is required to work with Rackspace cloud database provider.
# If it is not installed, don't register clouddatabase provider
def resource_mapping():
if rackspace_resource.PYRAX_INSTALLED:
return {
'Rackspace::Cloud::DBInstance': CloudDBInstance,
}
else:
return {}

View File

@ -1,117 +0,0 @@
# 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.
PYRAX_INSTALLED = True
try:
import pyrax
except ImportError:
PYRAX_INSTALLED = False
from heat.engine import resource
from heat.openstack.common import log as logging
logger = logging.getLogger(__name__)
class RackspaceResource(resource.Resource):
'''
Common base class for Rackspace Resource Providers
'''
properties_schema = {}
def __init__(self, name, json_snippet, stack):
super(RackspaceResource, self).__init__(name, json_snippet, stack)
if PYRAX_INSTALLED:
self.pyrax = pyrax
self._cloud_db = None
self._cloud_dns = None
self._cloud_lb = None
self._cloud_server = None
self._cloud_nw = None
self._cloud_blockstore = None
self._cloud_as = None
self._authenticated = False
def cloud_db(self):
'''Rackspace cloud database client.'''
if not self._cloud_db:
self.__authenticate()
self._cloud_db = self.pyrax.cloud_databases
return self._cloud_db
def cloud_lb(self):
'''Rackspace cloud loadbalancer client.'''
if not self._cloud_lb:
self.__authenticate()
self._cloud_lb = self.pyrax.cloud_loadbalancers
return self._cloud_lb
def auto_scale(self):
"""Rackspace Auto Scale client."""
if not self._cloud_as:
self.__authenticate()
self._cloud_as = self.pyrax.autoscale
return self._cloud_as
def cloud_dns(self):
'''Rackspace cloud dns client.'''
if not self._cloud_dns:
self.__authenticate()
self._cloud_dns = self.pyrax.cloud_dns
return self._cloud_dns
def nova(self):
'''Rackspace cloudservers client.'''
if not self._cloud_server:
self.__authenticate()
self._cloud_server = self.pyrax.cloudservers
return self._cloud_server
def cinder(self):
'''Rackspace cinder client.'''
if not self._cloud_blockstore:
self.__authenticate()
self._cloud_blockstore = self.pyrax.cloud_blockstorage
return self._cloud_blockstore
def neutron(self):
'''Rackspace neutron client.'''
if not self._cloud_nw:
self.__authenticate()
self._cloud_nw = self.pyrax.cloud_networks
return self._cloud_nw
def __authenticate(self):
# current implemenation shown below authenticates using
# username and password. Need make it work with auth-token
if not self._authenticated:
pyrax.set_setting("identity_type", "rackspace")
pyrax.set_setting("auth_endpoint", self.context.auth_url)
pyrax.set_setting("tenant_id", self.context.tenant)
logger.info("Authenticating with username:%s" %
self.context.username)
pyrax.auth_with_token(self.context.auth_token,
tenant_id=self.context.tenant_id,
tenant_name=self.context.tenant)
logger.info("User %s authenticated successfully."
% self.context.username)
self._authenticated = True

View File

@ -17,11 +17,11 @@ import itertools
from heat.common import exception
from heat.common import template_format
from heat.engine import clients
from heat.engine import resource
from heat.engine import scheduler
from ..engine.plugins import auto_scale # noqa
from ..engine.plugins import rackspace_resource # noqa
from heat.tests.common import HeatTestCase
from heat.tests import utils
@ -200,7 +200,7 @@ class ScalingGroupTest(HeatTestCase):
for res_name, res_class in auto_scale.unprotected_resources().items():
resource._register_class(res_name, res_class)
self.fake_auto_scale = FakeAutoScale()
self.patch(rackspace_resource.RackspaceResource,
self.patch(clients.OpenStackClients,
'auto_scale', lambda resource: self.fake_auto_scale)
def _setup_test_stack(self):
@ -349,7 +349,7 @@ class PolicyTest(HeatTestCase):
for res_name, res_class in auto_scale.unprotected_resources().items():
resource._register_class(res_name, res_class)
self.fake_auto_scale = FakeAutoScale()
self.patch(rackspace_resource.RackspaceResource,
self.patch(clients.OpenStackClients,
'auto_scale', lambda resource: self.fake_auto_scale)
def _setup_test_stack(self, template):
@ -493,7 +493,7 @@ class WebHookTest(HeatTestCase):
for res_name, res_class in auto_scale.unprotected_resources().items():
resource._register_class(res_name, res_class)
self.fake_auto_scale = FakeAutoScale()
self.patch(rackspace_resource.RackspaceResource,
self.patch(clients.OpenStackClients,
'auto_scale', lambda resource: self.fake_auto_scale)
def _setup_test_stack(self, template):

View File

@ -0,0 +1,31 @@
# 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.
from oslo.config import cfg
from heat.engine import clients
from heat.tests.common import HeatTestCase
from ..engine.plugins import clients as rackspace_clients # noqa
class ClientsTest(HeatTestCase):
def setUp(self):
super(ClientsTest, self).setUp()
cfg.CONF.cloud_backend = (
'rackspace.heat.engine.plugins.clients.Clients')
self.backend = clients.ClientBackend('fake_context')
def test_client_plugin_loads(self):
self.assertTrue(isinstance(self.backend, rackspace_clients.Clients))

View File

@ -27,7 +27,7 @@ from heat.openstack.common import uuidutils
from heat.tests.common import HeatTestCase
from heat.tests import utils
from ..engine.plugins import rackspace_resource # noqa
from heat.engine import clients
from ..engine.plugins import cloud_server # noqa
@ -134,9 +134,9 @@ class RackspaceCloudServerTest(HeatTestCase):
stack_name = '%s_stack' % name
(t, stack) = self._setup_test_stack(stack_name)
self.m.StubOutWithMock(rackspace_resource.RackspaceResource, "nova")
rackspace_resource.RackspaceResource.nova().MultipleTimes()\
.AndReturn(self.fc)
self.m.StubOutWithMock(clients.OpenStackClients, "nova")
clients.OpenStackClients.nova(
mox.IgnoreArg()).MultipleTimes().AndReturn(self.fc)
t['Resources']['WebServer']['Properties']['image'] = 'CentOS 5.2'
t['Resources']['WebServer']['Properties']['flavor'] = '256 MB Server'
@ -167,9 +167,9 @@ class RackspaceCloudServerTest(HeatTestCase):
def _update_test_cs(self, return_server, name, exit_code=0):
self._mock_ssh_sftp(exit_code)
self.m.StubOutWithMock(rackspace_resource.RackspaceResource, "nova")
rackspace_resource.RackspaceResource.nova().MultipleTimes()\
.AndReturn(self.fc)
self.m.StubOutWithMock(clients.OpenStackClients, "nova")
clients.OpenStackClients.nova(
mox.IgnoreArg()).MultipleTimes().AndReturn(self.fc)
def test_cs_create(self):
return_server = self.fc.servers.list()[1]
@ -207,9 +207,9 @@ class RackspaceCloudServerTest(HeatTestCase):
self.m.VerifyAll()
def test_cs_create_image_name_err(self):
self.m.StubOutWithMock(rackspace_resource.RackspaceResource, "nova")
rackspace_resource.RackspaceResource.nova().MultipleTimes()\
.AndReturn(self.fc)
self.m.StubOutWithMock(clients.OpenStackClients, "nova")
clients.OpenStackClients.nova(
mox.IgnoreArg()).MultipleTimes().AndReturn(self.fc)
stack_name = 'test_cs_create_image_name_err_stack'
(t, stack) = self._setup_test_stack(stack_name)
@ -227,9 +227,9 @@ class RackspaceCloudServerTest(HeatTestCase):
self.m.VerifyAll()
def test_cs_create_image_name_okay(self):
self.m.StubOutWithMock(rackspace_resource.RackspaceResource, "nova")
rackspace_resource.RackspaceResource.nova().MultipleTimes()\
.AndReturn(self.fc)
self.m.StubOutWithMock(clients.OpenStackClients, "nova")
clients.OpenStackClients.nova(
mox.IgnoreArg()).MultipleTimes().AndReturn(self.fc)
stack_name = 'test_cs_create_image_name_err_stack'
(t, stack) = self._setup_test_stack(stack_name)
@ -283,9 +283,9 @@ class RackspaceCloudServerTest(HeatTestCase):
def test_cs_create_flavor_err(self):
"""validate() should throw an if the flavor is invalid."""
self.m.StubOutWithMock(rackspace_resource.RackspaceResource, "nova")
rackspace_resource.RackspaceResource.nova().MultipleTimes()\
.AndReturn(self.fc)
self.m.StubOutWithMock(clients.OpenStackClients, "nova")
clients.OpenStackClients.nova(
mox.IgnoreArg()).MultipleTimes().AndReturn(self.fc)
stack_name = 'test_cs_create_flavor_err_stack'
(t, stack) = self._setup_test_stack(stack_name)

View File

@ -23,7 +23,7 @@ from heat.tests import utils
from heat.openstack.common import log as logging
from ..engine.plugins import cloud_dns
from ..engine.plugins import cloud_dns # noqa
logger = logging.getLogger(__name__)