diff --git a/sysinv/sysinv/centos/build_srpm.data b/sysinv/sysinv/centos/build_srpm.data index f3c2c4e149..7792898404 100644 --- a/sysinv/sysinv/centos/build_srpm.data +++ b/sysinv/sysinv/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="sysinv" -TIS_PATCH_VER=325 +TIS_PATCH_VER=326 diff --git a/sysinv/sysinv/sysinv/sysinv/agent/manager.py b/sysinv/sysinv/sysinv/sysinv/agent/manager.py index 7fe3655a15..0bc30a4968 100644 --- a/sysinv/sysinv/sysinv/sysinv/agent/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/agent/manager.py @@ -17,7 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # @@ -146,12 +146,14 @@ class AgentManager(service.PeriodicService): self._iconfig_read_config_reported = None self._ihost_personality = None self._ihost_uuid = "" + self._ihost_rootfs_device = "" self._agent_throttle = 0 self._mgmt_ip = None self._prev_disk = None self._prev_partition = None self._prev_lvg = None self._prev_pv = None + self._prev_fs = None self._subfunctions = None self._subfunctions_configured = False self._notify_subfunctions_alarm_clear = False @@ -745,6 +747,7 @@ class AgentManager(service.PeriodicService): self._ihost_uuid = ihost['uuid'] self._ihost_personality = ihost['personality'] self._mgmt_ip = ihost['mgmt_ip'] + self._ihost_rootfs_device = ihost['rootfs_device'] if os.path.isfile(tsc.PLATFORM_CONF_FILE): # read the platform config file and check for UUID @@ -1157,8 +1160,8 @@ class AgentManager(service.PeriodicService): LOG.debug("SysInv Agent Audit running.") if force_updates: - LOG.debug("SysInv Agent Audit force updates: (%s)" % - (', '.join(force_updates))) + LOG.info("SysInv Agent Audit force updates: (%s)" % + (', '.join(force_updates))) self._update_ttys_dcd_status(icontext, self._ihost_uuid) if self._agent_throttle > 5: @@ -1182,7 +1185,7 @@ class AgentManager(service.PeriodicService): self._prev_disk = None # if this audit is requested by conductor, clear - # previous states for disk, lvg and pv to force an update + # previous states for disk, lvg, pv and fs to force an update if force_updates: if constants.DISK_AUDIT_REQUEST in force_updates: self._prev_disk = None @@ -1192,6 +1195,8 @@ class AgentManager(service.PeriodicService): self._prev_pv = None if constants.PARTITION_AUDIT_REQUEST in force_updates: self._prev_partition = None + if constants.FILESYSTEM_AUDIT_REQUEST in force_updates: + self._prev_fs = None # Update disks idisk = self._idisk_operator.idisk_get() @@ -1250,6 +1255,55 @@ class AgentManager(service.PeriodicService): self._prev_lvg = None pass + # Update the filesystems + + # Get the supported filesystems for this host + filesystems = [] + + # check if the scratch fs is supported for current host + if utils.is_filesystem_supported(constants.FILESYSTEM_NAME_SCRATCH, self._ihost_personality): + scratch_lv_size = utils.get_controller_fs_scratch_size() + data = { + 'name': constants.FILESYSTEM_NAME_SCRATCH, + 'size': scratch_lv_size, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_SCRATCH] + } + filesystems.append(data) + + # check if the backup fs is supported for current host + if utils.is_filesystem_supported(constants.FILESYSTEM_NAME_BACKUP, self._ihost_personality): + backup_lv_size = utils.get_controller_fs_backup_size(self._ihost_rootfs_device) + data = { + 'name': constants.FILESYSTEM_NAME_BACKUP, + 'size': backup_lv_size, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_BACKUP] + } + filesystems.append(data) + + # check if the docker fs is supported for current host + if utils.is_filesystem_supported(constants.FILESYSTEM_NAME_DOCKER, self._ihost_personality): + data = { + 'name': constants.FILESYSTEM_NAME_DOCKER, + 'size': constants.KUBERNETES_DOCKER_STOR_SIZE, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_DOCKER] + } + filesystems.append(data) + + if filesystems and ((self._prev_fs is None) or (self._prev_fs != filesystems)): + try: + rpcapi.create_host_filesystems(icontext, + self._ihost_uuid, + filesystems) + self._prev_fs = filesystems + except exception.SysinvException: + LOG.exception("Sysinv Agent exception updating fs" + "conductor.") + self._prev_fs = None + pass + self._report_config_applied(icontext) if os.path.isfile(tsc.PLATFORM_CONF_FILE): diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 0ed5d90fe9..61965e4cbf 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -526,6 +526,26 @@ FILESYSTEM_LV_DICT = { FILESYSTEM_NAME_PATCH_VAULT: 'patch-vault-lv', } +FILESYSTEM_CONTROLLER_SUPPORTED_LIST = [ + FILESYSTEM_NAME_SCRATCH, + FILESYSTEM_NAME_BACKUP, + FILESYSTEM_NAME_DOCKER, +] + +FILESYSTEM_WORKER_SUPPORTED_LIST = [ + FILESYSTEM_NAME_DOCKER, +] + +FILESYSTEM_STORAGE_SUPPORTED_LIST = [ + FILESYSTEM_NAME_DOCKER, +] + +FILESYSTEM_HOSTS_SUPPORTED_LIST_DICT = { + CONTROLLER: FILESYSTEM_CONTROLLER_SUPPORTED_LIST, + WORKER: FILESYSTEM_WORKER_SUPPORTED_LIST, + STORAGE: FILESYSTEM_STORAGE_SUPPORTED_LIST, +} + SUPPORTED_LOGICAL_VOLUME_LIST = FILESYSTEM_LV_DICT.values() SUPPORTED_FILEYSTEM_LIST = [ @@ -594,10 +614,12 @@ DISK_AUDIT_REQUEST = "audit_disk" LVG_AUDIT_REQUEST = "audit_lvg" PV_AUDIT_REQUEST = "audit_pv" PARTITION_AUDIT_REQUEST = "audit_partition" +FILESYSTEM_AUDIT_REQUEST = "audit_fs" CONTROLLER_AUDIT_REQUESTS = [DISK_AUDIT_REQUEST, LVG_AUDIT_REQUEST, PV_AUDIT_REQUEST, - PARTITION_AUDIT_REQUEST] + PARTITION_AUDIT_REQUEST, + FILESYSTEM_AUDIT_REQUEST] # Interface definitions NETWORK_TYPE_NONE = 'none' diff --git a/sysinv/sysinv/sysinv/sysinv/common/exception.py b/sysinv/sysinv/sysinv/sysinv/common/exception.py index 5c074d0d0f..edd89c534d 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/exception.py +++ b/sysinv/sysinv/sysinv/sysinv/common/exception.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. @@ -1364,3 +1364,11 @@ class UnsupportedAssignedInterfaceDataNetworkType(Conflict): class UnsupportedRemovedInterfaceDataNetworkType(Conflict): message = _("Cannot remove datanetwork with type '%(network_type)s' " "from an interface.") + + +class FilesystemAlreadyExists(Conflict): + message = _("A Host FS with name %(name)s already exists.") + + +class FilesystemNotFound(NotFound): + message = _("No Host FS with id %(fs_id)s not found") diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index cfa0bbcf89..09c90f31eb 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -1605,6 +1605,16 @@ def get_dhcp_client_iaid(mac_address): return hwaddr[2] << 24 | hwaddr[3] << 16 | hwaddr[4] << 8 | hwaddr[5] +def is_filesystem_supported(fs, personality): + """ Check to see if a filesystem is supported for the host personality. + """ + + if personality in constants.FILESYSTEM_HOSTS_SUPPORTED_LIST_DICT: + if fs in constants.FILESYSTEM_HOSTS_SUPPORTED_LIST_DICT[personality]: + return True + return False + + def get_controller_fs_scratch_size(): """ Get the filesystem scratch size setup by kickstart. """ @@ -1636,6 +1646,38 @@ def get_controller_fs_scratch_size(): return scratch_gib +def get_controller_fs_backup_size(rootfs_device): + """ Get the filesystem backup size. + """ + + disk_size = get_disk_capacity_mib(rootfs_device) + disk_size = int(disk_size / 1024) + + if disk_size > constants.DEFAULT_SMALL_DISK_SIZE: + LOG.debug("Disk size : %s ... large disk defaults" % disk_size) + + database_storage = constants.DEFAULT_DATABASE_STOR_SIZE + + cgcs_lv_size = constants.DEFAULT_CGCS_STOR_SIZE + backup_lv_size = database_storage + cgcs_lv_size + \ + constants.BACKUP_OVERHEAD + + elif disk_size >= constants.MINIMUM_DISK_SIZE: + + LOG.debug("Disk size : %s ... small disk defaults" % disk_size) + + # Due to the small size of the disk we can't provide the + # proper amount of backup space which is (database + cgcs_lv + # + BACKUP_OVERHEAD) so we are using a smaller default. + backup_lv_size = constants.DEFAULT_SMALL_BACKUP_STOR_SIZE + + else: + LOG.info("Disk size : %s ... disk too small" % disk_size) + raise exception.SysinvException("Disk size requirements not met.") + + return backup_lv_size + + def get_cgts_vg_free_space(): """Determine free space in cgts-vg""" diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index e072d75e2b..937b2b1848 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -3299,6 +3299,61 @@ class ConductorManager(service.PeriodicService): return + def create_host_filesystems(self, context, + ihost_uuid, fs_dict_array): + """Create a filesystems for an ihost with the supplied data. + + This method allows records for filesystems for ihost to be + created. + + :param context: an admin context + :param ihost_uuid: ihost uuid unique id + :param fs_dict_array: initial values for filesystems group objects + :returns: pass or fail + """ + + ihost_uuid.strip() + try: + ihost = self.dbapi.ihost_get(ihost_uuid) + except exception.ServerNotFound: + LOG.exception("Invalid ihost_uuid %s" % ihost_uuid) + return + + host_fs_list = self.dbapi.host_fs_get_by_ihost(ihost_uuid) + forihostid = ihost['id'] + + for fs in fs_dict_array: + fs_dict = { + 'forihostid': forihostid, + } + fs_dict.update(fs) + found = False + + for host_fs in host_fs_list: + if host_fs.name == fs['name']: + found = True + LOG.debug("Host FS '%s' already exists" % fs['name']) + if host_fs.size != fs['size']: + LOG.info("Host FS uuid: %s changed size from %s to %s", + host_fs.uuid, host_fs.size, fs['size']) + # Update the database + try: + self.dbapi.host_fs_update(host_fs.id, fs_dict) + except Exception: + LOG.exception("Host FS Update failed") + break + if not found: + try: + + LOG.info("Creating Host FS:%s:%s %d for host id %d" % + (fs_dict['name'], fs_dict['logical_volume'], + fs_dict['size'], fs_dict['forihostid'])) + self.dbapi.host_fs_create(forihostid, fs_dict) + except Exception: + LOG.exception("Host FS Creation failed") + + return + def _fill_partition_info(self, db_part, ipart): db_part_dict = db_part.as_dict() keys = ['start_mib', 'end_mib', 'size_mib', 'type_name', 'type_guid'] @@ -4157,7 +4212,7 @@ class ConductorManager(service.PeriodicService): @periodic_task.periodic_task(spacing=CONF.conductor.audit_interval) def _agent_update_request(self, context): """ - Check DB for inventory objects with an inconsistent state and + Check DB for inventory objects with an inconsistent state and request an update from sysinv agent. Currently requesting updates for: - ipv: if state is not 'provisioned' @@ -4209,6 +4264,9 @@ class ConductorManager(service.PeriodicService): ilvgs = self.dbapi.ilvg_get_by_ihost(host.uuid) if not ilvgs: update_hosts_dict(host.id, constants.LVG_AUDIT_REQUEST) + host_fs = self.dbapi.host_fs_get_by_ihost(host.uuid) + if not host_fs: + update_hosts_dict(host.id, constants.FILESYSTEM_AUDIT_REQUEST) # Check partitions. partitions = self.dbapi.partition_get_all() diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py b/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py index ea61e46a36..6d4dd116c1 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/rpcapi.py @@ -16,7 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # """ @@ -176,6 +176,24 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy): self.make_msg('create_controller_filesystems', rootfs_device=rootfs_device)) + def create_host_filesystems(self, context, ihost_uuid, fs_dict_array): + """Create or update the filesystem for an ihost with the supplied + data. + + This method allows records for a filesystem for ihost to be + created, or updated. + + :param context: an admin context + :param ihost_uuid: ihost uuid unique id + :param fs_dict_array: initial values for the filesystems + :returns: pass or fail + """ + + return self.call(context, + self.make_msg('create_host_filesystems', + ihost_uuid=ihost_uuid, + fs_dict_array=fs_dict_array)) + def get_ihost_by_macs(self, context, ihost_macs): """Finds ihost db entry based upon the mac list diff --git a/sysinv/sysinv/sysinv/sysinv/db/api.py b/sysinv/sysinv/sysinv/sysinv/db/api.py index c524aa60ff..25471f8caa 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/api.py +++ b/sysinv/sysinv/sysinv/sysinv/db/api.py @@ -16,7 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # @@ -2228,9 +2228,10 @@ class Connection(object): :param values: A dict containing several items used to identify and track the controller_fs. Example: - values = {'name': constants.DEFAULT_DOCKER_STOR_SIZE, + values = {'name': constants.FILESYSTEM_NAME_DOCKER, 'size': 30, - 'logical_volume': constants.FILESYSTEM_NAME_LV_DICT, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_DOCKER], 'replicated': False} :returns: A controller_fs. """ @@ -4339,3 +4340,86 @@ class Connection(object): :param uuid: The uuid of an interface network association. """ + + @abc.abstractmethod + def host_fs_create(self, forihostid, values): + """Create a new filesystem for a host. + + :param forihostid: uuid or id of an ihost + :param values: A dict containing several items used to identify + and track the filesystem. + Example: + values = {'name': constants.FILESYSTEM_NAME_DOCKER, + 'size': 30, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_DOCKER], + 'forihostid': 1} + :returns: A filesystem. + """ + + @abc.abstractmethod + def host_fs_get(self, fs_id): + """Return a filesystem. + + :param fs_id: The id or uuid of a filesystem. + :returns: A filesystem. + """ + + @abc.abstractmethod + def host_fs_get_all(self, forihostid=None): + """Return filesystems. + + :param forihostid: The id or uuid of an ihost. + :returns: filesystem. + """ + + @abc.abstractmethod + def host_fs_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of filesystems. + + :param limit: Maximum number of filesystems to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def host_fs_get_by_ihost(self, ihost, limit=None, + marker=None, sort_key=None, + sort_dir=None): + """List all the filesystems for a given ihost. + + :param ihost: The id or uuid of an ihost. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted + :param sort_dir: direction in which results should be sorted + (asc, desc) + :returns: A list of filesystems. + """ + + @abc.abstractmethod + def host_fs_update(self, fs_id, values): + """Update properties of a filesystem. + + :param fs_id: The id or uuid of an filesystem. + :param values: Dict of values to update. May be a partial list. + Example: + values = {'name': constants.FILESYSTEM_NAME_DOCKER, + 'size': 30, + 'logical_volume': constants.FILESYSTEM_LV_DICT[ + constants.FILESYSTEM_NAME_DOCKER + ], + 'forihostid': 1} + :returns: A filesystem. + """ + + @abc.abstractmethod + def host_fs_destroy(self, fs_id): + """Destroy a filesystem. + + :param fs_id: The id or uuid of a filesystem. + """ diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py index 310344925e..8bf0fadfc7 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py @@ -15,7 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # """SQLAlchemy storage backend.""" @@ -148,7 +148,8 @@ def add_identity_filter(query, value, use_sensorgroupname=False, use_sensorname=False, use_cluster_uuid=False, - use_pciaddr=False): + use_pciaddr=False, + use_fsname=False): """Adds an identity filter to a query. Filters results by ID, if supplied value is a valid integer. @@ -189,6 +190,8 @@ def add_identity_filter(query, value, return query.filter_by(sensorname=value) elif use_pciaddr: return query.filter_by(pciaddr=value) + elif use_fsname: + return query.filter_by(name=value) else: return query.filter_by(hostname=value) @@ -1121,6 +1124,25 @@ def add_label_filter_by_host(query, hostid): return query.filter(models.ihost.uuid == hostid) +def add_host_fs_filter(query, value): + """Adds an fs-specific filter to a query. + + :param query: Initial query to add filter to. + :param value: Value for filtering results by. + :return: Modified query. + """ + return add_identity_filter(query, value, use_fsname=True) + + +def add_host_fs_filter_by_ihost(query, value): + if utils.is_int_like(value): + return query.filter_by(forihostid=value) + else: + query = query.join(models.ihost, + models.HostFs.forihostid == models.ihost.id) + return query.filter(models.ihost.uuid == value) + + class Connection(api.Connection): """SqlAlchemy connection.""" @@ -7934,3 +7956,82 @@ class Connection(api.Connection): @objects.objectify(objects.interface_datanetwork) def interface_datanetwork_query(self, values): return self._interface_datanetwork_query(values) + + def _host_fs_get(self, fs_id): + query = model_query(models.HostFs) + query = add_identity_filter(query, fs_id) + + try: + result = query.one() + except NoResultFound: + raise exception.FilesystemNotFound(fs_id=fs_id) + + return result + + @objects.objectify(objects.host_fs) + def host_fs_create(self, forihostid, values): + if not values.get('uuid'): + values['uuid'] = uuidutils.generate_uuid() + values['forihostid'] = int(forihostid) + fs = models.HostFs() + fs.update(values) + with _session_for_write() as session: + try: + session.add(fs) + session.flush() + except db_exc.DBDuplicateEntry: + raise exception.FilesystemAlreadyExists( + name=values['name'], host=forihostid) + + return self._host_fs_get(values['uuid']) + + @objects.objectify(objects.host_fs) + def host_fs_get_all(self, forihostid=None): + query = model_query(models.HostFs, read_deleted="no") + if forihostid: + query = query.filter_by(forihostid=forihostid) + return query.all() + + @objects.objectify(objects.host_fs) + def host_fs_get(self, fs_id): + return self._host_fs_get(fs_id) + + @objects.objectify(objects.host_fs) + def host_fs_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + return _paginate_query(models.HostFs, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.host_fs) + def host_fs_get_by_ihost(self, ihost, limit=None, marker=None, + sort_key=None, sort_dir=None): + + query = model_query(models.HostFs) + query = add_host_fs_filter_by_ihost(query, ihost) + return _paginate_query(models.HostFs, limit, marker, + sort_key, sort_dir, query) + + @objects.objectify(objects.host_fs) + def host_fs_update(self, fs_id, values): + with _session_for_write() as session: + query = model_query(models.HostFs, read_deleted="no", + session=session) + query = add_host_fs_filter(query, fs_id) + + count = query.update(values, synchronize_session='fetch') + if count != 1: + raise exception.FilesystemNotFound(fs_id=fs_id) + return query.one() + + def host_fs_destroy(self, fs_id): + with _session_for_write() as session: + # Delete physically since it has unique columns + if uuidutils.is_uuid_like(fs_id): + model_query(models.HostFs, read_deleted="no", + session=session).\ + filter_by(uuid=fs_id).\ + delete() + else: + model_query(models.HostFs, read_deleted="no").\ + filter_by(id=fs_id).\ + delete() diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/089_host_fs.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/089_host_fs.py new file mode 100644 index 0000000000..d57698987b --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/migrate_repo/versions/089_host_fs.py @@ -0,0 +1,61 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from sqlalchemy import DateTime, String, Integer +from sqlalchemy import Column, MetaData, Table, ForeignKey + +from sysinv.openstack.common import log + +ENGINE = 'InnoDB' +CHARSET = 'utf8' + +LOG = log.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + This database upgrade creates a new host_fs table for storing + filesystem info for a host. + """ + + meta = MetaData() + meta.bind = migrate_engine + + Table('i_host', + meta, + Column('id', Integer, primary_key=True, nullable=False), + mysql_engine=ENGINE, mysql_charset=CHARSET, autoload=True) + + # Define and create the host_fs table. + fs_app = Table( + 'host_fs', + meta, + Column('created_at', DateTime), + Column('updated_at', DateTime), + Column('deleted_at', DateTime), + + Column('id', Integer, primary_key=True, nullable=False), + Column('uuid', String(36), unique=True), + Column('name', String(255)), + Column('size', Integer), + Column('logical_volume', String(64)), + Column('forihostid', Integer, + ForeignKey('i_host.id', ondelete='CASCADE')), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + + fs_app.create() + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + # Downgrade is unsupported in this release. + raise NotImplementedError('SysInv database downgrade is unsupported.') diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py index d59c0c16a5..2b5241650b 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/models.py @@ -15,7 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -1721,3 +1721,17 @@ class KubeAppReleases(Base): app_id = Column(Integer, ForeignKey('kube_app.id', ondelete='CASCADE')) kube_app = relationship("KubeApp", lazy="joined", join_depth=1) UniqueConstraint('release', 'namespace', 'app_id', name='u_app_release_namespace') + + +class HostFs(Base): + __tablename__ = 'host_fs' + + id = Column(Integer, primary_key=True) + uuid = Column(String(36)) + + name = Column(String(64)) + size = Column(Integer) + logical_volume = Column(String(64)) + forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE')) + + host = relationship("ihost", lazy="joined", join_depth=1) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/__init__.py b/sysinv/sysinv/sysinv/sysinv/objects/__init__.py index a7224c7ed3..b234e33ab1 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/__init__.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/__init__.py @@ -12,7 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # @@ -88,6 +88,7 @@ from sysinv.objects import storage_file from sysinv.objects import storage_external from sysinv.objects import storage_tier from sysinv.objects import storage_ceph_external +from sysinv.objects import host_fs def objectify(klass): @@ -185,6 +186,7 @@ label = label.Label kube_app = kube_app.KubeApp kube_app_releases = kube_app_releases.KubeAppReleases datanetwork = datanetwork.DataNetwork +host_fs = host_fs.HostFS __all__ = (system, cluster, @@ -254,6 +256,7 @@ __all__ = (system, kube_app_releases, datanetwork, interface_network, + host_fs, # alias objects for RPC compatibility ihost, ilvg, diff --git a/sysinv/sysinv/sysinv/sysinv/objects/host_fs.py b/sysinv/sysinv/sysinv/sysinv/objects/host_fs.py new file mode 100644 index 0000000000..e31d2a33a0 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/objects/host_fs.py @@ -0,0 +1,38 @@ +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sysinv.db import api as db_api +from sysinv.objects import base +from sysinv.objects import utils + + +class HostFS(base.SysinvObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'uuid': utils.str_or_none, + 'name': utils.str_or_none, + 'size': utils.int_or_none, + 'logical_volume': utils.str_or_none, + + 'forihostid': int, + 'ihost_uuid': utils.str_or_none, + } + + _foreign_fields = {'ihost_uuid': 'host:uuid'} + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + return cls.dbapi.host_fs_get(uuid) + + def save_changes(self, context, updates): + self.dbapi.host_fs_update(self.uuid, updates)