def setUp(self): super(DbTestCase, self).setUp() self.dbapi = dbapi.get_instance() global _DB_CACHE if not _DB_CACHE: _DB_CACHE = Database(sqla_api, migration, sql_connection=CONF.database.connection) self.useFixture(_DB_CACHE)
def create_test_node(**kw): """Create test node entry in DB and return Node DB object. Function to be used to create test Node objects in the database. :param kw: kwargs with overriding values for node's attributes. :returns: Test Node DB object. """ node = get_test_node(**kw) # Let DB generate ID if it isn't specified explicitly if "id" not in kw: del node["id"] dbapi = db_api.get_instance() return dbapi.create_node(node)
def create_test_container(**kw): """Create test container entry in DB and return Container DB object. Function to be used to create test Container objects in the database. :param kw: kwargs with overriding values for container's attributes. :returns: Test Container DB object. """ container = get_test_container(**kw) # Let DB generate ID if it isn't specified explicitly if "id" not in kw: del container["id"] dbapi = db_api.get_instance() return dbapi.create_container(container)
def create_test_x509keypair(**kw): """Create test x509keypair entry in DB and return X509KeyPair DB object. Function to be used to create test X509KeyPair objects in the database. :param kw: kwargs with overriding values for x509keypair's attributes. :returns: Test X509KeyPair DB object. """ x509keypair = get_test_x509keypair(**kw) # Let DB generate ID if it isn't specified explicitly if "id" not in kw: del x509keypair["id"] dbapi = db_api.get_instance() return dbapi.create_x509keypair(x509keypair)
def create_test_bay(**kw): """Create test bay entry in DB and return Bay DB object. Function to be used to create test Bay objects in the database. :param kw: kwargs with overriding values for bay's attributes. :returns: Test Bay DB object. """ bay = get_test_bay(**kw) # Let DB generate ID if it isn't specified explicitly if "id" not in kw: del bay["id"] dbapi = db_api.get_instance() return dbapi.create_bay(bay)
def create_test_quotas(**kw): """Create test quotas entry in DB and return quotas DB object. :param kw: kwargs with overriding values for quota attributes. :returns: Test quotas DB object. """ quotas = get_test_quotas(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del quotas['id'] dbapi = db_api.get_instance() return dbapi.create_quota(quotas)
def create_test_federation(**kw): """Create test federation entry in DB and return federation DB object. :param kw: kwargs with overriding values for federation attributes. :return: Test quotas DB object. """ federation = get_test_federation(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del federation['id'] dbapi = db_api.get_instance() return dbapi.create_federation(federation)
def create_test_nodegroup(**kw): """Create test nodegroup entry in DB and return federation DB object. :param kw: kwargs with overriding values for nodegroup attributes. :return: Test nodegroup DB object. """ nodegroup = get_test_nodegroup(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' in nodegroup: del nodegroup['id'] dbapi = db_api.get_instance() return dbapi.create_nodegroup(nodegroup)
def create_test_magnum_service(**kw): """Create test magnum_service entry in DB and return magnum_service DB object. :param kw: kwargs with overriding values for magnum_service's attributes. :returns: Test magnum_service DB object. """ magnum_service = get_test_magnum_service(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del magnum_service['id'] dbapi = db_api.get_instance() return dbapi.create_magnum_service(magnum_service)
def create_test_pod(**kw): """Create test pod entry in DB and return Pod DB object. Function to be used to create test Pod objects in the database. :param kw: kwargs with overriding values for pod's attributes. :returns: Test Pod DB object. """ pod = get_test_pod(**kw) # Let DB generate ID if it isn't specified explicitly if "id" not in kw: del pod["id"] dbapi = db_api.get_instance() return dbapi.create_pod(pod)
def create_test_service(**kw): """Create test service entry in DB and return Service DB object. Function to be used to create test Service objects in the database. :param kw: kwargs with overriding values for service's attributes. :returns: Test Service DB object. """ service = get_test_service(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del service['id'] dbapi = db_api.get_instance() return dbapi.create_service(service)
def create_test_quota(**kw): """Create test quota entry in DB and return Quota DB object. Function to be used to create test Quota objects in the database. :param kw: kwargs with overriding values for quota's attributes. :returns: Test Quota DB object. """ quota = get_test_quota(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del quota['id'] dbapi = db_api.get_instance() return dbapi.create_quota(quota)
def create_test_cluster_template(**kw): """Create and return test ClusterTemplate DB object. Function to be used to create test ClusterTemplate objects in the database. :param kw: kwargs with overriding values for ClusterTemplate's attributes. :returns: Test ClusterTemplate DB object. """ cluster_template = get_test_cluster_template(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del cluster_template['id'] dbapi = db_api.get_instance() return dbapi.create_cluster_template(cluster_template)
def setUp(self): cfg.CONF.set_override("enable_authentication", False) super(DbTestCase, self).setUp() self.dbapi = dbapi.get_instance() global _DB_CACHE if not _DB_CACHE: _DB_CACHE = Database(sqla_api, migration, sql_connection=CONF.database.connection, sqlite_db=CONF.database.sqlite_db, sqlite_clean_db='clean.sqlite') self.useFixture(_DB_CACHE)
def setUp(self): super(FunctionalTest, self).setUp() cfg.CONF.set_override("auth_version", "v2.0", group='keystone_authtoken') cfg.CONF.set_override("admin_user", "admin", group='keystone_authtoken') self.app = self._make_app() self.dbapi = dbapi.get_instance() def reset_pecan(): pecan.set_config({}, overwrite=True) self.addCleanup(reset_pecan)
def create_test_rc(**kw): """Create test rc entry in DB and return ReplicationController DB object. Function to be used to create test ReplicationController objects in the database. :param kw: kwargs with overriding values for replication controller's attributes. :returns: Test ReplicationController DB object. """ replication_controller = get_test_rc(**kw) # Let DB generate ID if it isn't specified explicitly if 'id' not in kw: del replication_controller['id'] dbapi = db_api.get_instance() return dbapi.create_rc(replication_controller)
def setUp(self): super(FunctionalTest, self).setUp() cfg.CONF.set_override("auth_version", "v2.0", group='keystone_authtoken') cfg.CONF.set_override("admin_user", "admin", group='keystone_authtoken') self.app = self._make_app() self.dbapi = dbapi.get_instance() def reset_pecan(): pecan.set_config({}, overwrite=True) self.addCleanup(reset_pecan) p = mock.patch('magnum.api.controllers.v1.Controller._check_version') self._check_version = p.start() self.addCleanup(p.stop)
class Service(base.MagnumObject): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': int, 'uuid': obj_utils.str_or_none, 'name': obj_utils.str_or_none, 'project_id': obj_utils.str_or_none, 'user_id': obj_utils.str_or_none, 'bay_uuid': obj_utils.str_or_none, 'labels': obj_utils.dict_or_none, 'selector': obj_utils.dict_or_none, 'ip': obj_utils.str_or_none, 'port': obj_utils.int_or_none, 'manifest_url': obj_utils.str_or_none, 'manifest': obj_utils.str_or_none, } @staticmethod def _from_db_object(service, db_service): """Converts a database entity to a formal object.""" for field in service.fields: # ignore manifest_url as it was used for create service if field == 'manifest_url': continue if field == 'manifest': continue service[field] = db_service[field] service.obj_reset_changes() return service @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ Service._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get_by_id(cls, context, service_id): """Find a service based on its integer id and return a Service object. :param service_id: the id of a service. :returns: a :class:`Service` object. """ db_service = cls.dbapi.get_service_by_id(context, service_id) service = Service._from_db_object(cls(context), db_service) return service @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a service based on uuid and return a :class:`Service` object. :param uuid: the uuid of a service. :param context: Security context :returns: a :class:`Service` object. """ db_service = cls.dbapi.get_service_by_uuid(context, uuid) service = Service._from_db_object(cls(context), db_service) return service @base.remotable_classmethod def get_by_name(cls, context, name): """Find a service based on service name and return a :class:`Service` object. :param name: the name of a service. :param context: Security context :returns: a :class:`Service` object. """ db_service = cls.dbapi.get_service_by_name(context, name) service = Service._from_db_object(cls(context), db_service) return service @base.remotable_classmethod def list_by_bay_uuid(cls, context, bay_uuid): """Return a list of :class:`Service` objects associated with a given bay. :param bay_uuid: the uuid of a bay. :param context: Security context :returns: a list of class:`Service` object. """ db_services = cls.dbapi.get_services_by_bay_uuid(bay_uuid) return Service._from_db_object_list(db_services, cls, context) @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Service objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`Service` object. """ db_services = cls.dbapi.get_service_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return Service._from_db_object_list(db_services, cls, context) @base.remotable def create(self, context=None): """Create a Service record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Service(context) """ values = self.obj_get_changes() db_service = self.dbapi.create_service(values) self._from_db_object(self, db_service) @base.remotable def destroy(self, context=None): """Delete the Service from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Service(context) """ self.dbapi.destroy_service(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Service. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Service(context) """ updates = self.obj_get_changes() self.dbapi.update_service(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Service. Loads a service with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded service column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Service(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if (hasattr(self, base.get_attrname(field)) and self[field] != current[field]): self[field] = current[field]
class NodeGroup(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(), 'name': fields.StringField(), 'cluster_id': fields.StringField(), 'project_id': fields.StringField(), 'docker_volume_size': fields.IntegerField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'flavor_id': fields.StringField(nullable=True), 'image_id': fields.StringField(nullable=True), 'node_addresses': fields.ListOfStringsField(nullable=True), 'node_count': fields.IntegerField(nullable=False, default=1), 'role': fields.StringField(), 'max_node_count': fields.IntegerField(nullable=True), 'min_node_count': fields.IntegerField(nullable=False, default=1), 'is_default': fields.BooleanField(default=False) } @staticmethod def _from_db_object(nodegroup, db_nodegroup): """Converts a database entity to a formal object.""" for field in nodegroup.fields: nodegroup[field] = db_nodegroup[field] nodegroup.obj_reset_changes() return nodegroup @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ NodeGroup._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, cluster_id, nodegroup_id): """Find a nodegroup based on its id or uuid and return a NodeGroup. :param cluster_id: the of id a cluster. :param nodegroup_id: the id of a nodegroup. :param context: Security context :returns: a :class:`NodeGroup` object. """ if strutils.is_int_like(nodegroup_id): return cls.get_by_id(context, cluster_id, nodegroup_id) elif uuidutils.is_uuid_like(nodegroup_id): return cls.get_by_uuid(context, cluster_id, nodegroup_id) else: return cls.get_by_name(context, cluster_id, nodegroup_id) @base.remotable_classmethod def get_by_id(cls, context, cluster, id_): """Find a nodegroup based on its integer id and return a NodeGroup. :param cluster: the id of a cluster. :param id_: the id of a nodegroup. :param context: Security context :returns: a :class:`NodeGroup` object. """ db_nodegroup = cls.dbapi.get_nodegroup_by_id(context, cluster, id_) nodegroup = NodeGroup._from_db_object(cls(context), db_nodegroup) return nodegroup @base.remotable_classmethod def get_by_uuid(cls, context, cluster, uuid): """Find a nodegroup based on uuid and return a :class:`NodeGroup`. :param cluster: the id of a cluster. :param uuid: the uuid of a nodegroup. :param context: Security context :returns: a :class:`NodeGroup` object. """ db_nodegroup = cls.dbapi.get_nodegroup_by_uuid(context, cluster, uuid) nodegroup = NodeGroup._from_db_object(cls(context), db_nodegroup) return nodegroup @base.remotable_classmethod def get_by_name(cls, context, cluster, name): """Find a nodegroup based on name and return a NodeGroup object. :param cluster: the id of a cluster. :param name: the logical name of a nodegroup. :param context: Security context :returns: a :class:`NodeGroup` object. """ db_nodegroup = cls.dbapi.get_nodegroup_by_name(context, cluster, name) nodegroup = NodeGroup._from_db_object(cls(context), db_nodegroup) return nodegroup @base.remotable_classmethod def get_count_all(cls, context, cluster_id): """Get count of nodegroups in cluster. :param context: The security context :param cluster_id: The uuid of the cluster :returns: Count of nodegroups in the cluster. """ return cls.dbapi.get_cluster_nodegroup_count(context, cluster_id) @base.remotable_classmethod def list(cls, context, cluster, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of NodeGroup objects. :param context: Security context. :param cluster: The cluster uuid or name :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'name', 'node_count', 'stack_id', 'node_addresses', 'status'(should be a status list). :returns: a list of :class:`NodeGroup` objects. """ db_nodegroups = cls.dbapi.list_cluster_nodegroups(context, cluster, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return NodeGroup._from_db_object_list(db_nodegroups, cls, context) @base.remotable def create(self, context=None): """Create a nodegroup record in the DB. :param context: Security context """ values = self.obj_get_changes() db_nodegroup = self.dbapi.create_nodegroup(values) self._from_db_object(self, db_nodegroup) @base.remotable def destroy(self, context=None): """Delete the NodeGroup from the DB. :param context: Security context. """ self.dbapi.destroy_nodegroup(self.cluster_id, self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this NodeGroup. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. """ updates = self.obj_get_changes() self.dbapi.update_nodegroup(self.cluster_id, self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this NodeGroup. Loads a NodeGroup with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded NogeGroup column by column, if there are any updates. :param context: Security context. """ current = self.__class__.get_by_uuid(self._context, cluster=self.cluster_id, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field] @base.remotable_classmethod def update_nodegroup(cls, context, cluster_id, nodegroup_id, values): """Updates a NodeGroup. :param context: Security context. :param cluster_id: :param nodegroup_id: :param values: a dictionary with the changed values """ current = cls.get(context, cluster_id, nodegroup_id) db_nodegroup = cls.dbapi.update_nodegroup(cluster_id, current.uuid, values) return NodeGroup._from_db_object(cls(context), db_nodegroup)
class Service(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.StringField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'bay_uuid': fields.StringField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'selector': fields.DictOfStringsField(nullable=True), 'ip': fields.StringField(nullable=True), 'ports': magnum_fields.ListOfDictsField(nullable=True), 'manifest_url': fields.StringField(nullable=True), 'manifest': fields.StringField(nullable=True), } @base.remotable_classmethod def get_by_uuid(cls, context, uuid, bay_uuid, k8s_api): """Find a service based on service uuid and UUID of the Bay :param context: Security context :param uuid: the uuid of a service. :param bay_uuid: the UUID of the Bay :param k8s_api: k8s API object :returns: a :class:`Service` object. """ try: resp = k8s_api.list_namespaced_service(namespace='default') except rest.ApiException as err: raise exception.KubernetesAPIFailed(err=err) if resp is None: raise exception.ServiceListNotFound(bay_uuid=bay_uuid) service = {} for service_entry in resp.items: if service_entry.metadata.uid == uuid: service['uuid'] = service_entry.metadata.uid service['name'] = service_entry.metadata.name service['project_id'] = context.project_id service['user_id'] = context.user_id service['bay_uuid'] = bay_uuid service['labels'] = ast.literal_eval( service_entry.metadata.labels) if not service_entry.spec.selector: service['selector'] = {} else: service['selector'] = ast.literal_eval( service_entry.spec.selector) service['ip'] = service_entry.spec.cluster_ip service_value = [] for p in service_entry.spec.ports: ports = p.to_dict() if not ports['name']: ports['name'] = 'k8s-service' service_value.append(ports) service['ports'] = service_value service_obj = Service(context, **service) return service_obj raise exception.ServiceNotFound(service=uuid) @base.remotable_classmethod def get_by_name(cls, context, name, bay_uuid, k8s_api): """Find a service based on service name and UUID of the Bay :param context: Security context :param name: the name of a service. :param bay_uuid: the UUID of the Bay :param k8s_api: k8s API object :returns: a :class:`Service` object. """ try: resp = k8s_api.read_namespaced_service(name=name, namespace='default') except rest.ApiException as err: raise exception.KubernetesAPIFailed(err=err) if resp is None: raise exception.ServiceNotFound(service=name) service = {} service['uuid'] = resp.metadata.uid service['name'] = resp.metadata.name service['project_id'] = context.project_id service['user_id'] = context.user_id service['bay_uuid'] = bay_uuid service['labels'] = ast.literal_eval(resp.metadata.labels) if not resp.spec.selector: service['selector'] = {} else: service['selector'] = ast.literal_eval(resp.spec.selector) service['ip'] = resp.spec.cluster_ip service_value = [] for p in resp.spec.ports: ports = p.to_dict() if not ports['name']: ports['name'] = 'k8s-service' service_value.append(ports) service['ports'] = service_value service_obj = Service(context, **service) return service_obj
class Pod(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Remove unused Pod object API 'list_by_bay_uuid' VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.StringField(nullable=True), 'name': fields.StringField(nullable=True), 'desc': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'bay_uuid': fields.StringField(nullable=True), 'images': fields.ListOfStringsField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'status': fields.StringField(nullable=True), 'manifest_url': fields.StringField(nullable=True), 'manifest': fields.StringField(nullable=True), 'host': fields.StringField(nullable=True), } @staticmethod def _from_db_object(pod, db_pod): """Converts a database entity to a formal object.""" for field in pod.fields: # ignore manifest_url as it was used for create pod if field == 'manifest_url': continue if field == 'manifest': continue pod[field] = db_pod[field] pod.obj_reset_changes() return pod @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Pod._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get_by_id(cls, context, pod_id): """Find a pod based on its integer id and return a Pod object. :param pod_id: the id of a pod. :returns: a :class:`Pod` object. """ db_pod = cls.dbapi.get_pod_by_id(context, pod_id) pod = Pod._from_db_object(cls(context), db_pod) return pod @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a pod based on uuid and return a :class:`Pod` object. :param uuid: the uuid of a pod. :param context: Security context :returns: a :class:`Pod` object. """ db_pod = cls.dbapi.get_pod_by_uuid(context, uuid) pod = Pod._from_db_object(cls(context), db_pod) return pod @base.remotable_classmethod def get_by_name(cls, context, name): """Find a pod based on pod name and return a :class:`Pod` object. :param name: the name of a pod. :param context: Security context :returns: a :class:`Pod` object. """ db_pod = cls.dbapi.get_pod_by_name(name) pod = Pod._from_db_object(cls(context), db_pod) return pod @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Pod objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`Pod` object. """ db_pods = cls.dbapi.get_pod_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return Pod._from_db_object_list(db_pods, cls, context) @base.remotable def create(self, context=None): """Create a Pod record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Pod(context) """ values = self.obj_get_changes() db_pod = self.dbapi.create_pod(values) self._from_db_object(self, db_pod) @base.remotable def destroy(self, context=None): """Delete the Pod from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Pod(context) """ self.dbapi.destroy_pod(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Pod. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Pod(context) """ updates = self.obj_get_changes() self.dbapi.update_pod(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Pod. Loads a pod with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded pod column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Pod(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if field == 'manifest_url': continue if field == 'manifest': continue if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class BayModel(base.MagnumObject): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': int, 'uuid': obj_utils.str_or_none, 'project_id': obj_utils.str_or_none, 'user_id': obj_utils.str_or_none, 'name': obj_utils.str_or_none, 'image_id': obj_utils.str_or_none, 'flavor_id': obj_utils.str_or_none, 'master_flavor_id': obj_utils.str_or_none, 'keypair_id': obj_utils.str_or_none, 'dns_nameserver': obj_utils.str_or_none, 'external_network_id': obj_utils.str_or_none, 'fixed_network': obj_utils.str_or_none, 'apiserver_port': obj_utils.int_or_none, 'docker_volume_size': obj_utils.int_or_none, 'ssh_authorized_key': obj_utils.str_or_none, } @staticmethod def _from_db_object(baymodel, db_baymodel): """Converts a database entity to a formal object.""" for field in baymodel.fields: baymodel[field] = db_baymodel[field] baymodel.obj_reset_changes() return baymodel @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ BayModel._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, baymodel_id): """Find a baymodel based on its id or uuid and return a BayModel object. :param baymodel_id: the id *or* uuid of a baymodel. :returns: a :class:`BayModel` object. """ if utils.is_int_like(baymodel_id): return cls.get_by_id(context, baymodel_id) elif utils.is_uuid_like(baymodel_id): return cls.get_by_uuid(context, baymodel_id) else: raise exception.InvalidIdentity(identity=baymodel_id) @base.remotable_classmethod def get_by_id(cls, context, baymodel_id): """Find a baymodel based on its integer id and return a BayModel object. :param baymodel_id: the id of a baymodel. :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_id(context, baymodel_id) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a baymodel based on uuid and return a :class:`BayModel` object. :param uuid: the uuid of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_uuid(context, uuid) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def get_by_name(cls, context, name): """Find a baymodel based on name and return a :class:`BayModel` object. :param name: the name of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_name(context, name) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of BayModel objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`BayModel` object. """ db_baymodels = cls.dbapi.get_baymodel_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return BayModel._from_db_object_list(db_baymodels, cls, context) @base.remotable def create(self, context=None): """Create a BayModel record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ values = self.obj_get_changes() db_baymodel = self.dbapi.create_baymodel(values) self._from_db_object(self, db_baymodel) @base.remotable def destroy(self, context=None): """Delete the BayModel from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ self.dbapi.destroy_baymodel(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this BayModel. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ updates = self.obj_get_changes() self.dbapi.update_baymodel(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this BayModel. Loads a baymodel with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded baymodel column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if (hasattr(self, base.get_attrname(field)) and self[field] != current[field]): self[field] = current[field]
class Cluster(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added 'bay_create_timeout' field # Version 1.2: Add 'registry_trust_id' field # Version 1.3: Added 'baymodel' field # Version 1.4: Added more types of status to bay's status field # Version 1.5: Rename 'registry_trust_id' to 'trust_id' # Add 'trustee_user_name', 'trustee_password', # 'trustee_user_id' field # Version 1.6: Add rollback support for Bay # Version 1.7: Added 'coe_version' and 'container_version' fields # Version 1.8: Rename 'baymodel' to 'cluster_template' # Version 1.9: Rename table name from 'bay' to 'cluster' # Rename 'baymodel_id' to 'cluster_template_id' # Rename 'bay_create_timeout' to 'create_timeout' # Version 1.10: Added 'keypair' field # Version 1.11: Added 'RESUME_FAILED' in status field # Version 1.12: Added 'get_stats' method # Version 1.13: Added get_count_all method # Version 1.14: Added 'docker_volume_size' field # Version 1.15: Added 'labels' field # Version 1.16: Added 'master_flavor_id' field # Version 1.17: Added 'flavor_id' field # Version 1.18: Added 'health_status' and 'health_status_reason' field VERSION = '1.18' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'cluster_template_id': fields.StringField(nullable=True), 'keypair': fields.StringField(nullable=True), 'docker_volume_size': fields.IntegerField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'master_flavor_id': fields.StringField(nullable=True), 'flavor_id': fields.StringField(nullable=True), 'stack_id': fields.StringField(nullable=True), 'status': m_fields.ClusterStatusField(nullable=True), 'status_reason': fields.StringField(nullable=True), 'health_status': m_fields.ClusterHealthStatusField(nullable=True), 'health_status_reason': fields.DictOfStringsField(nullable=True), 'create_timeout': fields.IntegerField(nullable=True), 'api_address': fields.StringField(nullable=True), 'node_addresses': fields.ListOfStringsField(nullable=True), 'node_count': fields.IntegerField(nullable=True), 'master_count': fields.IntegerField(nullable=True), 'discovery_url': fields.StringField(nullable=True), 'master_addresses': fields.ListOfStringsField(nullable=True), 'ca_cert_ref': fields.StringField(nullable=True), 'magnum_cert_ref': fields.StringField(nullable=True), 'cluster_template': fields.ObjectField('ClusterTemplate'), 'trust_id': fields.StringField(nullable=True), 'trustee_username': fields.StringField(nullable=True), 'trustee_password': fields.StringField(nullable=True), 'trustee_user_id': fields.StringField(nullable=True), 'coe_version': fields.StringField(nullable=True), 'container_version': fields.StringField(nullable=True) } @staticmethod def _from_db_object(cluster, db_cluster): """Converts a database entity to a formal object.""" for field in cluster.fields: if field != 'cluster_template': cluster[field] = db_cluster[field] # Note(eliqiao): The following line needs to be placed outside the # loop because there is a dependency from cluster_template to # cluster_template_id. The cluster_template_id must be populated # first in the loop before it can be used to find the cluster_template. cluster['cluster_template'] = ClusterTemplate.get_by_uuid( cluster._context, cluster.cluster_template_id) cluster.obj_reset_changes() return cluster @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ Cluster._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, cluster_id): """Find a cluster based on its id or uuid and return a Cluster object. :param cluster_id: the id *or* uuid of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ if strutils.is_int_like(cluster_id): return cls.get_by_id(context, cluster_id) elif uuidutils.is_uuid_like(cluster_id): return cls.get_by_uuid(context, cluster_id) else: raise exception.InvalidIdentity(identity=cluster_id) @base.remotable_classmethod def get_by_id(cls, context, cluster_id): """Find a cluster based on its integer id and return a Cluster object. :param cluster_id: the id of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_id(context, cluster_id) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a cluster based on uuid and return a :class:`Cluster` object. :param uuid: the uuid of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_uuid(context, uuid) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def get_count_all(cls, context, filters=None): """Get count of matching clusters. :param context: The security context :param filters: filter dict, can includes 'cluster_template_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list), 'master_count'. :returns: Count of matching clusters. """ return cls.dbapi.get_cluster_count_all(context, filters=filters) @base.remotable_classmethod def get_by_name(cls, context, name): """Find a cluster based on name and return a Cluster object. :param name: the logical name of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_name(context, name) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Cluster objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'cluster_template_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list), 'master_count'. :returns: a list of :class:`Cluster` object. """ db_clusters = cls.dbapi.get_cluster_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Cluster._from_db_object_list(db_clusters, cls, context) @base.remotable_classmethod def get_stats(cls, context, project_id=None): """Return a list of Cluster objects. :param context: Security context. :param project_id: project id """ return cls.dbapi.get_cluster_stats(project_id) @base.remotable def create(self, context=None): """Create a Cluster record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ values = self.obj_get_changes() db_cluster = self.dbapi.create_cluster(values) self._from_db_object(self, db_cluster) @base.remotable def destroy(self, context=None): """Delete the Cluster from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ self.dbapi.destroy_cluster(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Cluster. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ updates = self.obj_get_changes() self.dbapi.update_cluster(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Cluster. Loads a Cluster with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded Cluster column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
def setUp(self): super(SqlAlchemyCustomTypesTestCase, self).setUp() self.dbapi = dbapi.get_instance()
class MagnumService(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'host': fields.StringField(nullable=True), 'binary': fields.StringField(nullable=True), 'disabled': fields.BooleanField(), 'disabled_reason': fields.StringField(nullable=True), 'last_seen_up': fields.DateTimeField(nullable=True), 'forced_down': fields.BooleanField(), 'report_count': fields.IntegerField(), } @staticmethod def _from_db_object(magnum_service, db_magnum_service): """Converts a database entity to a formal object.""" for field in magnum_service.fields: magnum_service[field] = db_magnum_service[field] magnum_service.obj_reset_changes() return magnum_service @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ MagnumService._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get_by_host_and_binary(cls, context, host, binary): """Find a magnum_service based on its hostname and binary. :param host: The host on which the binary is running. :param binary: The name of the binary. :returns: a :class:`MagnumService` object. """ db_magnum_service = cls.dbapi.get_magnum_service_by_host_and_binary( context, host, binary) if db_magnum_service is None: return None magnum_service = MagnumService._from_db_object(cls(context), db_magnum_service) return magnum_service @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of MagnumService objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`MagnumService` object. """ db_magnum_services = cls.dbapi.get_magnum_service_list( context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return MagnumService._from_db_object_list(db_magnum_services, cls, context) @base.remotable def create(self, context=None): """Create a MagnumService record in the DB. :param context: Security context. """ values = self.obj_get_changes() db_magnum_service = self.dbapi.create_magnum_service(values) self._from_db_object(self, db_magnum_service) @base.remotable def destroy(self, context=None): """Delete the MagnumService from the DB. :param context: Security context. """ self.dbapi.destroy_magnum_service(self.id) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this MagnumService. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. """ updates = self.obj_get_changes() self.dbapi.update_magnum_service(self.id, updates) self.obj_reset_changes() @base.remotable def report_state_up(self, context=None): """Touching the magnum_service record to show aliveness. :param context: Security context. """ self.report_count += 1 self.save(context)
class BayModel(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Add 'registry_enabled' field # Version 1.2: Added 'network_driver' field # Version 1.3: Added 'labels' attribute # Version 1.4: Added 'insecure' attribute # Version 1.5: Changed type of 'coe' from StringField to BayTypeField # Version 1.6: Change 'insecure' to 'tls_disabled' # Version 1.7: Added 'public' field # Version 1.8: Added 'server_type' field # Version 1.9: Added 'volume_driver' field # Version 1.10: Removed 'ssh_authorized_key' field # Version 1.11: Added 'insecure_registry' field # Version 1.12: Added 'docker_storage_driver' field # Version 1.13: Added 'master_lb_enabled' field # Version 1.14: Added 'fixed_subnet' field # Version 1.15: Added 'floating_ip_enabled' field VERSION = '1.15' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'name': fields.StringField(nullable=True), 'image_id': fields.StringField(nullable=True), 'flavor_id': fields.StringField(nullable=True), 'master_flavor_id': fields.StringField(nullable=True), 'keypair_id': fields.StringField(nullable=True), 'dns_nameserver': fields.StringField(nullable=True), 'external_network_id': fields.StringField(nullable=True), 'fixed_network': fields.StringField(nullable=True), 'fixed_subnet': fields.StringField(nullable=True), 'network_driver': fields.StringField(nullable=True), 'volume_driver': fields.StringField(nullable=True), 'apiserver_port': fields.IntegerField(nullable=True), 'docker_volume_size': fields.IntegerField(nullable=True), 'docker_storage_driver': m_fields.DockerStorageDriverField(nullable=True), 'cluster_distro': fields.StringField(nullable=True), 'coe': m_fields.BayTypeField(nullable=True), 'http_proxy': fields.StringField(nullable=True), 'https_proxy': fields.StringField(nullable=True), 'no_proxy': fields.StringField(nullable=True), 'registry_enabled': fields.BooleanField(default=False), 'labels': fields.DictOfStringsField(nullable=True), 'tls_disabled': fields.BooleanField(default=False), 'public': fields.BooleanField(default=False), 'server_type': fields.StringField(nullable=True), 'insecure_registry': fields.StringField(nullable=True), 'master_lb_enabled': fields.BooleanField(default=False), 'floating_ip_enabled': fields.BooleanField(default=True), } @staticmethod def _from_db_object(baymodel, db_baymodel): """Converts a database entity to a formal object.""" for field in baymodel.fields: baymodel[field] = db_baymodel[field] baymodel.obj_reset_changes() return baymodel @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ BayModel._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, baymodel_id): """Find a baymodel based on its id or uuid and return a BayModel object. :param baymodel_id: the id *or* uuid of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ if strutils.is_int_like(baymodel_id): return cls.get_by_id(context, baymodel_id) elif uuidutils.is_uuid_like(baymodel_id): return cls.get_by_uuid(context, baymodel_id) else: raise exception.InvalidIdentity(identity=baymodel_id) @base.remotable_classmethod def get_by_id(cls, context, baymodel_id): """Find a baymodel based on its integer id and return a BayModel object. :param baymodel_id: the id of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_id(context, baymodel_id) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a baymodel based on uuid and return a :class:`BayModel` object. :param uuid: the uuid of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_uuid(context, uuid) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def get_by_name(cls, context, name): """Find a baymodel based on name and return a :class:`BayModel` object. :param name: the name of a baymodel. :param context: Security context :returns: a :class:`BayModel` object. """ db_baymodel = cls.dbapi.get_baymodel_by_name(context, name) baymodel = BayModel._from_db_object(cls(context), db_baymodel) return baymodel @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of BayModel objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`BayModel` object. """ db_baymodels = cls.dbapi.get_baymodel_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return BayModel._from_db_object_list(db_baymodels, cls, context) @base.remotable def create(self, context=None): """Create a BayModel record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ values = self.obj_get_changes() db_baymodel = self.dbapi.create_baymodel(values) self._from_db_object(self, db_baymodel) @base.remotable def destroy(self, context=None): """Delete the BayModel from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ self.dbapi.destroy_baymodel(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this BayModel. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ updates = self.obj_get_changes() self.dbapi.update_baymodel(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this BayModel. Loads a baymodel with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded baymodel column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BayModel(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class Container(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Add memory field VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.StringField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'image': fields.StringField(nullable=True), 'command': fields.StringField(nullable=True), 'bay_uuid': fields.StringField(nullable=True), 'status': m_fields.ContainerStatusField(nullable=True), 'memory': fields.StringField(nullable=True), } @staticmethod def _from_db_object(container, db_container): """Converts a database entity to a formal object.""" for field in container.fields: container[field] = db_container[field] container.obj_reset_changes() return container @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ Container._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get_by_id(cls, context, container_id): """Find a container based on its integer id and return a Container object. :param container_id: the id of a container. :returns: a :class:`Container` object. """ db_container = cls.dbapi.get_container_by_id(context, container_id) container = Container._from_db_object(cls(context), db_container) return container @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a container based on uuid and return a :class:`Container` object. :param uuid: the uuid of a container. :param context: Security context :returns: a :class:`Container` object. """ db_container = cls.dbapi.get_container_by_uuid(context, uuid) container = Container._from_db_object(cls(context), db_container) return container @base.remotable_classmethod def get_by_name(cls, context, name): """Find a bay based on name and return a Bay object. :param name: the logical name of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_container_by_name(context, name) bay = Container._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Container objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`Container` object. """ db_containers = cls.dbapi.get_container_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return Container._from_db_object_list(db_containers, cls, context) @base.remotable def create(self, context=None): """Create a Container record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Container(context) """ values = self.obj_get_changes() db_container = self.dbapi.create_container(values) self._from_db_object(self, db_container) @base.remotable def destroy(self, context=None): """Delete the Container from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Container(context) """ self.dbapi.destroy_container(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Container. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Container(context) """ updates = self.obj_get_changes() self.dbapi.update_container(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Container. Loads a container with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded container column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Container(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class Bay(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added 'bay_create_timeout' field # Version 1.2: Add 'registry_trust_id' field # Version 1.3: Added 'baymodel' field # Version 1.4: Added more types of status to bay's status field # Version 1.5: Reanme 'registry_trust_id' to 'trust_id' # Add 'trustee_user_name', 'trustee_password', # 'trustee_user_id' field VERSION = '1.5' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'baymodel_id': fields.StringField(nullable=True), 'stack_id': fields.StringField(nullable=True), 'status': m_fields.BayStatusField(nullable=True), 'status_reason': fields.StringField(nullable=True), 'bay_create_timeout': fields.IntegerField(nullable=True), 'api_address': fields.StringField(nullable=True), 'node_addresses': fields.ListOfStringsField(nullable=True), 'node_count': fields.IntegerField(nullable=True), 'master_count': fields.IntegerField(nullable=True), 'discovery_url': fields.StringField(nullable=True), 'master_addresses': fields.ListOfStringsField(nullable=True), 'ca_cert_ref': fields.StringField(nullable=True), 'magnum_cert_ref': fields.StringField(nullable=True), 'baymodel': fields.ObjectField('BayModel'), 'trust_id': fields.StringField(nullable=True), 'trustee_username': fields.StringField(nullable=True), 'trustee_password': fields.StringField(nullable=True), 'trustee_user_id': fields.StringField(nullable=True) } @staticmethod def _from_db_object(bay, db_bay): """Converts a database entity to a formal object.""" for field in bay.fields: if field != 'baymodel': bay[field] = db_bay[field] # Note(eliqiao): The following line needs to be placed outside the # loop because there is a dependency from baymodel to baymodel_id. # The baymodel_id must be populated first in the loop before it can be # used to find the baymodel. bay['baymodel'] = baymodel.BayModel.get_by_uuid( bay._context, bay.baymodel_id) bay.obj_reset_changes() return bay @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Bay._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get(cls, context, bay_id): """Find a bay based on its id or uuid and return a Bay object. :param bay_id: the id *or* uuid of a bay. :param context: Security context :returns: a :class:`Bay` object. """ if utils.is_int_like(bay_id): return cls.get_by_id(context, bay_id) elif utils.is_uuid_like(bay_id): return cls.get_by_uuid(context, bay_id) else: raise exception.InvalidIdentity(identity=bay_id) @base.remotable_classmethod def get_by_id(cls, context, bay_id): """Find a bay based on its integer id and return a Bay object. :param bay_id: the id of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_id(context, bay_id) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a bay based on uuid and return a :class:`Bay` object. :param uuid: the uuid of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_uuid(context, uuid) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def get_by_name(cls, context, name): """Find a bay based on name and return a Bay object. :param name: the logical name of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_name(context, name) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Bay objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'baymodel_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list), 'master_count'. :returns: a list of :class:`Bay` object. """ db_bays = cls.dbapi.get_bay_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Bay._from_db_object_list(db_bays, cls, context) @base.remotable def create(self, context=None): """Create a Bay record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ values = self.obj_get_changes() db_bay = self.dbapi.create_bay(values) self._from_db_object(self, db_bay) @base.remotable def destroy(self, context=None): """Delete the Bay from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ self.dbapi.destroy_bay(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Bay. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ updates = self.obj_get_changes() self.dbapi.update_bay(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Bay. Loads a bay with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded bay column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class Node(base.MagnumObject): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': int, 'uuid': obj_utils.str_or_none, 'project_id': obj_utils.str_or_none, 'user_id': obj_utils.str_or_none, 'type': obj_utils.str_or_none, 'image_id': obj_utils.str_or_none, 'ironic_node_id': obj_utils.str_or_none } @staticmethod def _from_db_object(node, db_node): """Converts a database entity to a formal object.""" for field in node.fields: node[field] = db_node[field] node.obj_reset_changes() return node @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Node._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get_by_id(cls, context, node_id): """Find a node based on its integer id and return a Node object. :param node_id: the id of a node. :returns: a :class:`Node` object. """ db_node = cls.dbapi.get_node_by_id(context, node_id) node = Node._from_db_object(cls(context), db_node) return node @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a node based on uuid and return a :class:`Node` object. :param uuid: the uuid of a node. :param context: Security context :returns: a :class:`Node` object. """ db_node = cls.dbapi.get_node_by_uuid(context, uuid) node = Node._from_db_object(cls(context), db_node) return node @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Node objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`Node` object. """ db_nodes = cls.dbapi.get_node_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return Node._from_db_object_list(db_nodes, cls, context) @base.remotable def create(self, context=None): """Create a Node record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Node(context) """ values = self.obj_get_changes() db_node = self.dbapi.create_node(values) self._from_db_object(self, db_node) @base.remotable def destroy(self, context=None): """Delete the Node from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Node(context) """ self.dbapi.destroy_node(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Node. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Node(context) """ updates = self.obj_get_changes() self.dbapi.update_node(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Node. Loads a node with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded node column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Node(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if (hasattr(self, base.get_attrname(field)) and self[field] != current[field]): self[field] = current[field]
class X509KeyPair(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added new method get_x509keypair_by_bay_uuid VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'bay_uuid': fields.StringField(nullable=True), 'ca_cert': fields.StringField(nullable=True), 'certificate': fields.StringField(nullable=True), 'private_key': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), } @staticmethod def _from_db_object(x509keypair, db_x509keypair): """Converts a database entity to a formal object.""" for field in x509keypair.fields: x509keypair[field] = db_x509keypair[field] x509keypair.obj_reset_changes() return x509keypair @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ X509KeyPair._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, x509keypair_id): """Find a X509KeyPair based on its id or uuid. Find X509KeyPair by id or uuid and return a X509KeyPair object. :param x509keypair_id: the id *or* uuid of a x509keypair. :returns: a :class:`X509KeyPair` object. """ if utils.is_int_like(x509keypair_id): return cls.get_by_id(context, x509keypair_id) elif utils.is_uuid_like(x509keypair_id): return cls.get_by_uuid(context, x509keypair_id) else: raise exception.InvalidIdentity(identity=x509keypair_id) @base.remotable_classmethod def get_by_id(cls, context, x509keypair_id): """Find a X509KeyPair based on its integer id. Find X509KeyPair by id and return a X509KeyPair object. :param x509keypair_id: the id of a x509keypair. :returns: a :class:`X509KeyPair` object. """ db_x509keypair = cls.dbapi.get_x509keypair_by_id( context, x509keypair_id) x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair) return x509keypair @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a x509keypair based on uuid and return a :class:`X509KeyPair` object. :param uuid: the uuid of a x509keypair. :param context: Security context :returns: a :class:`X509KeyPair` object. """ db_x509keypair = cls.dbapi.get_x509keypair_by_uuid(context, uuid) x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair) return x509keypair @base.remotable_classmethod def get_by_name(cls, context, name): """Find a x509keypair based on name and return a X509KeyPair object. :param name: the logical name of a x509keypair. :param context: Security context :returns: a :class:`X509KeyPair` object. """ db_x509keypair = cls.dbapi.get_x509keypair_by_name(context, name) x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair) return x509keypair @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of X509KeyPair objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can include 'x509keypairmodel_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list). :returns: a list of :class:`X509KeyPair` object. """ db_x509keypairs = cls.dbapi.get_x509keypair_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return X509KeyPair._from_db_object_list(db_x509keypairs, cls, context) @base.remotable def create(self, context=None): """Create a X509KeyPair record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: X509KeyPair(context) """ values = self.obj_get_changes() db_x509keypair = self.dbapi.create_x509keypair(values) self._from_db_object(self, db_x509keypair) @base.remotable def destroy(self, context=None): """Delete the X509KeyPair from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: X509KeyPair(context) """ self.dbapi.destroy_x509keypair(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this X509KeyPair. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: X509KeyPair(context) """ updates = self.obj_get_changes() self.dbapi.update_x509keypair(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this X509KeyPair. Loads a x509keypair with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded x509keypair column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: X509KeyPair(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field] @base.remotable_classmethod def get_by_bay_uuid(cls, context, bay_uuid): """Return a :class:`Cert` object associated with a given bay. :param bay_uuid: the uuid of a bay. :param context: Security context :returns: a class:`Cert` object. """ db_cert = cls.dbapi.get_x509keypair_by_bay_uuid(context, bay_uuid) return X509KeyPair._from_db_object(cls(context), db_cert)
class Bay(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'baymodel_id': fields.StringField(nullable=True), 'stack_id': fields.StringField(nullable=True), # One of CREATE_IN_PROGRESS|CREATE_FAILED|CREATED # UPDATE_IN_PROGRESS|UPDATE_FAILED|UPDATED # DELETE_IN_PROGRESS|DELETE_FAILED|DELETED 'status': fields.StringField(nullable=True), 'status_reason': fields.StringField(nullable=True), 'api_address': fields.StringField(nullable=True), 'node_addresses': fields.ListOfStringsField(nullable=True), 'node_count': fields.IntegerField(nullable=True), 'discovery_url': fields.StringField(nullable=True), } @staticmethod def _from_db_object(bay, db_bay): """Converts a database entity to a formal object.""" for field in bay.fields: bay[field] = db_bay[field] bay.obj_reset_changes() return bay @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Bay._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get(cls, context, bay_id): """Find a bay based on its id or uuid and return a Bay object. :param bay_id: the id *or* uuid of a bay. :returns: a :class:`Bay` object. """ if utils.is_int_like(bay_id): return cls.get_by_id(context, bay_id) elif utils.is_uuid_like(bay_id): return cls.get_by_uuid(context, bay_id) else: raise exception.InvalidIdentity(identity=bay_id) @base.remotable_classmethod def get_by_id(cls, context, bay_id): """Find a bay based on its integer id and return a Bay object. :param bay_id: the id of a bay. :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_id(context, bay_id) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a bay based on uuid and return a :class:`Bay` object. :param uuid: the uuid of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_uuid(context, uuid) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def get_by_name(cls, context, name): """Find a bay based on name and return a Bay object. :param name: the logical name of a bay. :param context: Security context :returns: a :class:`Bay` object. """ db_bay = cls.dbapi.get_bay_by_name(context, name) bay = Bay._from_db_object(cls(context), db_bay) return bay @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Bay objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'baymodel_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list). :returns: a list of :class:`Bay` object. """ db_bays = cls.dbapi.get_bay_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Bay._from_db_object_list(db_bays, cls, context) @base.remotable_classmethod def list_all(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return all tenants of Bay objects. :param context: Security context, should be an admin context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'baymodel_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list). :returns: a list of :class:`Bay` object. """ db_bays = cls.dbapi.get_bay_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters, opts={'get_all_tenants': True}) return Bay._from_db_object_list(db_bays, cls, context) @base.remotable def create(self, context=None): """Create a Bay record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ values = self.obj_get_changes() db_bay = self.dbapi.create_bay(values) self._from_db_object(self, db_bay) @base.remotable def destroy(self, context=None): """Delete the Bay from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ self.dbapi.destroy_bay(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Bay. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ updates = self.obj_get_changes() self.dbapi.update_bay(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Bay. Loads a bay with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded bay column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Bay(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class Quota(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'project_id': fields.StringField(nullable=False), 'resource': fields.StringField(nullable=False), 'hard_limit': fields.IntegerField(nullable=False), } @base.remotable_classmethod def get_quota_by_project_id_resource(cls, context, project_id, resource): """Find a quota based on its integer id and return a Quota object. :param project_id: the id of a project. :param resource: resource name. :param context: Security context :returns: a :class:`Quota` object. """ db_quota = cls.dbapi.get_quota_by_project_id_resource( project_id, resource) quota = Quota._from_db_object(cls(context), db_quota) return quota @staticmethod def _from_db_object(quota, db_quota): """Converts a database entity to a formal object.""" for field in quota.fields: setattr(quota, field, db_quota[field]) quota.obj_reset_changes() return quota @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Quota._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get_by_id(cls, context, quota_id): """Find a quota based on its integer id and return a Quota object. :param quota_id: the id of a quota. :param context: Security context :returns: a :class:`Quota` object. """ db_quota = cls.dbapi.get_quota_by_id(context, quota_id) quota = Quota._from_db_object(cls(context), db_quota) return quota @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Quota objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'project_id', 'resource'. :returns: a list of :class:`Quota` object. """ db_quotas = cls.dbapi.get_quota_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Quota._from_db_object_list(db_quotas, cls, context) @base.remotable_classmethod def quota_get_all_by_project_id(cls, context, project_id): """Find a quota based on project id. :param project_id: the project id. :param context: Security context :returns: a :class:`Quota` object. """ quotas = cls.dbapi.get_quota_by_project_id(context, project_id) return Quota._from_db_object_list(quotas, cls, context) @base.remotable def create(self, context=None): """Save a quota based on project id. :param context: security context. :returns: a :class:`Quota` object. """ values = self.obj_get_changes() db_quota = self.dbapi.create_quota(values) self._from_db_object(self, db_quota) @base.remotable def delete(self, context=None): """Delete the quota from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Quota(context) """ self.dbapi.delete_quota(self.project_id, self.resource) self.obj_reset_changes() @base.remotable_classmethod def update_quota(cls, context, project_id, quota): """Save a quota based on project id. :param quota: quota. :returns: a :class:`Quota` object. """ db_quota = cls.dbapi.update_quota(project_id, quota) return Quota._from_db_object(cls(context), db_quota)
class ReplicationController(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.StringField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'images': fields.ListOfStringsField(nullable=True), 'bay_uuid': fields.StringField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'replicas': fields.IntegerField(nullable=True), 'manifest_url': fields.StringField(nullable=True), 'manifest': fields.StringField(nullable=True), } @base.remotable_classmethod def get_by_uuid(cls, context, uuid, bay_uuid, k8s_api): """Return a :class:`ReplicationController` object based on uuid. :param context: Security context :param uuid: the uuid of a ReplicationController. :param bay_uuid: the UUID of the Bay. :returns: a :class:`ReplicationController` object. """ try: resp = k8s_api.list_namespaced_replication_controller( namespace='default') except rest.ApiException as err: raise exception.KubernetesAPIFailed(err=err) if resp is None: raise exception.ReplicationControllerListNotFound( bay_uuid=bay_uuid) rc = {} for entry in resp.items: if entry.metadata.uid == uuid: rc['uuid'] = entry.metadata.uid rc['name'] = entry.metadata.name rc['project_id'] = context.project_id rc['user_id'] = context.user_id rc['images'] = [ c.image for c in entry.spec.template.spec.containers] rc['bay_uuid'] = bay_uuid # Convert string to dictionary rc['labels'] = ast.literal_eval(entry.metadata.labels) rc['replicas'] = entry.status.replicas rc_obj = ReplicationController(context, **rc) return rc_obj raise exception.ReplicationControllerNotFound(rc=uuid) @base.remotable_classmethod def get_by_name(cls, context, name, bay_uuid, k8s_api): """Return a :class:`ReplicationController` object based on name. :param context: Security context :param name: the name of a ReplicationController. :param bay_uuid: the UUID of the Bay. :returns: a :class:`ReplicationController` object. """ try: resp = k8s_api.read_namespaced_replication_controller( name=name, namespace='default') except rest.ApiException as err: raise exception.KubernetesAPIFailed(err=err) if resp is None: raise exception.ReplicationControllerNotFound(rc=name) rc = {} rc['uuid'] = resp.metadata.uid rc['name'] = resp.metadata.name rc['project_id'] = context.project_id rc['user_id'] = context.user_id rc['images'] = [c.image for c in resp.spec.template.spec.containers] rc['bay_uuid'] = bay_uuid # Convert string to dictionary rc['labels'] = ast.literal_eval(resp.metadata.labels) rc['replicas'] = resp.status.replicas rc_obj = ReplicationController(context, **rc) return rc_obj
class Federation(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): """Represents a Federation object. Version 1.0: Initial Version """ VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'hostcluster_id': fields.StringField(nullable=True), 'member_ids': fields.ListOfStringsField(nullable=True), 'status': m_fields.FederationStatusField(nullable=True), 'status_reason': fields.StringField(nullable=True), 'properties': fields.DictOfStringsField(nullable=True) } @staticmethod def _from_db_object(federation, db_federation): """Converts a database entity to a formal object.""" for field in federation.fields: federation[field] = db_federation[field] federation.obj_reset_changes() return federation @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [Federation._from_db_object(cls(context), obj) for obj in db_objects] @base.remotable_classmethod def get(cls, context, federation_id): """Find a federation based on its id or uuid and return it. :param federation_id: the id *or* uuid of a federation. :param context: Security context :returns: a :class:`Federation` object. """ if strutils.is_int_like(federation_id): return cls.get_by_id(context, federation_id) elif uuidutils.is_uuid_like(federation_id): return cls.get_by_uuid(context, federation_id) else: raise exception.InvalidIdentity(identity=federation_id) @base.remotable_classmethod def get_by_id(cls, context, federation_id): """Find a federation based on its integer id and return it. :param federation_id: the id of a federation. :param context: Security context :returns: a :class:`Federation` object. """ db_federation = cls.dbapi.get_federation_by_id(context, federation_id) federation = Federation._from_db_object(cls(context), db_federation) return federation @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a federation based on uuid and return it. :param uuid: the uuid of a federation. :param context: Security context :returns: a :class:`Federation` object. """ db_federation = cls.dbapi.get_federation_by_uuid(context, uuid) federation = Federation._from_db_object(cls(context), db_federation) return federation @base.remotable_classmethod def get_count_all(cls, context, filters=None): """Get count of matching federation. :param context: The security context :param filters: filter dict, can includes 'name', 'project_id', 'hostcluster_id', 'member_ids', 'status' (should be a status list). :returns: Count of matching federation. """ return cls.dbapi.get_federation_count_all(context, filters=filters) @base.remotable_classmethod def get_by_name(cls, context, name): """Find a federation based on name and return a Federation object. :param name: the logical name of a federation. :param context: Security context :returns: a :class:`Federation` object. """ db_federation = cls.dbapi.get_federation_by_name(context, name) federation = Federation._from_db_object(cls(context), db_federation) return federation @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Federation objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'name', 'project_id', 'hostcluster_id', 'member_ids', 'status' (should be a status list). :returns: a list of :class:`Federation` object. """ db_federation = cls.dbapi.get_federation_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Federation._from_db_object_list(db_federation, cls, context) @base.remotable def create(self, context=None): """Create a Federation record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Federation(context) """ values = self.obj_get_changes() db_federation = self.dbapi.create_federation(values) self._from_db_object(self, db_federation) @base.remotable def destroy(self, context=None): """Delete the Federation from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Federation(context) """ self.dbapi.destroy_federation(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Federation. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Federation(context) """ updates = self.obj_get_changes() self.dbapi.update_federation(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Load updates for this Federation. Loads a Federation with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded Federation column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Federation(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field]
class Cluster(base.MagnumPersistentObject, base.MagnumObject, base.MagnumObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added 'bay_create_timeout' field # Version 1.2: Add 'registry_trust_id' field # Version 1.3: Added 'baymodel' field # Version 1.4: Added more types of status to bay's status field # Version 1.5: Rename 'registry_trust_id' to 'trust_id' # Add 'trustee_user_name', 'trustee_password', # 'trustee_user_id' field # Version 1.6: Add rollback support for Bay # Version 1.7: Added 'coe_version' and 'container_version' fields # Version 1.8: Rename 'baymodel' to 'cluster_template' # Version 1.9: Rename table name from 'bay' to 'cluster' # Rename 'baymodel_id' to 'cluster_template_id' # Rename 'bay_create_timeout' to 'create_timeout' # Version 1.10: Added 'keypair' field # Version 1.11: Added 'RESUME_FAILED' in status field # Version 1.12: Added 'get_stats' method # Version 1.13: Added get_count_all method # Version 1.14: Added 'docker_volume_size' field # Version 1.15: Added 'labels' field # Version 1.16: Added 'master_flavor_id' field # Version 1.17: Added 'flavor_id' field # Version 1.18: Added 'health_status' and 'health_status_reason' field # Version 1.19: Added nodegroups, default_ng_worker, default_ng_master # Version 1.20: Fields node_count, master_count, node_addresses, # master_addresses are now properties. # Version 1.21 Added fixed_network, fixed_subnet, floating_ip_enabled # Version 1.22 Added master_lb_enabled # Version 1.23 Added etcd_ca_cert_ref and front_proxy_ca_cert_ref VERSION = '1.23' dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(nullable=True), 'name': fields.StringField(nullable=True), 'project_id': fields.StringField(nullable=True), 'user_id': fields.StringField(nullable=True), 'cluster_template_id': fields.StringField(nullable=True), 'keypair': fields.StringField(nullable=True), 'docker_volume_size': fields.IntegerField(nullable=True), 'labels': fields.DictOfStringsField(nullable=True), 'master_flavor_id': fields.StringField(nullable=True), 'flavor_id': fields.StringField(nullable=True), 'stack_id': fields.StringField(nullable=True), 'status': m_fields.ClusterStatusField(nullable=True), 'status_reason': fields.StringField(nullable=True), 'health_status': m_fields.ClusterHealthStatusField(nullable=True), 'health_status_reason': fields.DictOfStringsField(nullable=True), 'create_timeout': fields.IntegerField(nullable=True), 'api_address': fields.StringField(nullable=True), 'discovery_url': fields.StringField(nullable=True), 'ca_cert_ref': fields.StringField(nullable=True), 'magnum_cert_ref': fields.StringField(nullable=True), 'etcd_ca_cert_ref': fields.StringField(nullable=True), 'front_proxy_ca_cert_ref': fields.StringField(nullable=True), 'cluster_template': fields.ObjectField('ClusterTemplate'), 'trust_id': fields.StringField(nullable=True), 'trustee_username': fields.StringField(nullable=True), 'trustee_password': fields.StringField(nullable=True), 'trustee_user_id': fields.StringField(nullable=True), 'coe_version': fields.StringField(nullable=True), 'container_version': fields.StringField(nullable=True), 'fixed_network': fields.StringField(nullable=True), 'fixed_subnet': fields.StringField(nullable=True), 'floating_ip_enabled': fields.BooleanField(default=True), 'master_lb_enabled': fields.BooleanField(default=False), } @staticmethod def _from_db_object(cluster, db_cluster): """Converts a database entity to a formal object.""" for field in cluster.fields: # cluster_template will be loaded lazily when it is needed # by obj_load_attr. if field != 'cluster_template': cluster[field] = db_cluster[field] cluster.obj_reset_changes() return cluster @property def nodegroups(self): # Returns all nodegroups that belong to the cluster. return NodeGroup.list(self._context, self.uuid) @property def default_ng_worker(self): # Assume that every cluster will have only one default # non-master nodegroup. We don't want to limit the roles # so each nodegroup that does not have a master role is # considered as a worker/minion nodegroup. filters = {'is_default': True} default_ngs = NodeGroup.list(self._context, self.uuid, filters=filters) return [n for n in default_ngs if n.role != 'master'][0] @property def default_ng_master(self): # Assume that every cluster will have only one default # master nodegroup. filters = {'role': 'master', 'is_default': True} return NodeGroup.list(self._context, self.uuid, filters=filters)[0] @property def node_count(self): return sum(n.node_count for n in self.nodegroups if n.role != 'master') @property def master_count(self): return sum(n.node_count for n in self.nodegroups if n.role == 'master') @property def node_addresses(self): node_addresses = [] for ng in self.nodegroups: if ng.role != 'master': node_addresses += ng.node_addresses return node_addresses @property def master_addresses(self): master_addresses = [] for ng in self.nodegroups: if ng.role == 'master': master_addresses += ng.node_addresses return master_addresses @staticmethod def _from_db_object_list(db_objects, cls, context): """Converts a list of database entities to a list of formal objects.""" return [ Cluster._from_db_object(cls(context), obj) for obj in db_objects ] @base.remotable_classmethod def get(cls, context, cluster_id): """Find a cluster based on its id or uuid and return a Cluster object. :param cluster_id: the id *or* uuid of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ if strutils.is_int_like(cluster_id): return cls.get_by_id(context, cluster_id) elif uuidutils.is_uuid_like(cluster_id): return cls.get_by_uuid(context, cluster_id) else: raise exception.InvalidIdentity(identity=cluster_id) @base.remotable_classmethod def get_by_id(cls, context, cluster_id): """Find a cluster based on its integer id and return a Cluster object. :param cluster_id: the id of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_id(context, cluster_id) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def get_by_uuid(cls, context, uuid): """Find a cluster based on uuid and return a :class:`Cluster` object. :param uuid: the uuid of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_uuid(context, uuid) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def get_count_all(cls, context, filters=None): """Get count of matching clusters. :param context: The security context :param filters: filter dict, can includes 'cluster_template_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list), 'master_count'. :returns: Count of matching clusters. """ return cls.dbapi.get_cluster_count_all(context, filters=filters) @base.remotable_classmethod def get_by_name(cls, context, name): """Find a cluster based on name and return a Cluster object. :param name: the logical name of a cluster. :param context: Security context :returns: a :class:`Cluster` object. """ db_cluster = cls.dbapi.get_cluster_by_name(context, name) cluster = Cluster._from_db_object(cls(context), db_cluster) return cluster @base.remotable_classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None, filters=None): """Return a list of Cluster objects. :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :param filters: filter dict, can includes 'cluster_template_id', 'name', 'node_count', 'stack_id', 'api_address', 'node_addresses', 'project_id', 'user_id', 'status'(should be a status list), 'master_count'. :returns: a list of :class:`Cluster` object. """ db_clusters = cls.dbapi.get_cluster_list(context, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir, filters=filters) return Cluster._from_db_object_list(db_clusters, cls, context) @base.remotable_classmethod def get_stats(cls, context, project_id=None): """Return a list of Cluster objects. :param context: Security context. :param project_id: project id """ return cls.dbapi.get_cluster_stats(project_id) @base.remotable def create(self, context=None): """Create a Cluster record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ values = self.obj_get_changes() db_cluster = self.dbapi.create_cluster(values) self._from_db_object(self, db_cluster) @base.remotable def destroy(self, context=None): """Delete the Cluster from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ self.dbapi.destroy_cluster(self.uuid) self.obj_reset_changes() @base.remotable def save(self, context=None): """Save updates to this Cluster. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ updates = self.obj_get_changes() self.dbapi.update_cluster(self.uuid, updates) self.obj_reset_changes() @base.remotable def refresh(self, context=None): """Loads updates for this Cluster. Loads a Cluster with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded Cluster column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Cluster(context) """ current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) for field in self.fields: if self.obj_attr_is_set(field) and self[field] != current[field]: self[field] = current[field] def obj_load_attr(self, attrname): if attrname not in LAZY_LOADED_ATTRS: raise exception.ObjectError(action='obj_load_attr', obj_name=self.name, obj_id=self.uuid, reason='unable to lazy-load %s' % attrname) self['cluster_template'] = ClusterTemplate.get_by_uuid( self._context, self.cluster_template_id) self.obj_reset_changes(['cluster_template']) def as_dict(self): dict_ = super(Cluster, self).as_dict() # Update the dict with the attributes coming form # the cluster's nodegroups. dict_.update({ 'node_count': self.node_count, 'master_count': self.master_count, 'node_addresses': self.node_addresses, 'master_addresses': self.master_addresses }) return dict_