Exemple #1
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_LI("Creating a database instance for tenant '%s'"),
                 tenant_id)
        LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
        LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        context.notification = notification.DBaaSInstanceCreate(context,
                                                                request=req)
        datastore_args = body['instance'].get('datastore', {})
        datastore, datastore_version = (
            datastore_models.get_datastore_version(**datastore_args))
        image_id = datastore_version.image_id
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)

        configuration = self._configuration_parse(context, body)
        databases = populate_validated_databases(
            body['instance'].get('databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if 'volume' in body['instance']:
            volume_info = body['instance']['volume']
            volume_size = int(volume_info['size'])
            volume_type = volume_info.get('type')
        else:
            volume_size = None
            volume_type = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        availability_zone = body['instance'].get('availability_zone')
        nics = body['instance'].get('nics')

        slave_of_id = body['instance'].get('replica_of',
                                           # also check for older name
                                           body['instance'].get('slave_of'))
        replica_count = body['instance'].get('replica_count')
        instance = models.Instance.create(context, name, flavor_id,
                                          image_id, databases, users,
                                          datastore, datastore_version,
                                          volume_size, backup_id,
                                          availability_zone, nics,
                                          configuration, slave_of_id,
                                          replica_count=replica_count,
                                          volume_type=volume_type)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #2
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_("Creating a database instance for tenant '%s'") % tenant_id)
        LOG.info(logging.mask_password(_("req : '%s'\n\n") % req))
        LOG.info(logging.mask_password(_("body : '%s'\n\n") % body))
        context = req.environ[wsgi.CONTEXT_KEY]
        datastore_args = body['instance'].get('datastore', {})
        datastore, datastore_version = (
            datastore_models.get_datastore_version(**datastore_args))
        image_id = datastore_version.image_id
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)

        configuration = self._configuration_parse(context, body)
        databases = populate_validated_databases(
            body['instance'].get('databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if 'volume' in body['instance']:
            volume_size = int(body['instance']['volume']['size'])
        else:
            volume_size = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        if 'availability_zone' in body['instance']:
            availability_zone = body['instance']['availability_zone']
        else:
            availability_zone = None

        if 'nics' in body['instance']:
            nics = body['instance']['nics']
        else:
            nics = None

        if 'slave_of' in body['instance']:
            slave_of_id = body['instance']['slave_of']
        else:
            slave_of_id = None

        instance = models.Instance.create(context, name, flavor_id,
                                          image_id, databases, users,
                                          datastore, datastore_version,
                                          volume_size, backup_id,
                                          availability_zone, nics,
                                          configuration, slave_of_id)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_("Creating a database instance 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]
        # Set the service type to mysql if its not in the request
        service_type = body["instance"].get("service_type") or CONF.service_type
        service = models.ServiceImage.find_by(service_name=service_type)
        image_id = service["image_id"]
        name = body["instance"]["name"]
        flavor_ref = body["instance"]["flavorRef"]
        flavor_id = utils.get_id_from_href(flavor_ref)
        databases = populate_validated_databases(body["instance"].get("databases", []))
        users = None
        try:
            users = populate_users(body["instance"].get("users", []))
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if "volume" in body["instance"]:
            volume_size = int(body["instance"]["volume"]["size"])
        else:
            volume_size = None

        if "restorePoint" in body["instance"]:
            backupRef = body["instance"]["restorePoint"]["backupRef"]
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        if "availability_zone" in body["instance"]:
            availability_zone = body["instance"]["availability_zone"]
        else:
            availability_zone = None

        instance = models.Instance.create(
            context,
            name,
            flavor_id,
            image_id,
            databases,
            users,
            service_type,
            volume_size,
            backup_id,
            availability_zone,
        )

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #4
0
        def _create_resources():
            # parse the ID from the Ref
            instance_id = utils.get_id_from_href(instance)

            # verify that the instance exists and can perform actions
            from trove.instance.models import Instance
            instance_model = Instance.load(context, instance_id)
            instance_model.validate_can_perform_action()

            cls.verify_swift_auth_token(context)

            try:
                db_info = DBBackup.create(name=name,
                                          description=description,
                                          tenant_id=context.tenant,
                                          state=BackupState.NEW,
                                          instance_id=instance_id,
                                          deleted=False)
            except exception.InvalidModelError as ex:
                LOG.exception("Unable to create Backup record:")
                raise exception.BackupCreationError(str(ex))

            backup_info = {'id': db_info.id,
                           'name': name,
                           'description': description,
                           'instance_id': instance_id,
                           'backup_type': db_info.backup_type,
                           'checksum': db_info.checksum,
                           }
            api.API(context).create_backup(backup_info, instance_id)
            return db_info
Exemple #5
0
    def _parse_grow_item(self, item):
        used_keys = []

        def _check_option(key, required=False, valid_values=None):
            if required and key not in item:
                raise exception.TroveError(
                    _("An instance with the options %(given)s is missing " "the MongoDB required option %(expected)s.")
                    % {"given": item.keys(), "expected": key}
                )
            value = item.get(key, None)
            if valid_values and value not in valid_values:
                raise exception.TroveError(
                    _("The value %(value)s for key %(key)s is invalid. " "Allowed values are %(valid)s.")
                    % {"value": value, "key": key, "valid": valid_values}
                )
            used_keys.append(key)
            return value

        flavor_id = utils.get_id_from_href(_check_option("flavorRef", required=True))
        volume_size = int(_check_option("volume", required=True)["size"])
        instance_type = _check_option("type", required=True, valid_values=["replica", "query_router"])
        name = _check_option("name")
        related_to = _check_option("related_to")

        unused_keys = list(set(item.keys()).difference(set(used_keys)))
        if unused_keys:
            raise exception.TroveError(_("The arguments %s are not supported by MongoDB.") % unused_keys)

        instance = {"flavor_id": flavor_id, "volume_size": volume_size, "instance_type": instance_type}
        if name:
            instance["name"] = name
        if related_to:
            instance["related_to"] = related_to
        return instance
 def action(self, context, req, action, param):
     if action == 'grow':
         context.notification = DBaaSClusterGrow(context, request=req)
         with StartNotification(context, cluster_id=self.id):
             instances = []
             for node in param:
                 instance = {
                     'flavor_id': utils.get_id_from_href(node['flavorRef'])
                 }
                 if 'name' in node:
                     instance['name'] = node['name']
                 if 'volume' in node:
                     instance['volume_size'] = int(node['volume']['size'])
                 if 'modules' in node:
                     instance['modules'] = node['modules']
                 if 'nics' in node:
                     instance['nics'] = node['nics']
                 if 'availability_zone' in node:
                     instance['availability_zone'] = (
                         node['availability_zone'])
                 instances.append(instance)
             return self.grow(instances)
     elif action == 'shrink':
         context.notification = DBaaSClusterShrink(context, request=req)
         with StartNotification(context, cluster_id=self.id):
             instance_ids = [instance['id'] for instance in param]
             return self.shrink(instance_ids)
     else:
         raise exception.BadRequest(_("Action %s not supported") % action)
Exemple #7
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_("Creating a database instance 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]
        # Set the service type to mysql if its not in the request
        service_type = (body['instance'].get('service_type') or
                        CONF.service_type)
        service = models.ServiceImage.find_by(service_name=service_type)
        image_id = service['image_id']
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)
        databases = populate_validated_databases(
            body['instance'].get('databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if 'volume' in body['instance']:
            volume_size = int(body['instance']['volume']['size'])
        else:
            volume_size = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        if 'availability_zone' in body['instance']:
            availability_zone = body['instance']['availability_zone']
        else:
            availability_zone = None

        instance = models.Instance.create(context, name, flavor_id,
                                          image_id, databases, users,
                                          service_type, volume_size,
                                          backup_id, availability_zone)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #8
0
 def _action_resize_flavor(self, context, req, instance, flavorRef):
     context.notification = notification.DBaaSInstanceResizeInstance(
         context, request=req)
     new_flavor_id = utils.get_id_from_href(flavorRef)
     with StartNotification(context, instance_id=instance.id,
                            new_flavor_id=new_flavor_id):
         instance.resize_flavor(new_flavor_id)
     return wsgi.Result(None, 202)
Exemple #9
0
 def _action_grow_cluster(self, cluster, body):
     nodes = body["grow"]
     instances = []
     for node in nodes:
         instance = {"flavor_id": utils.get_id_from_href(node["flavorRef"])}
         if "name" in node:
             instance["name"] = node["name"]
         if "volume" in node:
             instance["volume_size"] = int(node["volume"]["size"])
         instances.append(instance)
     return cluster.grow(instances)
Exemple #10
0
    def _parse_grow_item(self, item):
        used_keys = []

        def _check_option(key, required=False, valid_values=None,
                          flatten_value=False):
            if required and key not in item:
                raise exception.TroveError(
                    _('An instance with the options %(given)s is missing '
                      'the MongoDB required option %(expected)s.')
                    % {'given': item.keys(), 'expected': key}
                )
            value = item.get(key, None)
            if value and flatten_value and isinstance(value, list):
                value = ','.join(value)
            if valid_values and value not in valid_values:
                raise exception.TroveError(
                    _("The value '%(value)s' for key '%(key)s' is invalid. "
                      "Allowed values are %(valid)s.")
                    % {'value': value, 'key': key, 'valid': valid_values}
                )
            used_keys.append(key)
            return value

        flavor_id = utils.get_id_from_href(_check_option('flavorRef',
                                                         required=True))
        volume_size = int(_check_option('volume', required=True)['size'])
        instance_type = _check_option('type', required=True,
                                      valid_values=['replica',
                                                    'query_router'],
                                      flatten_value=True)
        name = _check_option('name')
        related_to = _check_option('related_to')
        nics = _check_option('nics')
        availability_zone = _check_option('availability_zone')

        unused_keys = list(set(item.keys()).difference(set(used_keys)))
        if unused_keys:
            raise exception.TroveError(
                _('The arguments %s are not supported by MongoDB.')
                % unused_keys
            )

        instance = {'flavor_id': flavor_id,
                    'volume_size': volume_size,
                    'instance_type': instance_type}
        if name:
            instance['name'] = name
        if related_to:
            instance['related_to'] = related_to
        if nics:
            instance['nics'] = nics
        if availability_zone:
            instance['availability_zone'] = availability_zone
        return instance
Exemple #11
0
 def _action_grow_cluster(self, cluster, body):
     nodes = body['grow']
     instances = []
     for node in nodes:
         instance = {
             'flavor_id': utils.get_id_from_href(node['flavorRef'])
         }
         if 'name' in node:
             instance['name'] = node['name']
         instances.append(instance)
     return cluster.grow(instances)
Exemple #12
0
    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))

        # TODO(saurabhs): add extended_properties to apischema
        extended_properties = body['cluster'].get('extended_properties', {})

        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 = volume_type = nics = availability_zone = None
            if 'volume' in node:
                volume_size = int(node['volume']['size'])
                volume_type = node['volume'].get('volume_type')
            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,
                              "volume_type": volume_type,
                              "nics": nics,
                              "availability_zone": availability_zone})

        context.notification = notification.DBaaSClusterCreate(context,
                                                               request=req)
        with StartNotification(context, name=name, datastore=datastore.name,
                               datastore_version=datastore_version.name):
            cluster = models.Cluster.create(context, name, datastore,
                                            datastore_version, instances,
                                            extended_properties)
        view = views.load_view(cluster, req=req, load_servers=False)
        return wsgi.Result(view.data(), 200)
Exemple #13
0
        def _create_resources():
            # parse the ID from the Ref
            instance_id = utils.get_id_from_href(instance)

            # verify that the instance exists and can perform actions
            from trove.instance.models import Instance
            instance_model = Instance.load(context, instance_id)
            instance_model.validate_can_perform_action()
            cls.validate_can_perform_action(
                instance_model, 'backup_create')
            cls.verify_swift_auth_token(context)
            if instance_model.cluster_id is not None:
                raise exception.ClusterInstanceOperationNotSupported()

            ds = instance_model.datastore
            ds_version = instance_model.datastore_version
            parent = None
            if parent_id:
                # Look up the parent info or fail early if not found or if
                # the user does not have access to the parent.
                _parent = cls.get_by_id(context, parent_id)
                parent = {
                    'location': _parent.location,
                    'checksum': _parent.checksum,
                }
            try:
                db_info = DBBackup.create(name=name,
                                          description=description,
                                          tenant_id=context.tenant,
                                          state=BackupState.NEW,
                                          instance_id=instance_id,
                                          parent_id=parent_id,
                                          datastore_version_id=ds_version.id,
                                          deleted=False)
            except exception.InvalidModelError as ex:
                LOG.exception(_("Unable to create backup record for "
                                "instance: %s"), instance_id)
                raise exception.BackupCreationError(str(ex))

            backup_info = {'id': db_info.id,
                           'name': name,
                           'description': description,
                           'instance_id': instance_id,
                           'backup_type': db_info.backup_type,
                           'checksum': db_info.checksum,
                           'parent': parent,
                           'datastore': ds.name,
                           'datastore_version': ds_version.name,
                           }
            api.API(context).create_backup(backup_info, instance_id)
            return db_info
Exemple #14
0
 def _action_grow_cluster(self, cluster, body):
     nodes = body['grow']
     instances = []
     for node in nodes:
         instance = {
             'flavor_id': utils.get_id_from_href(node['flavorRef'])
         }
         if 'name' in node:
             instance['name'] = node['name']
         if 'volume' in node:
             instance['volume_size'] = int(node['volume']['size'])
         if 'nics' in node:
             instance['nics'] = node['nics']
         if 'availability_zone' in node:
             instance['availability_zone'] = node['availability_zone']
         instances.append(instance)
     return cluster.grow(instances)
Exemple #15
0
    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)
