Skip to content

Commit

Permalink
add ds8000 resources info (#790)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanjiangyu-ghca authored Jan 5, 2022
1 parent a9c31b5 commit 73c98e4
Show file tree
Hide file tree
Showing 7 changed files with 841 additions and 0 deletions.
Empty file.
67 changes: 67 additions & 0 deletions delfin/drivers/ibm/ds8k/alert_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 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.
import time

import six
from oslo_log import log

from delfin import exception
from delfin.common import alert_util
from delfin.common import constants

LOG = log.getLogger(__name__)


class AlertHandler(object):

TIME_PATTERN = "%Y-%m-%dT%H:%M:%S%z"

ALERT_LEVEL_MAP = {'error': constants.Severity.CRITICAL,
'warning': constants.Severity.WARNING,
'info': constants.Severity.INFORMATIONAL
}
SECONDS_TO_MS = 1000

def parse_queried_alerts(self, alert_model_list, alert_list, query_para):
alerts = alert_list.get('data', {}).get('events')
if alerts:
for alert in alerts:
try:
occur_time = int(time.mktime(time.strptime(
alert.get('time'),
self.TIME_PATTERN))) * AlertHandler.SECONDS_TO_MS
if not alert_util.is_alert_in_time_range(
query_para, occur_time):
continue

alert_model = {}
alert_model['alert_id'] = alert.get('type')
alert_model['alert_name'] = alert.get('description')
alert_model['severity'] = self.ALERT_LEVEL_MAP.get(
alert.get('severity'),
constants.Severity.INFORMATIONAL)
alert_model['description'] = alert.get('description')
alert_model['category'] = constants.Category.FAULT
alert_model['type'] = constants.EventType.EQUIPMENT_ALARM
alert_model['sequence_number'] = alert.get('id')
alert_model['occur_time'] = occur_time
alert_model['resource_type'] = \
constants.DEFAULT_RESOURCE_TYPE
alert_model_list.append(alert_model)
except Exception as e:
LOG.error(e)
err_msg = "Failed to build alert model as some" \
" attributes missing in queried alerts: %s"\
% (six.text_type(e))
raise exception.InvalidResults(err_msg)
261 changes: 261 additions & 0 deletions delfin/drivers/ibm/ds8k/ds8k.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# 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.
import six
from oslo_log import log
from oslo_utils import units

from delfin import exception
from delfin.common import constants
from delfin.drivers import driver
from delfin.drivers.ibm.ds8k import rest_handler, alert_handler

LOG = log.getLogger(__name__)


class DS8KDriver(driver.StorageDriver):

PORT_TYPE_MAP = {'FC-AL': constants.PortType.FC,
'SCSI-FCP': constants.PortType.FC,
'FICON': constants.PortType.FICON
}
PORT_STATUS_MAP = {
'online': constants.PortHealthStatus.NORMAL,
'offline': constants.PortHealthStatus.ABNORMAL,
'fenced': constants.PortHealthStatus.UNKNOWN,
'quiescing': constants.PortHealthStatus.UNKNOWN
}

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.rest_handler = rest_handler.RestHandler(**kwargs)
self.rest_handler.login()

def reset_connection(self, context, **kwargs):
self.rest_handler.logout()
self.rest_handler.verify = kwargs.get('verify', False)
self.rest_handler.login()

def close_connection(self):
self.rest_handler.logout()

def get_storage(self, context):
try:
result = None
system_info = self.rest_handler.get_rest_info('/api/v1/systems')
if system_info:
system_data = system_info.get('data', {}).get('systems', [])
if system_data:
for system in system_data:
name = system.get('name')
model = system.get('MTM')
serial_number = system.get('sn')
version = system.get('release')
status = constants.StorageStatus.NORMAL
if system.get('state') != 'online':
status = constants.StorageStatus.ABNORMAL
total = 0
free = 0
used = 0
raw = 0
if system.get('cap') != '' and \
system.get('cap') is not None:
total = int(system.get('cap'))
if system.get('capraw') != '' and \
system.get('capraw') is not None:
raw = int(system.get('capraw'))
if system.get('capalloc') != '' and \
system.get('capalloc') is not None:
used = int(system.get('capalloc'))
if system.get('capavail') != '' and \
system.get('capavail') is not None:
free = int(system.get('capavail'))
result = {
'name': name,
'vendor': 'IBM',
'model': model,
'status': status,
'serial_number': serial_number,
'firmware_version': version,
'location': '',
'total_capacity': total,
'raw_capacity': raw,
'used_capacity': used,
'free_capacity': free
}
break
else:
raise exception.StorageBackendException(
"ds8k storage system info is None")
else:
raise exception.StorageBackendException(
"ds8k storage system info is None")
return result
except Exception as err:
err_msg = "Failed to get storage attributes from ds8k: %s" % \
(six.text_type(err))
raise exception.InvalidResults(err_msg)

def list_storage_pools(self, context):
pool_info = self.rest_handler.get_rest_info('/api/v1/pools')
pool_list = []
status = constants.StoragePoolStatus.NORMAL
if pool_info is not None:
pool_data = pool_info.get('data', {}).get('pools', [])
for pool in pool_data:
if pool.get('stgtype') == 'fb':
pool_type = constants.StorageType.BLOCK
else:
pool_type = constants.StorageType.FILE
if (int(pool.get('capalloc')) / int(pool.get('cap'))) * 100 > \
int(pool.get('threshold')):
status = constants.StoragePoolStatus.ABNORMAL
pool_name = '%s_%s' % (pool.get('name'), pool.get('node'))
pool_result = {
'name': pool_name,
'storage_id': self.storage_id,
'native_storage_pool_id': str(pool.get('id')),
'status': status,
'storage_type': pool_type,
'total_capacity': int(pool.get('cap')),
'used_capacity': int(pool.get('capalloc')),
'free_capacity': int(pool.get('capavail'))
}
pool_list.append(pool_result)
return pool_list

def list_volumes(self, context):
volume_list = []
pool_list = self.rest_handler.get_rest_info('/api/v1/pools')
if pool_list is not None:
pool_data = pool_list.get('data', {}).get('pools', [])
for pool in pool_data:
url = '/api/v1/pools/%s/volumes' % pool.get('id')
volumes = self.rest_handler.get_rest_info(url)
if volumes is not None:
vol_entries = volumes.get('data', {}).get('volumes', [])
for volume in vol_entries:
total = volume.get('cap')
used = volume.get('capalloc')
vol_type = constants.VolumeType.THICK if \
volume.get('stgtype') == 'fb' else \
constants.VolumeType.THIN
status = constants.StorageStatus.NORMAL if \
volume.get('state') == 'normal' else\
constants.StorageStatus.ABNORMAL
vol_name = '%s_%s' % (volume.get('name'),
volume.get('id'))
vol = {
'name': vol_name,
'storage_id': self.storage_id,
'description': '',
'status': status,
'native_volume_id': str(volume.get('id')),
'native_storage_pool_id':
volume.get('pool').get('id'),
'wwn': '',
'type': vol_type,
'total_capacity': int(total),
'used_capacity': int(used),
'free_capacity': int(total) - int(used)
}
volume_list.append(vol)
return volume_list

def list_alerts(self, context, query_para=None):
alert_model_list = []
alert_list = self.rest_handler.get_rest_info(
'/api/v1/events?severity=warning,error')
alert_handler.AlertHandler() \
.parse_queried_alerts(alert_model_list, alert_list, query_para)
return alert_model_list

@staticmethod
def division_port_wwn(original_wwn):
result_wwn = None
if not original_wwn:
return result_wwn
is_first = True
for i in range(0, len(original_wwn), 2):
if is_first is True:
result_wwn = '%s' % (original_wwn[i:i + 2])
is_first = False
else:
result_wwn = '%s:%s' % (result_wwn, original_wwn[i:i + 2])
return result_wwn

def list_ports(self, context):
port_list = []
port_info = self.rest_handler.get_rest_info('/api/v1/ioports')
if port_info:
port_data = port_info.get('data', {}).get('ioports', [])
for port in port_data:
status = DS8KDriver.PORT_STATUS_MAP.get(
port.get('state'), constants.PortHealthStatus.UNKNOWN)
speed = None
connection_status = constants.PortConnectionStatus.CONNECTED\
if status == constants.PortHealthStatus.NORMAL \
else constants.PortConnectionStatus.DISCONNECTED
if port.get('speed'):
speed = int(port.get('speed').split(' ')[0]) * units.G
port_result = {
'name': port.get('loc'),
'storage_id': self.storage_id,
'native_port_id': port.get('id'),
'location': port.get('loc'),
'connection_status': connection_status,
'health_status': status,
'type': DS8KDriver.PORT_TYPE_MAP.get(
port.get('protocol'), constants.PortType.OTHER),
'logical_type': '',
'speed': speed,
'max_speed': speed,
'wwn': DS8KDriver.division_port_wwn(port.get('wwpn'))
}
port_list.append(port_result)
return port_list

def list_controllers(self, context):
controller_list = []
controller_info = self.rest_handler.get_rest_info('/api/v1/nodes')
if controller_info:
contrl_data = controller_info.get('data', {}).get('nodes', [])
for contrl in contrl_data:
status = constants.ControllerStatus.NORMAL if \
contrl.get('state') == 'online' else \
constants.ControllerStatus.UNKNOWN
controller_result = {
'name': contrl.get('id'),
'storage_id': self.storage_id,
'native_controller_id': contrl.get('id'),
'status': status
}
controller_list.append(controller_result)
return controller_list

def add_trap_config(self, context, trap_config):
pass

def remove_trap_config(self, context, trap_config):
pass

@staticmethod
def parse_alert(context, alert):
pass

def clear_alert(self, context, alert):
pass

@staticmethod
def get_access_url():
return 'https://{ip}:{port}'
Loading

0 comments on commit 73c98e4

Please sign in to comment.