Skip to content

Commit

Permalink
Add NAS resource filesystem
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-v committed Feb 17, 2021
1 parent 8023a1f commit 6fa64b2
Show file tree
Hide file tree
Showing 12 changed files with 420 additions and 1 deletion.
54 changes: 54 additions & 0 deletions delfin/api/v1/filesystems.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2021 The SODA Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from delfin import db
from delfin.api import api_utils
from delfin.api.common import wsgi
from delfin.api.views import filesystems as filesystem_view


class PortController(wsgi.Controller):

def __init__(self):
super(PortController, self).__init__()
self.search_options = ['name', 'status', 'id', 'storage_id', 'wwn',
'native_controller_id', 'native_filesystem_id']

def _get_fs_search_options(self):
"""Return filesystems search options allowed ."""
return self.search_options

def index(self, req):
ctxt = req.environ['delfin.context']
query_params = {}
query_params.update(req.GET)
# update options other than filters
sort_keys, sort_dirs = api_utils.get_sort_params(query_params)
marker, limit, offset = api_utils.get_pagination_params(query_params)
# strip out options except supported search options
api_utils.remove_invalid_options(ctxt, query_params,
self._get_fs_search_options())

filesystems = db.filesystem_get_all(ctxt, marker, limit, sort_keys,
sort_dirs, query_params, offset)
return filesystem_view.build_filesystems(filesystems)

def show(self, req, id):
ctxt = req.environ['delfin.context']
filesystem = db.filesystem_get(ctxt, id)
return filesystem_view.build_filesystem(filesystem)


def create_resource():
return wsgi.Resource(PortController())
5 changes: 5 additions & 0 deletions delfin/api/v1/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from delfin.api.v1 import alert_source
from delfin.api.v1 import alerts
from delfin.api.v1 import controllers
from delfin.api.v1 import filesystems
from delfin.api.v1 import ports
from delfin.api.v1 import disks
from delfin.api.v1 import storage_pools
Expand Down Expand Up @@ -109,3 +110,7 @@ def _setup_routes(self, mapper):
self.resources['disks'] = disks.create_resource()
mapper.resource("disk", "disks",
controller=self.resources['disks'])

self.resources['filesystems'] = filesystems.create_resource()
mapper.resource("filesystems", "filesystems",
controller=self.resources['filesystems'])
26 changes: 26 additions & 0 deletions delfin/api/views/filesystems.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2020 The SODA Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy


def build_filesystems(filesystems):
# Build list of filesystems
views = [build_filesystem(filesystem)
for filesystem in filesystems]
return dict(filesystems=views)


def build_filesystem(filesystem):
view = copy.deepcopy(filesystem)
return dict(view)
17 changes: 17 additions & 0 deletions delfin/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,23 @@ class DiskLogicalType(object):
ALL = (FREE, MEMBER, HOTSPARE, CACHE, UNKNOWN)


class FilesystemStatus(object):
NORMAL = 'normal'
OFFLINE = 'offline'
UNKNOWN = 'unknown'

ALL = (NORMAL, OFFLINE, UNKNOWN)


class FilesystemSecurityMode(object):
MIXED = 'mixed'
NATIVE = 'native'
WINDOWS = 'windows'
UNIX = 'unix'

ALL = (MIXED, NATIVE, WINDOWS, UNIX)


# Enumerations for alert severity
class Severity(object):
FATAL = 'Fatal'
Expand Down
58 changes: 58 additions & 0 deletions delfin/db/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,64 @@ def disk_get_all(context, marker=None, limit=None, sort_keys=None,
filters, offset)


def filesystems_create(context, values):
"""Create multiple filesystems."""
return IMPL.filesystems_create(context, values)


def filesystems_update(context, values):
"""Update multiple filesystems."""
return IMPL.filesystems_update(context, values)


def filesystems_delete(context, values):
"""Delete multiple filesystems."""
return IMPL.filesystems_delete(context, values)


def filesystem_create(context, values):
"""Create a filesystem from the values dictionary."""
return IMPL.filesystem_create(context, values)


def filesystem_update(context, filesystem_id, values):
"""Update a filesystem with the values dictionary."""
return IMPL.filesystem_update(context, filesystem_id, values)


def filesystem_get(context, filesystem_id):
"""Get a filesystem or raise an exception if it does not exist."""
return IMPL.filesystem_get(context, filesystem_id)


def filesystem_delete_by_storage(context, storage_id):
"""Delete a filesystem or raise an exception if it does not exist."""
return IMPL.filesystem_delete_by_storage(context, storage_id)


def filesystem_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None, offset=None):
"""Retrieves all filesystems.
If no sort parameters are specified then the returned volumes are sorted
first by the 'created_at' key and then by the 'id' key in descending
order.
:param context: context of this request, it's helpful to trace the request
:param marker: the last item of the previous page, used to determine the
next page of results to return
:param limit: maximum number of items to return
:param sort_keys: list of attributes by which results should be sorted,
paired with corresponding item in sort_dirs
:param sort_dirs: list of directions in which results should be sorted,
paired with corresponding item in sort_keys, for example
'desc' for descending order
:param filters: dictionary of filters
:param offset: number of items to skip
:returns: list of controllers
"""
return IMPL.filesystem_get_all(context, marker, limit, sort_keys,
sort_dirs, filters, offset)