Exemple #16
0
        def _create_resources():
            # parse the ID from the Ref
            instance_id = utils.get_id_from_href(instance)

            # verify that the instance exists and can perform actions
            from trove.instance.models import Instance

            instance_model = Instance.load(context, instance_id)
            instance_model.validate_can_perform_action()

            cls.verify_swift_auth_token(context)

            parent = None
            if parent_id:
                # Look up the parent info or fail early if not found or if
                # the user does not have access to the parent.
                _parent = cls.get_by_id(context, parent_id)
                parent = {"location": _parent.location, "checksum": _parent.checksum}
            try:
                db_info = DBBackup.create(
                    name=name,
                    description=description,
                    tenant_id=context.tenant,
                    state=BackupState.NEW,
                    instance_id=instance_id,
                    parent_id=parent_id,
                    deleted=False,
                )
            except exception.InvalidModelError as ex:
                LOG.exception("Unable to create Backup record:")
                raise exception.BackupCreationError(str(ex))

            backup_info = {
                "id": db_info.id,
                "name": name,
                "description": description,
                "instance_id": instance_id,
                "backup_type": db_info.backup_type,
                "checksum": db_info.checksum,
                "parent": parent,
            }
            api.API(context).create_backup(backup_info, instance_id)
            return db_info
Exemple #17
0
 def action(self, context, req, action, param):
     if action == "grow":
         context.notification = DBaaSClusterGrow(context, request=req)
         with StartNotification(context, cluster_id=self.id):
             instances = []
             for node in param:
                 instance = {"flavor_id": utils.get_id_from_href(node["flavorRef"])}
                 if "name" in node:
                     instance["name"] = node["name"]
                 if "volume" in node:
                     instance["volume_size"] = int(node["volume"]["size"])
                 instances.append(instance)
             return self.grow(instances)
     elif action == "shrink":
         context.notification = DBaaSClusterShrink(context, request=req)
         with StartNotification(context, cluster_id=self.id):
             instance_ids = [instance["id"] for instance in param]
             return self.shrink(instance_ids)
     else:
         raise exception.BadRequest(_("Action %s not supported") % action)
Exemple #18
0
    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'])
            if 'volume' in node:
                volume_size = int(node['volume']['size'])
            else:
                volume_size = None
            instances.append({"flavor_id": flavor_id,
                              "volume_size": volume_size})

        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)
Exemple #19
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_LI("Creating a database instance for tenant '%s'"),
                 tenant_id)
        LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
        LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        context.notification = notification.DBaaSInstanceCreate(context,
                                                                request=req)
        datastore_args = body['instance'].get('datastore', {})
        datastore, datastore_version = (
            datastore_models.get_datastore_version(**datastore_args))
        image_id = datastore_version.image_id
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)

        configuration = self._configuration_parse(context, body)
        databases = populate_validated_databases(
            body['instance'].get('databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if 'volume' in body['instance']:
            volume_info = body['instance']['volume']
            volume_size = int(volume_info['size'])
            volume_type = volume_info.get('type')
        else:
            volume_size = None
            volume_type = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        availability_zone = body['instance'].get('availability_zone')
        nics = body['instance'].get('nics')

        slave_of_id = body['instance'].get('replica_of',
                                           # also check for older name
                                           body['instance'].get('slave_of'))
        replica_count = body['instance'].get('replica_count')
        locality = body['instance'].get('locality')
        if locality:
            locality_domain = ['affinity', 'anti-affinity']
            locality_domain_msg = ("Invalid locality '%s'. "
                                   "Must be one of ['%s']" %
                                   (locality,
                                    "', '".join(locality_domain)))
            if locality not in locality_domain:
                raise exception.BadRequest(msg=locality_domain_msg)
            if slave_of_id:
                dupe_locality_msg = (
                    'Cannot specify locality when adding replicas to existing '
                    'master.')
                raise exception.BadRequest(msg=dupe_locality_msg)

        instance = models.Instance.create(context, name, flavor_id,
                                          image_id, databases, users,
                                          datastore, datastore_version,
                                          volume_size, backup_id,
                                          availability_zone, nics,
                                          configuration, slave_of_id,
                                          replica_count=replica_count,
                                          volume_type=volume_type,
                                          locality=locality)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #20
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_LI("Creating a database instance for tenant '%s'"),
                 tenant_id)
        LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
        LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        datastore_args = body['instance'].get('datastore', {})
        datastore, datastore_version = (datastore_models.get_datastore_version(
            **datastore_args))
        image_id = datastore_version.image_id
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)

        configuration = self._configuration_parse(context, body)
        databases = populate_validated_databases(body['instance'].get(
            'databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        if 'volume' in body['instance']:
            volume_size = int(body['instance']['volume']['size'])
        else:
            volume_size = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        availability_zone = body['instance'].get('availability_zone')
        nics = body['instance'].get('nics')

        slave_of_id = body['instance'].get(
            'replica_of',
            # also check for older name
            body['instance'].get('slave_of'))
        replica_count = body['instance'].get('replica_count')
        instance = models.Instance.create(context,
                                          name,
                                          flavor_id,
                                          image_id,
                                          databases,
                                          users,
                                          datastore,
                                          datastore_version,
                                          volume_size,
                                          backup_id,
                                          availability_zone,
                                          nics,
                                          configuration,
                                          slave_of_id,
                                          replica_count=replica_count)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #21
0
 def _action_resize_flavor(self, instance, flavorRef):
     new_flavor_id = utils.get_id_from_href(flavorRef)
     instance.resize_flavor(new_flavor_id)
     return wsgi.Result(None, 202)
Exemple #22
0
 def _configuration_parse(self, context, body):
     if 'configuration' in body['instance']:
         configuration_ref = body['instance']['configuration']
         if configuration_ref:
             configuration_id = utils.get_id_from_href(configuration_ref)
             return configuration_id
Exemple #23
0
    def create(self, req, body, tenant_id):
        # TODO(hub-cap): turn this into middleware
        LOG.info(_LI("Creating a database instance for tenant '%s'"),
                 tenant_id)
        LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
        LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        policy.authorize_on_tenant(context, 'instance:create')
        context.notification = notification.DBaaSInstanceCreate(context,
                                                                request=req)
        datastore_args = body['instance'].get('datastore', {})
        datastore, datastore_version = (datastore_models.get_datastore_version(
            **datastore_args))
        image_id = datastore_version.image_id
        name = body['instance']['name']
        flavor_ref = body['instance']['flavorRef']
        flavor_id = utils.get_id_from_href(flavor_ref)

        configuration = self._configuration_parse(context, body)
        databases = populate_validated_databases(body['instance'].get(
            'databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(msg=ve)

        # The following operations have their own API calls.
        # We need to make sure the same policies are enforced when
        # creating an instance.
        # i.e. if attaching configuration group to an existing instance is not
        # allowed, it should not be possible to create a new instance with the
        # group attached either
        if configuration:
            policy.authorize_on_tenant(context, 'configuration:update')
        if users:
            policy.authorize_on_tenant(context,
                                       'instance:extension:user:create')
        if databases:
            policy.authorize_on_tenant(context,
                                       'instance:extension:database:create')

        if 'volume' in body['instance']:
            volume_info = body['instance']['volume']
            volume_size = int(volume_info['size'])
            volume_type = volume_info.get('type')
        else:
            volume_size = None
            volume_type = None

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        availability_zone = body['instance'].get('availability_zone')
        nics = body['instance'].get('nics')

        slave_of_id = body['instance'].get(
            'replica_of',
            # also check for older name
            body['instance'].get('slave_of'))
        replica_count = body['instance'].get('replica_count')
        modules = body['instance'].get('modules')
        locality = body['instance'].get('locality')
        if locality:
            locality_domain = ['affinity', 'anti-affinity']
            locality_domain_msg = ("Invalid locality '%s'. "
                                   "Must be one of ['%s']" %
                                   (locality, "', '".join(locality_domain)))
            if locality not in locality_domain:
                raise exception.BadRequest(msg=locality_domain_msg)
            if slave_of_id:
                dupe_locality_msg = (
                    'Cannot specify locality when adding replicas to existing '
                    'master.')
                raise exception.BadRequest(msg=dupe_locality_msg)
        region_name = body['instance'].get('region_name', CONF.os_region_name)

        instance = models.Instance.create(context,
                                          name,
                                          flavor_id,
                                          image_id,
                                          databases,
                                          users,
                                          datastore,
                                          datastore_version,
                                          volume_size,
                                          backup_id,
                                          availability_zone,
                                          nics,
                                          configuration,
                                          slave_of_id,
                                          replica_count=replica_count,
                                          volume_type=volume_type,
                                          modules=modules,
                                          locality=locality,
                                          region_name=region_name)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #24
0
        def _create_resources():
            # parse the ID from the Ref
            instance_id = utils.get_id_from_href(instance)

            # verify that the instance exists and can perform actions
            from trove.instance.models import Instance
            instance_model = Instance.load(context, instance_id)
            instance_model.validate_can_perform_action()
            cls.validate_can_perform_action(instance_model, 'backup_create')
            cls.verify_swift_auth_token(context)
            if instance_model.cluster_id is not None:
                raise exception.ClusterInstanceOperationNotSupported()

            ds = instance_model.datastore
            ds_version = instance_model.datastore_version
            parent = None
            last_backup_id = None
            if parent_id:
                # Look up the parent info or fail early if not found or if
                # the user does not have access to the parent.
                _parent = cls.get_by_id(context, parent_id)
                parent = {
                    'location': _parent.location,
                    'checksum': _parent.checksum,
                }
            elif incremental:
                _parent = Backup.get_last_completed(context, instance_id)
                if _parent:
                    parent = {
                        'location': _parent.location,
                        'checksum': _parent.checksum
                    }
                    last_backup_id = _parent.id
            try:
                db_info = DBBackup.create(name=name,
                                          description=description,
                                          tenant_id=context.project_id,
                                          state=BackupState.NEW,
                                          instance_id=instance_id,
                                          parent_id=parent_id
                                          or last_backup_id,
                                          datastore_version_id=ds_version.id,
                                          deleted=False)
            except exception.InvalidModelError as ex:
                LOG.exception(
                    "Unable to create backup record for "
                    "instance: %s", instance_id)
                raise exception.BackupCreationError(str(ex))

            backup_info = {
                'id': db_info.id,
                'name': name,
                'description': description,
                'instance_id': instance_id,
                'backup_type': db_info.backup_type,
                'checksum': db_info.checksum,
                'parent': parent,
                'datastore': ds.name,
                'datastore_version': ds_version.name,
            }
            api.API(context).create_backup(backup_info, instance_id)
            return db_info
Exemple #25
0
    def create(cls,
               context,
               instance,
               name,
               description=None,
               parent_id=None,
               incremental=False,
               swift_container=None,
               restore_from=None):
        """
        create db record for Backup
        :param cls:
        :param context: tenant_id included
        :param instance:
        :param name:
        :param description:
        :param parent_id:
        :param incremental: flag to indicate incremental backup
                            based on previous backup
        :param swift_container: Swift container name.
        :param restore_from: A dict that contains backup information of another
                             region.
        :return:
        """
        backup_state = BackupState.NEW
        checksum = None
        instance_id = None
        parent = None
        last_backup_id = None
        location = None
        backup_type = constants.BACKUP_TYPE_FULL
        size = None

        if restore_from:
            # Check location and datastore version.
            LOG.info(f"Restoring backup, restore_from: {restore_from}")
            backup_state = BackupState.RESTORED

            ds_version_id = restore_from.get('local_datastore_version_id')
            ds_version = datastore_models.DatastoreVersion.load_by_uuid(
                ds_version_id)

            location = restore_from.get('remote_location')
            swift_client = clients.create_swift_client(context)
            try:
                obj_meta = swift.get_metadata(swift_client,
                                              location,
                                              extra_attrs=['etag'])
            except Exception:
                msg = f'Failed to restore backup from {location}'
                LOG.exception(msg)
                raise exception.BackupCreationError(msg)

            checksum = obj_meta['etag']
            if 'parent_location' in obj_meta:
                backup_type = constants.BACKUP_TYPE_INC

            size = restore_from['size']
        else:
            instance_id = utils.get_id_from_href(instance)
            # Import here to avoid circular imports.
            from trove.instance import models as inst_model
            instance_model = inst_model.Instance.load(context, instance_id)
            instance_model.validate_can_perform_action()
            if instance_model.cluster_id is not None:
                raise exception.ClusterInstanceOperationNotSupported()

            cls.validate_can_perform_action(instance_model, 'backup_create')

            cls.verify_swift_auth_token(context)

            ds = instance_model.datastore
            ds_version = instance_model.datastore_version

            if parent_id:
                # Look up the parent info or fail early if not found or if
                # the user does not have access to the parent.
                _parent = cls.get_by_id(context, parent_id)
                parent = {
                    'location': _parent.location,
                    'checksum': _parent.checksum,
                }
            elif incremental:
                _parent = Backup.get_last_completed(context, instance_id)
                if _parent:
                    parent = {
                        'location': _parent.location,
                        'checksum': _parent.checksum
                    }
                    last_backup_id = _parent.id

            if parent:
                backup_type = constants.BACKUP_TYPE_INC

        def _create_resources():
            try:
                db_info = DBBackup.create(name=name,
                                          description=description,
                                          tenant_id=context.project_id,
                                          state=backup_state,
                                          instance_id=instance_id,
                                          parent_id=parent_id
                                          or last_backup_id,
                                          datastore_version_id=ds_version.id,
                                          deleted=False,
                                          location=location,
                                          checksum=checksum,
                                          backup_type=backup_type,
                                          size=size)
            except exception.InvalidModelError as ex:
                LOG.exception(
                    "Unable to create backup record for "
                    "instance: %s", instance_id)
                raise exception.BackupCreationError(str(ex))

            if not restore_from:
                backup_info = {
                    'id': db_info.id,
                    'name': name,
                    'description': description,
                    'instance_id': instance_id,
                    'backup_type': db_info.backup_type,
                    'checksum': db_info.checksum,
                    'parent': parent,
                    'datastore': ds.name,
                    'datastore_version': ds_version.name,
                    'swift_container': swift_container
                }
                api.API(context).create_backup(backup_info, instance_id)
            else:
                context.notification.payload.update({'backup_id': db_info.id})

            return db_info

        return run_with_quotas(context.project_id, {'backups': 1},
                               _create_resources)
Exemple #26
0
    def action(self, context, req, action, param):
        if action == 'grow':
            context.notification = DBaaSClusterGrow(context, request=req)
            with StartNotification(context, cluster_id=self.id):
                instances = []
                for node in param:
                    instance = {
                        'flavor_id': utils.get_id_from_href(node['flavorRef'])
                    }
                    if 'name' in node:
                        instance['name'] = node['name']
                    if 'volume' in node:
                        instance['volume_size'] = int(node['volume']['size'])
                    if 'modules' in node:
                        instance['modules'] = node['modules']
                    if 'nics' in node:
                        instance['nics'] = node['nics']
                    if 'availability_zone' in node:
                        instance['availability_zone'] = (
                            node['availability_zone'])
                    if 'type' in node:
                        instance_type = node['type']
                        if isinstance(instance_type, six.string_types):
                            instance_type = instance_type.split(',')
                        instance['instance_type'] = instance_type
                    instances.append(instance)
                return self.grow(instances)
        elif action == 'shrink':
            context.notification = DBaaSClusterShrink(context, request=req)
            instance_ids = [instance['id'] for instance in param]
            with StartNotification(context,
                                   cluster_id=self.id,
                                   instance_ids=instance_ids):
                instance_ids = [instance['id'] for instance in param]
                return self.shrink(instance_ids)
        elif action == "reset-status":
            context.notification = DBaaSClusterResetStatus(context,
                                                           request=req)
            with StartNotification(context, cluster_id=self.id):
                return self.reset_status()

        elif action == 'restart':
            context.notification = DBaaSClusterRestart(context, request=req)
            with StartNotification(context, cluster_id=self.id):
                return self.restart()

        elif action == 'upgrade':
            context.notification = DBaaSClusterUpgrade(context, request=req)
            dv_id = param['datastore_version']
            dv = datastore_models.DatastoreVersion.load(self.datastore, dv_id)
            with StartNotification(context,
                                   cluster_id=self.id,
                                   datastore_version=dv.id):
                self.upgrade(dv)
            self.update_db(datastore_version_id=dv.id)

        elif action == 'configuration_attach':
            configuration_id = param['configuration_id']
            context.notification = DBaaSClusterAttachConfiguration(context,
                                                                   request=req)
            with StartNotification(context,
                                   cluster_id=self.id,
                                   configuration_id=configuration_id):
                return self.configuration_attach(configuration_id)

        elif action == 'configuration_detach':
            context.notification = DBaaSClusterDetachConfiguration(context,
                                                                   request=req)
            with StartNotification(context, cluster_id=self.id):
                return self.configuration_detach()

        else:
            raise exception.BadRequest(_("Action %s not supported") % action)
Exemple #27
0
    def create(self, req, body, tenant_id):
        LOG.info("Creating a database instance for tenant '%s'", tenant_id)
        LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
        LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
        context = req.environ[wsgi.CONTEXT_KEY]
        policy.authorize_on_tenant(context, 'instance:create')
        context.notification = notification.DBaaSInstanceCreate(context,
                                                                request=req)

        name = body['instance']['name']
        slave_of_id = body['instance'].get('replica_of')
        replica_count = body['instance'].get('replica_count')
        flavor_ref = body['instance'].get('flavorRef')
        datastore_args = body['instance'].get('datastore', {})
        volume_info = body['instance'].get('volume', {})
        availability_zone = body['instance'].get('availability_zone')
        nics = body['instance'].get('nics', [])
        locality = body['instance'].get('locality')
        region_name = body['instance'].get(
            'region_name', CONF.service_credentials.region_name)
        access = body['instance'].get('access', None)

        if slave_of_id:
            if flavor_ref:
                msg = 'Cannot specify flavor when creating replicas.'
                raise exception.BadRequest(message=msg)
            if datastore_args:
                msg = 'Cannot specify datastore when creating replicas.'
                raise exception.BadRequest(message=msg)
            if volume_info:
                msg = 'Cannot specify volume when creating replicas.'
                raise exception.BadRequest(message=msg)
            if locality:
                msg = 'Cannot specify locality when creating replicas.'
                raise exception.BadRequest(message=msg)
            backup_model.verify_swift_auth_token(context)
        else:
            if replica_count and replica_count > 1:
                msg = (f"Replica count only valid when creating replicas. "
                       f"Cannot create {replica_count} instances.")
                raise exception.BadRequest(message=msg)

        flavor_id = utils.get_id_from_href(flavor_ref)

        if volume_info:
            volume_size = int(volume_info.get('size'))
            volume_type = volume_info.get('type')
        else:
            volume_size = None
            volume_type = None

        if slave_of_id:
            try:
                replica_source = models.DBInstance.find_by(context,
                                                           id=slave_of_id,
                                                           deleted=False)
                flavor_id = replica_source.flavor_id
            except exception.ModelNotFoundError:
                LOG.error(f"Cannot create a replica of {slave_of_id} as that "
                          f"instance could not be found.")
                raise exception.NotFound(uuid=slave_of_id)
            if replica_source.slave_of_id:
                raise exception.Forbidden(
                    f"Cannot create a replica of a replica {slave_of_id}")

            datastore_version = ds_models.DatastoreVersion.load_by_uuid(
                replica_source.datastore_version_id)
            datastore = ds_models.Datastore.load(
                datastore_version.datastore_id)
        else:
            datastore, datastore_version = ds_models.get_datastore_version(
                **datastore_args)

        # If only image_tags is configured in the datastore version, get
        # the image ID using the tags.
        glance_client = clients.create_glance_client(context)
        image_id = common_glance.get_image_id(glance_client,
                                              datastore_version.image_id,
                                              datastore_version.image_tags)
        LOG.info(f'Using image {image_id} for creating instance')

        databases = populate_validated_databases(body['instance'].get(
            'databases', []))
        database_names = [database.get('_name', '') for database in databases]
        users = None
        try:
            users = populate_users(body['instance'].get('users', []),
                                   database_names)
        except ValueError as ve:
            raise exception.BadRequest(message=str(ve))
        if slave_of_id and (databases or users):
            raise exception.ReplicaCreateWithUsersDatabasesError()

        configuration = self._configuration_parse(context, body)
        modules = body['instance'].get('modules')

        # The following operations have their own API calls.
        # We need to make sure the same policies are enforced when
        # creating an instance.
        # i.e. if attaching configuration group to an existing instance is not
        # allowed, it should not be possible to create a new instance with the
        # group attached either
        if configuration:
            policy.authorize_on_tenant(context, 'instance:update')
        if modules:
            policy.authorize_on_tenant(context, 'instance:module_apply')
        if users:
            policy.authorize_on_tenant(context,
                                       'instance:extension:user:create')
        if databases:
            policy.authorize_on_tenant(context,
                                       'instance:extension:database:create')

        if 'restorePoint' in body['instance']:
            backupRef = body['instance']['restorePoint']['backupRef']
            backup_id = utils.get_id_from_href(backupRef)
        else:
            backup_id = None

        # Only 1 nic is allowed as defined in API jsonschema.
        # Use list just for backward compatibility.
        if len(nics) > 0:
            nic = nics[0]
            LOG.info('Checking user provided instance network %s', nic)
            if slave_of_id and nic.get('ip_address'):
                msg = "Cannot specify IP address when creating replicas."
                raise exception.BadRequest(message=msg)
            self._check_nic(context, nic)

        if locality:
            locality_domain = ['affinity', 'anti-affinity']
            locality_domain_msg = ("Invalid locality '%s'. "
                                   "Must be one of ['%s']" %
                                   (locality, "', '".join(locality_domain)))
            if locality not in locality_domain:
                raise exception.BadRequest(message=locality_domain_msg)

        instance = models.Instance.create(context,
                                          name,
                                          flavor_id,
                                          image_id,
                                          databases,
                                          users,
                                          datastore,
                                          datastore_version,
                                          volume_size,
                                          backup_id,
                                          availability_zone,
                                          nics,
                                          configuration,
                                          slave_of_id,
                                          replica_count=replica_count,
                                          volume_type=volume_type,
                                          modules=modules,
                                          locality=locality,
                                          region_name=region_name,
                                          access=access)

        view = views.InstanceDetailView(instance, req=req)
        return wsgi.Result(view.data(), 200)
Exemple #28
0
 def _configuration_parse(self, context, body):
     if 'configuration' in body['instance']:
         configuration_ref = body['instance']['configuration']
         if configuration_ref:
             configuration_id = utils.get_id_from_href(configuration_ref)
             return configuration_id
Exemple #29
0
    def create(self, req, body, tenant_id):
        LOG.debug(("Creating a Cluster for Tenant '%(tenant_id)s'\n"
                   "req : '%(req)s'\n\nbody : '%(body)s'\n\n") % {
                       "tenant_id": tenant_id,
                       "req": req,
                       "body": 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))

        # TODO(saurabhs): add extended_properties to apischema
        extended_properties = body['cluster'].get('extended_properties', {})

        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 = volume_type = nics = availability_zone = None
            modules = None
            if 'volume' in node:
                volume_size = int(node['volume']['size'])
                volume_type = node['volume'].get('volume_type')
            if 'nics' in node:
                nics = node['nics']
            if 'availability_zone' in node:
                availability_zone = node['availability_zone']
            if 'modules' in node:
                modules = node['modules']

            instances.append({
                "flavor_id": flavor_id,
                "volume_size": volume_size,
                "volume_type": volume_type,
                "nics": nics,
                "availability_zone": availability_zone,
                'region_name': node.get('region_name'),
                "modules": modules
            })

        locality = body['cluster'].get('locality')
        if locality:
            locality_domain = ['affinity', 'anti-affinity']
            locality_domain_msg = ("Invalid locality '%s'. "
                                   "Must be one of ['%s']" %
                                   (locality, "', '".join(locality_domain)))
            if locality not in locality_domain:
                raise exception.BadRequest(msg=locality_domain_msg)

        context.notification = notification.DBaaSClusterCreate(context,
                                                               request=req)
        with StartNotification(context,
                               name=name,
                               datastore=datastore.name,
                               datastore_version=datastore_version.name):
            cluster = models.Cluster.create(context, name, datastore,
                                            datastore_version, instances,
                                            extended_properties, locality)
        cluster.locality = locality
        view = views.load_view(cluster, req=req, load_servers=False)
        return wsgi.Result(view.data(), 200)