# Copyright 2014 eBay Software Foundation # 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. from oslo_config.cfg import NoSuchOptError from trove.cluster import models from trove.cluster import views from trove.common import apischema from trove.common import cfg from trove.common import exception from trove.common.i18n import _ from trove.common import pagination from trove.common.strategies.cluster import strategy from trove.common import utils from trove.common import wsgi from trove.datastore import models as datastore_models from trove.openstack.common import log as logging CONF = cfg.CONF LOG = logging.getLogger(__name__) class ClusterController(wsgi.Controller): """Controller for cluster functionality.""" schemas = apischema.cluster.copy() @classmethod def get_action_schema(cls, body, action_schema): action_type = body.keys()[0] return action_schema.get(action_type, {}) @classmethod def get_schema(cls, action, body): action_schema = super(ClusterController, cls).get_schema(action, body) if action == 'action': action_schema = cls.get_action_schema(body, action_schema) return action_schema def action(self, req, body, tenant_id, id): LOG.debug("Committing Action Against Cluster for " "Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("id : '%s'\n\n") % id) if not body: raise exception.BadRequest(_("Invalid request body.")) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) manager = cluster.datastore_version.manager api_strategy = strategy.load_api_strategy(manager) _actions = api_strategy.cluster_controller_actions selected_action = None for key in body: if key in _actions: selected_action = _actions[key] break else: message = _("No action '%(action)s' supplied " "by strategy for manager '%(manager)s'") % ( {'action': key, 'manager': manager}) raise exception.TroveError(message) return selected_action(cluster, body) def show(self, req, tenant_id, id): """Return a single cluster.""" LOG.debug("Showing a Cluster for Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("id : '%s'\n\n") % id) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) return wsgi.Result(views.load_view(cluster, req=req).data(), 200) def show_instance(self, req, tenant_id, cluster_id, instance_id): """Return a single instance belonging to a cluster.""" LOG.debug("Showing an Instance in a Cluster for Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("cluster_id : '%s'\n\n") % cluster_id) LOG.info(_("instance_id : '%s'\n\n") % instance_id) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, cluster_id) instance = models.Cluster.load_instance(context, cluster.id, instance_id) return wsgi.Result(views.ClusterInstanceDetailView( instance, req=req).data(), 200) def delete(self, req, tenant_id, id): """Delete a cluster.""" LOG.debug("Deleting a Cluster for Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("id : '%s'\n\n") % id) context = req.environ[wsgi.CONTEXT_KEY] cluster = models.Cluster.load(context, id) cluster.delete() return wsgi.Result(None, 202) def index(self, req, tenant_id): """Return a list of clusters.""" LOG.debug("Showing a list of clusters for Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) context = req.environ[wsgi.CONTEXT_KEY] if not context.is_admin and context.tenant != tenant_id: raise exception.TroveOperationAuthError(tenant_id=context.tenant) # load all clusters and instances for the tenant clusters, marker = models.Cluster.load_all(context, tenant_id) view = views.ClustersView(clusters, req=req) paged = pagination.SimplePaginatedDataView(req.url, 'clusters', view, marker) return wsgi.Result(paged.data(), 200) def create(self, req, body, tenant_id): LOG.debug("Creating a Cluster for Tenant '%s'" % tenant_id) LOG.info(_("req : '%s'\n\n") % req) LOG.info(_("body : '%s'\n\n") % body) context = req.environ[wsgi.CONTEXT_KEY] name = body['cluster']['name'] datastore_args = body['cluster'].get('datastore', {}) datastore, datastore_version = ( datastore_models.get_datastore_version(**datastore_args)) try: clusters_enabled = (CONF.get(datastore_version.manager) .get('cluster_support')) except NoSuchOptError: clusters_enabled = False if not clusters_enabled: raise exception.ClusterDatastoreNotSupported( datastore=datastore.name, datastore_version=datastore_version.name) nodes = body['cluster']['instances'] instances = [] for node in nodes: flavor_id = utils.get_id_from_href(node['flavorRef']) volume_size = nics = availability_zone = None if 'volume' in node: volume_size = int(node['volume']['size']) if 'nics' in node: nics = node['nics'] if 'availability_zone' in node: availability_zone = node['availability_zone'] instances.append({"flavor_id": flavor_id, "volume_size": volume_size, "nics": nics, "availability_zone": availability_zone}) cluster = models.Cluster.create(context, name, datastore, datastore_version, instances) view = views.load_view(cluster, req=req, load_servers=False) return wsgi.Result(view.data(), 200)