Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add hitachi vsp storage driver to community #388

Merged
merged 44 commits into from
Nov 25, 2020
Merged

add hitachi vsp storage driver to community #388

merged 44 commits into from
Nov 25, 2020

Conversation

jiangyutan
Copy link
Contributor

@jiangyutan jiangyutan commented Nov 21, 2020

What this PR does / why we need it:
this PR is for hitachi vsp storage,it provide hitachi storage's information collect,such as system,pools,volumes,it support VSP F/G seriers,and VSP F/G 350,370,700,900 support get the alerts,other seriers do not support alerts For now.

Which issue this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close that issue when PR gets merged): fixes #

Special notes for your reviewer:

Release note:

@codecov
Copy link

codecov bot commented Nov 21, 2020

Codecov Report

Merging #388 (2f906a2) into v0.8.0-maint (068fcc8) will increase coverage by 0.12%.
The diff coverage is 67.10%.

@@               Coverage Diff                @@
##           v0.8.0-maint     #388      +/-   ##
================================================
+ Coverage         66.91%   67.04%   +0.12%     
================================================
  Files                90       93       +3     
  Lines              6399     6700     +301     
  Branches            748      784      +36     
================================================
+ Hits               4282     4492     +210     
- Misses             1872     1944      +72     
- Partials            245      264      +19     
Impacted Files Coverage Δ
delfin/drivers/hitachi/vsp/rest_handler.py 55.97% <55.97%> (ø)
delfin/drivers/hitachi/vsp/vsp_stor.py 75.30% <75.30%> (ø)
delfin/drivers/hitachi/vsp/consts.py 100.00% <100.00%> (ø)
delfin/ssl_utils.py 55.31% <0.00%> (+4.25%) ⬆️
delfin/drivers/utils/rest_client.py 59.70% <0.00%> (+5.97%) ⬆️
delfin/common/alert_util.py 86.20% <0.00%> (+6.89%) ⬆️

@@ -0,0 +1,220 @@
# Copyright 2020 The SODA Authors.
# Copyright (c) 2016 Huawei Technologies Co., Ltd.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove huawei copyright

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove d

@@ -0,0 +1,266 @@
# Copyright 2020 The SODA Authors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File name should be lower case with underscore.

Comment on lines 30 to 33
HDSVSP_SESSION_ID = None
STORAGE_DEVICE_ID = None
DEVICE_MODEL = None
SERIALNUMBER = None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these constants? Should these be member variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when login or get_device_id everytime,they will be refresh

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, so I think it should be member variables and should not be upper case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now changed them to member variables

.format(res.status_code, res.text))
# if method is logout,return immediately
if method == 'DELETE' and RestHandler.\
REST_LOGOUT_URL in url:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the definition of REST_LOGOUT_URL?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

elif res.status_code == 503:
raise exception.InvalidResults(res.text)
else:
LOG.error('Rest exec failed')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please give more details in this log about what rest command exec failed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have changed

raise exception.InvalidResults(err_msg)

def get_resinfo_call(self, url, data=None, method=None, resName=None):
rejson = None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local variable name rejson is not correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have changed

def logout(self):
try:
url = RestHandler.HDSVSP_LOGOUT_URL
if RestHandler.HDSVSP_SESSION_ID is not None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If RestHandler.HDSVSP_SESSION_ID is none, the url is RestHandler.HDSVSP_LOGOUT_URL, then we call delete of this url, what would happen? All the sessions would be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

