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)
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)
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
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)
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)
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)
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)
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
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)
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)
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
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)
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)
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
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)
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)
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)
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)
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)
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
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)
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
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)
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)
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)
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)