def access_info_create(context, values):
"""Create a storage access information that used to connect
to a specific storage device.
Expand Down
144 changes: 144 additions & 0 deletions delfin/db/sqlalchemy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,148 @@ def _process_disk_info_filters(query, filters):
return query


def filesystems_create(context, filesystems):
"""Create multiple filesystems."""
session = get_session()
filesystems_refs = []
with session.begin():

for filesystem in filesystems:
LOG.debug('adding new filesystem for native_filesystem_id {0}:'
.format(filesystem.get('native_filesystem_id')))
if not filesystem.get('id'):
filesystem['id'] = uuidutils.generate_uuid()

filesystem_ref = models.Filesystem()
filesystem_ref.update(filesystem)
filesystems_refs.append(filesystem_ref)

session.add_all(filesystems_refs)

return filesystems_refs


def filesystems_update(context, filesystems):
"""Update multiple filesystems."""
session = get_session()

with session.begin():
filesystem_refs = []

for filesystem in filesystems:
LOG.debug('updating filesystem {0}:'.format(
filesystem.get('id')))
query = _filesystem_get_query(context, session)
result = query.filter_by(id=filesystem.get('id')
).update(filesystem)

if not result:
LOG.error(exception.FilesystemNotFound(filesystem.get(
'id')))
else:
filesystem_refs.append(result)

return filesystem_refs


def filesystems_delete(context, filesystems_id_list):
"""Delete multiple filesystems."""
session = get_session()
with session.begin():
for filesystem_id in filesystems_id_list:
LOG.debug('deleting filesystem {0}:'.format(filesystem_id))
query = _filesystem_get_query(context, session)
result = query.filter_by(id=filesystem_id).delete()

if not result:
LOG.error(exception.FilesystemNotFound(filesystem_id))
return


def _filesystem_get_query(context, session=None):
return model_query(context, models.Filesystem, session=session)


def _filesystem_get(context, filesystem_id, session=None):
result = (_filesystem_get_query(context, session=session)
.filter_by(id=filesystem_id)
.first())

if not result:
raise exception.FilesystemNotFound(filesystem_id)

return result


def filesystem_create(context, values):
"""Create a filesystem from the values dictionary."""
if not values.get('id'):
values['id'] = uuidutils.generate_uuid()

filesystem_ref = models.Filesystem()
filesystem_ref.update(values)

session = get_session()
with session.begin():
session.add(filesystem_ref)

return _filesystem_get(context,
filesystem_ref['id'],
session=session)


def filesystem_update(context, filesystem_id, values):
"""Update a filesystem with the values dictionary."""
session = get_session()

with session.begin():
query = _filesystem_get_query(context, session)
result = query.filter_by(id=filesystem_id).update(values)

if not result:
raise exception.FilesystemNotFound(filesystem_id)

return result


def filesystem_get(context, filesystem_id):
"""Get a filesystem or raise an exception if it does not exist."""
return _filesystem_get(context, filesystem_id)


def filesystem_delete_by_storage(context, storage_id):
"""Delete filesystem or raise an exception if it does not exist."""
_filesystem_get_query(context).filter_by(storage_id=storage_id).delete()


def filesystem_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None, offset=None):
"""Retrieves all filesystems."""

session = get_session()
with session.begin():
# Generate the query
query = _generate_paginate_query(context, session, models.Filesystem,
marker, limit, sort_keys, sort_dirs,
filters, offset,
)
# No Filesystem would match, return empty list
if query is None:
return []
return query.all()


@apply_like_filters(model=models.Filesystem)
def _process_filesystem_info_filters(query, filters):
"""Common filter processing for filesystems queries."""
if filters:
if not is_valid_model_filters(models.Filesystem, filters):
return
query = query.filter_by(**filters)

return query


def is_orm_value(obj):
"""Check if object is an ORM field or expression."""
return isinstance(obj, (sqlalchemy.orm.attributes.InstrumentedAttribute,
Expand Down Expand Up @@ -1126,6 +1268,8 @@ def alert_source_get_all(context, marker=None, limit=None, sort_keys=None,
models.Port: (_port_get_query, _process_port_info_filters, _port_get),
models.Disk: (_disk_get_query, _process_disk_info_filters,
_disk_get),
models.Filesystem: (_filesystem_get_query,
_process_filesystem_info_filters, _filesystem_get),
}


Expand Down
18 changes: 18 additions & 0 deletions delfin/db/sqlalchemy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,24 @@ class Port(BASE, DelfinBase):
ipv6_mask = Column(String(255))


class Filesystem(BASE, DelfinBase):
"""Represents a filesystem object."""
__tablename__ = 'filesystems'
id = Column(String(36), primary_key=True)
name = Column(String(255))
storage_id = Column(String(36))
native_filesystem_id = Column(String(255))
status = Column(String(255))
allocation_type = Column(String(255))
security_mode = Column(String(255))
total_capacity = Column(BigInteger)
used_capacity = Column(BigInteger)
free_capacity = Column(BigInteger)
compression = Column(Boolean)
deduplication = Column(Boolean)
worm = Column(Boolean)


class AlertSource(BASE, DelfinBase):
"""Represents an alert source configuration."""
__tablename__ = 'alert_source'
Expand Down
5 changes: 5 additions & 0 deletions delfin/drivers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ def list_disks(self, context, storage_id):
driver = self.driver_manager.get_driver(context, storage_id=storage_id)
return driver.list_disks(context)

def list_filesystems(self, context, storage_id):
"""List all filesystems from storage system."""
driver = self.driver_manager.get_driver(context, storage_id=storage_id)
return driver.list_filesystems(context)

def add_trap_config(self, context, storage_id, trap_config):
"""Config the trap receiver in storage system."""
pass
Expand Down
5 changes: 5 additions & 0 deletions delfin/drivers/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ def list_disks(self, context):
"""List all disks from storage system."""
pass

@abc.abstractmethod
def list_filesystems(self, context):
"""List all filesystems from storage system."""
pass

@abc.abstractmethod
def add_trap_config(self, context, trap_config):
"""Config the trap receiver in storage system."""
Expand Down
Loading

0 comments on commit 6fa64b2

Please sign in to comment.