Skip to content

Commit 0861f4a

Browse files
committed
Add support for NVMe host
1 parent 1968e71 commit 0861f4a

File tree

6 files changed

+179
-1
lines changed

6 files changed

+179
-1
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.vscode
2+
__pycache__
3+
4+
# pytest coverage
5+
.coverage
6+
htmlcov

PyPowerFlex/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class PowerFlexClient:
4949
'service_template',
5050
'managed_device',
5151
'deployment',
52-
'firmware_repository'
52+
'firmware_repository',
53+
'host'
5354
)
5455

5556
def __init__(self,
@@ -102,6 +103,7 @@ def initialize(self):
102103
self.__add_storage_entity('managed_device', objects.ManagedDevice)
103104
self.__add_storage_entity('deployment', objects.Deployment)
104105
self.__add_storage_entity('firmware_repository', objects.FirmwareRepository)
106+
self.__add_storage_entity('host', objects.Host)
105107
utils.init_logger(self.configuration.log_level)
106108
if version.parse(self.system.api_version()) < version.Version('3.0'):
107109
raise exceptions.PowerFlexClientException(

PyPowerFlex/base_client.py

+14
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,17 @@ def _query_selected_statistics(self, action, params=None):
370370
LOG.error(exc.message)
371371
raise exc
372372
return response
373+
374+
def _modify_entity(self, action, sdc_id, params):
375+
r, response = self.send_post_request(self.base_action_url,
376+
action=action,
377+
entity=self.entity,
378+
entity_id=sdc_id,
379+
params=params)
380+
if r.status_code != requests.codes.ok:
381+
exc = exceptions.PowerFlexFailRenaming(self.entity, sdc_id,
382+
response)
383+
LOG.error(exc.message)
384+
raise exc
385+
386+
return self.get(entity_id=sdc_id)

PyPowerFlex/objects/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from PyPowerFlex.objects.managed_device import ManagedDevice
3232
from PyPowerFlex.objects.deployment import Deployment
3333
from PyPowerFlex.objects.firmware_repository import FirmwareRepository
34+
from PyPowerFlex.objects.host import Host
3435

3536

3637
__all__ = [
@@ -52,4 +53,5 @@
5253
'ManagedDevice',
5354
'Deployment',
5455
'FirmwareRepository',
56+
'Host',
5557
]

PyPowerFlex/objects/host.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Copyright (c) 2024 Dell Inc. or its subsidiaries.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
import logging
17+
from PyPowerFlex import base_client
18+
19+
20+
LOG = logging.getLogger(__name__)
21+
22+
class Host(base_client.EntityRequest):
23+
def create(self,
24+
nqn,
25+
name=None,
26+
max_num_paths=None,
27+
max_num_sys_ports=None):
28+
"""Create a new NVMe host.
29+
30+
:param nqn: NQN of the NVMe host
31+
:type nqn: str
32+
:param name: Name of the NVMe Host
33+
:type name: str
34+
:param maxNumPaths: Maximum Number of Paths Per Volume.
35+
:type maxNumPaths: str
36+
:param maxNumSysPorts: Maximum Number of Ports Per Protection Domain
37+
:type maxNumSysPorts: str
38+
:return: Created host
39+
:rtype: dict
40+
"""
41+
42+
params = dict(
43+
nqn=nqn,
44+
name=name,
45+
maxNumPaths=max_num_paths,
46+
maxNumSysPorts=max_num_sys_ports
47+
)
48+
49+
return self._create_entity(params)
50+
51+
def modify_max_num_paths(self, host_id, max_num_paths):
52+
"""Modify Maximum Number of Paths Per Volume.
53+
54+
:param host_id: ID of the SDC
55+
:type host_id: str
56+
:param max_num_paths: Maximum Number of Paths Per Volume.
57+
:type max_num_paths: str
58+
:return: result
59+
:rtype: dict
60+
"""
61+
62+
action = 'modifyMaxNumPaths'
63+
64+
params = dict(
65+
newMaxNumPaths=max_num_paths
66+
)
67+
68+
return self._perform_entity_operation_based_on_action(action=action,
69+
entity_id=host_id, params=params, add_entity=False)
70+
71+
def modify_max_num_sys_ports(self, host_id, max_num_sys_ports):
72+
"""Modify Maximum Number of Ports Per Protection Domain.
73+
74+
:param host_id: ID of the SDC
75+
:type host_id: str
76+
:param max_num_sys_ports: Maximum Number of Ports Per Protection Domain.
77+
:type max_num_sys_ports: str
78+
:return: result
79+
:rtype: dict
80+
"""
81+
82+
action = 'modifyMaxNumSysPorts'
83+
84+
params = dict(
85+
newMaxNumSysPorts=max_num_sys_ports
86+
)
87+
88+
return self._perform_entity_operation_based_on_action(action=action,
89+
entity_id=host_id, params=params, add_entity=False)

tests/test_host.py

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) 2024 Dell Inc. or its subsidiaries.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
from PyPowerFlex import exceptions
17+
import tests
18+
19+
20+
class TestHostClient(tests.PyPowerFlexTestCase):
21+
def setUp(self):
22+
super(TestHostClient, self).setUp()
23+
self.client.initialize()
24+
self.fake_host_id="1"
25+
self.fake_nqn = "nqn::"
26+
27+
self.MOCK_RESPONSES = {
28+
self.RESPONSE_MODE.Valid: {
29+
# create
30+
'/types/Host/instances': {'id': self.fake_host_id},
31+
'/instances/Host::{}'.format(self.fake_host_id):
32+
{'id': self.fake_host_id},
33+
'/instances/Host::{}'
34+
'/action/modifyMaxNumPaths'.format(self.fake_host_id): {},
35+
'/instances/Host::{}'
36+
'/action/modifyMaxNumSysPorts'.format(self.fake_host_id): {},
37+
}
38+
}
39+
40+
def test_sdc_host_create(self):
41+
self.client.host.create(self.fake_nqn, max_num_paths='8', max_num_sys_ports='8')
42+
43+
def test_sdc_host_create_bad_status(self):
44+
with self.http_response_mode(self.RESPONSE_MODE.BadStatus):
45+
self.assertRaises(exceptions.PowerFlexFailCreating,
46+
self.client.host.create, self.fake_nqn)
47+
def test_sdc_modify_max_num_paths(self):
48+
self.client.host.modify_max_num_paths(self.fake_host_id, max_num_paths='8')
49+
50+
def test_sdc_modify_max_num_paths_bad_status(self):
51+
with self.http_response_mode(self.RESPONSE_MODE.BadStatus):
52+
self.assertRaises(exceptions.PowerFlexFailEntityOperation,
53+
self.client.host.modify_max_num_paths,
54+
self.fake_host_id,
55+
max_num_paths='8')
56+
57+
def test_sdc_modify_max_num_sys_ports(self):
58+
self.client.host.modify_max_num_sys_ports(self.fake_host_id, max_num_sys_ports='8')
59+
60+
def test_sdc_modify_max_num_sys_ports_bad_status(self):
61+
with self.http_response_mode(self.RESPONSE_MODE.BadStatus):
62+
self.assertRaises(exceptions.PowerFlexFailEntityOperation,
63+
self.client.host.modify_max_num_sys_ports,
64+
self.fake_host_id,
65+
max_num_sys_ports='8')

0 commit comments

Comments
 (0)