def get_specific_storage(self):
url = '%s%s' % \
(RestHandler.HDSVSP_COMM_URL, RestHandler.STORAGE_DEVICE_ID)
rejson = self.get_resinfo_call(url,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local variable name should be imporved.
Please check all other local variable names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

LOG.error("Get device id error: %s", six.text_type(e))
raise e

def get_specific_storage(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be get_storage?

self.rest_client = RestClient(**kwargs)
self.rest_handler = rest_handler.RestHandler(self.rest_client)
self.rest_handler.get_device_id()
self.rest_handler.login()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that everytime login() was called, get_device_id() need be called at first, so would it be better to put get_device_id() into login()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_device_id() need at the first time,becuase we need device_id,when the session overdue and login again,we do not need get device again

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

rejson = None
res = self.call(url, data, method)
if res is not None:
if res.status_code == consts.SUCCESS_STATUS_CODES:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to assign SUCCESS_STATUS_CODES to status_code manually?
res should have its own status_code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed


if res is None:
LOG.error('Login res is None')
raise exception.InvalidResults('res is None')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What res is None? And it should be started with capital letter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

ERROR_SESSION_INVALID_CODE = 403
ERROR_SESSION_IS_BEING_USED_CODE = 409
SUCCESS_STATUS_CODES = 200
# block size
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems to be meaningless.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUCCESS_STATUS_CODES changed


HDSVSP_AUTH_KEY = 'Authorization'

def __init__(self, restclient):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restclient should be rest_client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

# 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.
ERROR_CONNECT_TO_SERVER = -403
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR_CONNECT_TO_SERVER and LOGIN_SOCKET_TIMEOUT not used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

LOG.error(err_msg)
raise exception.InvalidResults(err_msg)

def get_resinfo_call(self, url, data=None, method=None, resName=None):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function is going to 'get' resource info, should the method always be 'GET'?
If the method always be 'GET', we do not need to set method as parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not always 'GET'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked that,get_resinfo_call just is GET,have changed


def __init__(self, **kwargs):
super().__init__(**kwargs)
self.rest_client = RestClient(**kwargs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One doubt.
HdsVspDriver have rest_client and rest_handler, and rest_handler has rest_client, so when should HdsVspDriver use rest_client and when use rest_handler? What the difference between rest_client and rest_handler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest_handler will use rest_client,and in HdsVspDriver, i init rest_client first and init rest_handler with it to rest_handler,it's a same rest_client

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest_client just do rest init, http request,rest_handler do bussiness

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but for a storage driver, only one rest object is enough, two object for rest would confuse other developers.
If rest_handler already has rest_client, would it be better that not operate rest_client directly anymore?
Or we can make rest_handler a sub class of rest_client, so it can has all the method what rest_client has.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

if pools_info is not None:
pools = pools_info.get('data')
else:
return pool_list
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch meanings some error during get_all_pools()? Or some other means?
I'm concerning about that, if I got a empty list from list_storage_pools(), it means actually there is no pool or met some issue during querying pool info?
Same for list_volumes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes,there may be met some issue during querying pool info,so i return a empty list

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So when I get an empty list from list_storage_pools, how can I know whether it has no pool or it has pools but I met some issue when querying?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

from delfin.drivers.hitachi.vsp.rest_handler import RestHandler
from delfin.drivers.hitachi.vsp.vsp_stor import HitachiVspDriver
from delfin.drivers.utils.rest_client import RestClient
from requests import Session
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why move this import sentence to this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

LOG = logging.getLogger(__name__)


class RestHandler(RestClient):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this new class and why can't the existing res_client util be used/enhanced?

used_total = total_total - free_total
else:
free_total = 0
total_total = 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we think of some better variable name? like total_total -> total_capacity or total_raw_cap

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

'description': 'Hitachi VSP Pool',
'status': status,
'storage_type': storage_type,
'subscribed_capacity': int(total_cap),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come total_cap and subscribed_Cap be same?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to this comment?

volume_list = []
volumes = volumes_info.get('data')
for volume in volumes:
if volume.get('emulationType') == 'NOT DEFINED':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a volume doesn't have emulation type, where will be the capacity or storage be accounted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in hitachi rest api of the volume,there always have emulationType

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then what is this 'NOT DEFINED?


total_cap = \
int(volume.get('blockCapacity')) * consts.BLOCK_SIZE
used_cap = \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to screw the storage report. Used_cap and total_cap is same so free_cap is 0 always.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making free =0 may be true for a thick , because total_capacity=allocated_capacity (which is used from the perspective of array). but there should be a beeter way to update this for a thin volume. please check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes,i kown that,but there is no used_capacity or free_capacity

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for thin devices, won't the Storage Summary report be affected by this?


return alert_list

def add_trap_config(self, context, trap_config):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put a TODO if it has to be implemented later, else put comment

ERROR_SESSION_IS_BEING_USED_CODE = 409
BLOCK_SIZE = 512

VSP_FXXX_GXXX_SERIES = ('VSP G350', 'VSP G370', 'VSP G700', 'VSP G900',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VSP_F_G_SERIES is better for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there also have like F200,G200 they are different

self.rest_handler.login()

def reset_connection(self, context, **kwargs):
self.rest_handler.logout()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verify should be updated before login

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified accessing with the certificate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not yet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

completed

delfin/drivers/hitachi/vsp/rest_handler.py Outdated Show resolved Hide resolved
delfin/drivers/hitachi/vsp/rest_handler.py Show resolved Hide resolved
delfin/drivers/hitachi/vsp/rest_handler.py Outdated Show resolved Hide resolved
'raw_capacity': int(total_capacity),
'total_capacity': int(total_capacity),
'used_capacity': int(total_capacity - free_capacity),
'free_capacity': int(free_capacity)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it provide subscribed capacity?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, nit provide


total_cap = \
int(volume.get('blockCapacity')) * consts.BLOCK_SIZE
used_cap = \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making free =0 may be true for a thick , because total_capacity=allocated_capacity (which is used from the perspective of array). but there should be a beeter way to update this for a thin volume. please check.

ERROR_SESSION_IS_BEING_USED_CODE = 409
BLOCK_SIZE = 512

VSP_F_G_350_370_700_900_SERIES = ('VSP G350', 'VSP G370', 'VSP G700',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to SUPPORTED_VSP_SERIES

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

delfin/drivers/hitachi/vsp/rest_handler.py Outdated Show resolved Hide resolved
Copy link
Member

@NajmudheenCT NajmudheenCT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wisererik wisererik merged commit ae88070 into sodafoundation:v0.8.0-maint Nov 25, 2020
@kumarashit
Copy link
Collaborator

I still see the comments not addressed. What is the plan for it?

Copy link
Collaborator

@kumarashit kumarashit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to address the comments before merging?

joseph-v pushed a commit to joseph-v/delfin that referenced this pull request Dec 23, 2020
joseph-v pushed a commit to joseph-v/delfin that referenced this pull request Dec 23, 2020
kumarashit pushed a commit that referenced this pull request Jan 2, 2021
* Code improvement (#363)

* ibm storwize_svc add sshpool and fixed some issue (#381)

Add storage driver for IBM Storwize and svc series

* add hitachi vsp storage driver to community (#388)

Add hitachi vsp driver

* Fix vsp driver issue

* change pool status and some optimize for vsp (#395)

* rest api change timeout and fix trap parse (#401)

* fix ssh excption error when the port is wrong and do some optimize (#402)

* Update the value of 'update_at' of storage when going to sync the storage (#425)

* Code improvement (#363)

* ibm storwize_svc add sshpool and fixed some issue (#381)

Add storage driver for IBM Storwize and svc series

* add hitachi vsp storage driver to community (#388)

Add hitachi vsp driver

* Fix vsp driver issue

* change pool status and some optimize for vsp (#395)

* rest api change timeout and fix trap parse (#401)

* fix ssh excption error when the port is wrong and do some optimize (#402)

* Update the value of 'update_at' of storage when going to sync the storage (#425)

* Fix rebase issue

* Fixing CI failure issues

Co-authored-by: ThisIsClark <liuyuchibubao@gmail.com>
Co-authored-by: jiangyutan <69443713+jiangyutan@users.noreply.github.com>
Co-authored-by: Joseph Vazhappilly <josephvp@gmail.com>
Co-authored-by: root <pravin ranjan>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants