Skip to content

Commit

Permalink
Add Disk resource to Delfin (#407)
Browse files Browse the repository at this point in the history
* Add Disk resource to Delfin

* Add unit tests of disk db apis

* Fix review comments
  • Loading branch information
joseph-v authored Dec 18, 2020
1 parent 9099b30 commit b3bcba0
Show file tree
Hide file tree
Showing 18 changed files with 532 additions and 12 deletions.
54 changes: 54 additions & 0 deletions delfin/api/v1/disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# 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.

from delfin import db
from delfin.api import api_utils
from delfin.api.common import wsgi
from delfin.api.views import disks as disk_view


class DiskController(wsgi.Controller):

def __init__(self):
super(DiskController, self).__init__()
self.search_options = ['name', 'status', 'id', 'storage_id',
'native_disk_id']

def _get_disks_search_options(self):
"""Return disks 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_disks_search_options())

disks = db.disk_get_all(ctxt, marker, limit, sort_keys,
sort_dirs, query_params, offset)
return disk_view.build_disks(disks)

def show(self, req, id):
ctxt = req.environ['delfin.context']
disk = db.disk_get(ctxt, id)
return disk_view.build_disk(disk)


def create_resource():
return wsgi.Resource(DiskController())
5 changes: 5 additions & 0 deletions delfin/api/v1/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from delfin.api.v1 import alerts
from delfin.api.v1 import controllers
from delfin.api.v1 import ports
from delfin.api.v1 import disks
from delfin.api.v1 import storage_pools
from delfin.api.v1 import storages
from delfin.api.v1 import volumes
Expand Down Expand Up @@ -104,3 +105,7 @@ def _setup_routes(self, mapper):
self.resources['ports'] = ports.create_resource()
mapper.resource("port", "ports",
controller=self.resources['ports'])

self.resources['disks'] = disks.create_resource()
mapper.resource("disk", "disks",
controller=self.resources['disks'])
26 changes: 26 additions & 0 deletions delfin/api/views/disks.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_disks(disks):
# Build list of disks
views = [build_disk(disk)
for disk in disks]
return dict(disks=views)


def build_disk(disk):
view = copy.deepcopy(disk)
return dict(view)
28 changes: 28 additions & 0 deletions delfin/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,34 @@ class PortLogicalType(object):
INTERNAL, MAINTENANCE, INTERCONNECT, OTHER)


class DiskStatus(object):
NORMAL = 'normal'
ABNORMAL = 'abnormal'
OFFLINE = 'offline'

ALL = (NORMAL, ABNORMAL, OFFLINE)


class DiskPhysicalType(object):
SATA = 'sata'
SAS = 'sas'
SSD = 'ssd'
NL_SSD = 'nl-ssd'
UNKNOWN = 'unknown'

ALL = (SATA, SAS, SSD, NL_SSD, UNKNOWN)


class DiskLogicalType(object):
FREE = 'free'
MEMBER = 'member'
HOTSPARE = 'hotspare'
CACHE = 'cache'
UNKNOWN = 'unknown'

ALL = (FREE, MEMBER, HOTSPARE, CACHE, UNKNOWN)


# Enumerations for alert severity
class Severity(object):
FATAL = 'Fatal'
Expand Down
22 changes: 21 additions & 1 deletion delfin/db/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,21 +344,41 @@ def port_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs, filters, offset)


def disks_create(context, values):
"""Create multiple disks."""
return IMPL.disks_create(context, values)


def disks_update(context, values):
"""Update multiple disks."""
return IMPL.disks_update(context, values)


def disks_delete(context, values):
"""Delete multiple disks."""
return IMPL.disks_delete(context, values)


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


def disk_update(context, disk_id, values):
"""Update a disk withe the values dictionary."""
return IMPL.disk_create(context, disk_id, values)
return IMPL.disk_update(context, disk_id, values)


def disk_get(context, disk_id):
"""Get a disk or raise an exception if it does not exist."""
return IMPL.disk_get(context, disk_id)


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


def disk_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None, offset=None):
"""Retrieves all disks.
Expand Down
134 changes: 129 additions & 5 deletions delfin/db/sqlalchemy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,25 +867,147 @@ def _process_port_info_filters(query, filters):
return query


def disks_create(context, disks):
"""Create multiple disks."""
session = get_session()
disks_refs = []
with session.begin():

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

disk_ref = models.Disk()
disk_ref.update(disk)
disks_refs.append(disk_ref)

session.add_all(disks_refs)

return disks_refs


def disks_update(context, disks):
"""Update multiple disks."""
session = get_session()

with session.begin():
disk_refs = []

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

if not result:
LOG.error(exception.DiskNotFound(disk.get(
'id')))
else:
disk_refs.append(result)

return disk_refs


def disks_delete(context, disks_id_list):
"""Delete multiple disks."""
session = get_session()
with session.begin():
for disk_id in disks_id_list:
LOG.debug('deleting disk {0}:'.format(disk_id))
query = _disk_get_query(context, session)
result = query.filter_by(id=disk_id).delete()

if not result:
LOG.error(exception.DiskNotFound(disk_id))

return


def _disk_get_query(context, session=None):
return model_query(context, models.Disk, session=session)


def _disk_get(context, disk_id, session=None):
result = (_disk_get_query(context, session=session)
.filter_by(id=disk_id)
.first())

if not result:
raise exception.DiskNotFound(disk_id)

return result


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

disk_ref = models.Disk()
disk_ref.update(values)

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

return _disk_get(context,
disk_ref['id'],
session=session)


def disk_update(context, disk_id, values):
"""Update a disk withe the values dictionary."""
return NotImplemented
"""Update a disk with the values dictionary."""
session = get_session()

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

if not result:
raise exception.DiskNotFound(disk_id)

return result


def disk_get(context, disk_id):
"""Get a disk or raise an exception if it does not exist."""
return NotImplemented
return _disk_get(context, disk_id)


def disk_delete_by_storage(context, storage_id):
"""Delete disk or raise an exception if it does not exist."""
_disk_get_query(context).filter_by(storage_id=storage_id).delete()


def disk_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None, offset=None):
"""Retrieves all disks."""
return NotImplemented

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


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

return query


def is_orm_value(obj):
Expand Down Expand Up @@ -1002,6 +1124,8 @@ def alert_source_get_all(context, marker=None, limit=None, sort_keys=None,
_process_controller_info_filters,
_controller_get),
models.Port: (_port_get_query, _process_port_info_filters, _port_get),
models.Disk: (_disk_get_query, _process_disk_info_filters,
_disk_get),
}


Expand Down
15 changes: 11 additions & 4 deletions delfin/db/sqlalchemy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,21 @@ class Disk(BASE, DelfinBase):
"""Represents a disk object."""
__tablename__ = 'disks'
id = Column(String(36), primary_key=True)
name = Column(String(255))
status = Column(String(255))
vendor = Column(String(255))
native_disk_id = Column(String(255))
name = Column(String(255))
serial_number = Column(String(255))
manufacturer = Column(String(255))
model = Column(String(255))
media_type = Column(String(255))
firmware = Column(String(255))
speed = Column(Integer)
capacity = Column(BigInteger)
status = Column(String(255))
physical_type = Column(String(255))
logical_type = Column(String(255))
health_score = Column(Integer)
native_disk_group_id = Column(String(255))
storage_id = Column(String(255))
location = Column(String(255))


class Controller(BASE, DelfinBase):
Expand Down
5 changes: 5 additions & 0 deletions delfin/drivers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ def list_ports(self, context, storage_id):
driver = self.driver_manager.get_driver(context, storage_id=storage_id)
return driver.list_ports(context)

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

def add_trap_config(self, context, storage_id, trap_config):
"""Config the trap receiver in storage system."""
pass
Expand Down
3 changes: 3 additions & 0 deletions delfin/drivers/dell_emc/vmax/vmax.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ def list_controllers(self, context):
def list_ports(self, context):
pass

def list_disks(self, context):
pass

def add_trap_config(self, context, trap_config):
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 @@ -58,6 +58,11 @@ def list_ports(self, context):
"""List all ports from storage system."""
pass

@abc.abstractmethod
def list_disks(self, context):
"""List all disks 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 b3bcba0

Please sign in to comment.