Merge "Redfish: Adds 'reset_ilo_credential' for redfish systems"
This commit is contained in:
commit
c2523811e4
|
@ -76,6 +76,7 @@ SUPPORTED_REDFISH_METHODS = [
|
|||
'set_one_time_boot',
|
||||
'update_persistent_boot',
|
||||
'set_pending_boot_mode',
|
||||
'reset_ilo_credential',
|
||||
]
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
|
|
@ -16,6 +16,7 @@ __author__ = 'HPE'
|
|||
|
||||
import sushy
|
||||
|
||||
from proliantutils.redfish.resources.account_service import account_service
|
||||
from proliantutils.redfish.resources.manager import manager
|
||||
from proliantutils.redfish.resources.system import system
|
||||
from proliantutils.redfish.resources import update_service
|
||||
|
@ -63,3 +64,12 @@ class HPESushy(sushy.Sushy):
|
|||
return (update_service.
|
||||
HPEUpdateService(self._conn, update_service_url,
|
||||
redfish_version=self.redfish_version))
|
||||
|
||||
def get_account_service(self):
|
||||
"""Return a HPEAccountService object"""
|
||||
account_service_url = utils.get_subresource_path_by(self,
|
||||
'AccountService')
|
||||
|
||||
return (account_service.
|
||||
HPEAccountService(self._conn, account_service_url,
|
||||
redfish_version=self.redfish_version))
|
||||
|
|
|
@ -117,6 +117,7 @@ class RedfishOperations(operations.IloOperations):
|
|||
# for error reporting purpose
|
||||
self.host = redfish_controller_ip
|
||||
self._root_prefix = root_prefix
|
||||
self._username = username
|
||||
|
||||
try:
|
||||
self._sushy = main.HPESushy(
|
||||
|
@ -570,3 +571,25 @@ class RedfishOperations(operations.IloOperations):
|
|||
{'device': device, 'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def reset_ilo_credential(self, password):
|
||||
"""Resets the iLO password.
|
||||
|
||||
:param password: The password to be set.
|
||||
:raises: IloError, if account not found or on an error from iLO.
|
||||
"""
|
||||
try:
|
||||
acc_service = self._sushy.get_account_service()
|
||||
member = acc_service.accounts.get_member_details(self._username)
|
||||
if member is None:
|
||||
msg = (self._("No account found with username: %s")
|
||||
% self._username)
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
member.update_credentials(password)
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._('The Redfish controller failed to update '
|
||||
'credentials for %(username)s. Error %(error)s') %
|
||||
{'username': self._username, 'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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.
|
||||
|
||||
__author__ = 'HPE'
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
|
||||
class HPEAccount(base.ResourceBase):
|
||||
|
||||
username = base.Field('UserName')
|
||||
|
||||
def update_credentials(self, password):
|
||||
"""Update credentials of a redfish system
|
||||
|
||||
:param password: password to be updated
|
||||
"""
|
||||
data = {
|
||||
'Password': password,
|
||||
}
|
||||
self._conn.patch(self.path, data=data)
|
||||
|
||||
|
||||
class HPEAccountCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return HPEAccount
|
||||
|
||||
def get_member_details(self, username):
|
||||
"""Returns the HPEAccount object
|
||||
|
||||
:param username: username of account
|
||||
:returns: HPEAccount object if criterion matches, None otherwise
|
||||
"""
|
||||
members = self.get_members()
|
||||
for member in members:
|
||||
if member.username == username:
|
||||
return member
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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 sushy.resources import base
|
||||
|
||||
from proliantutils.redfish.resources.account_service import account
|
||||
from proliantutils.redfish import utils
|
||||
|
||||
|
||||
class HPEAccountService(base.ResourceBase):
|
||||
"""Class that extends the functionality of AccountService resource class
|
||||
|
||||
This class extends the functionality of Account resource class
|
||||
from sushy
|
||||
"""
|
||||
|
||||
_accounts = None
|
||||
|
||||
@property
|
||||
def accounts(self):
|
||||
"""Property to provide instance of HPEAccountCollection
|
||||
|
||||
"""
|
||||
if self._accounts is None:
|
||||
self._accounts = account.HPEAccountCollection(
|
||||
self._conn, utils.get_subresource_path_by(self, 'Accounts'),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._accounts
|
||||
|
||||
def refresh(self):
|
||||
super(HPEAccountService, self).refresh()
|
||||
self._accounts = None
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#AccountService/Accounts/Members/$entity",
|
||||
"@odata.etag": "W/\"BA0D308D\"",
|
||||
"@odata.id": "/redfish/v1/AccountService/Accounts/1/",
|
||||
"@odata.type": "#ManagerAccount.v1_0_0.ManagerAccount",
|
||||
"Description": "iLO User Account",
|
||||
"Id": "1",
|
||||
"Name": "User Account",
|
||||
"Oem":
|
||||
{
|
||||
"Hpe":
|
||||
{
|
||||
"@odata.type": "#HpeiLOAccount.v2_0_0.HpeiLOAccount",
|
||||
"LoginName": "foo",
|
||||
"Privileges":
|
||||
{
|
||||
"HostBIOSConfigPriv": true,
|
||||
"HostNICConfigPriv": true,
|
||||
"HostStorageConfigPriv": true,
|
||||
"LoginPriv": true,
|
||||
"RemoteConsolePriv": true,
|
||||
"SystemRecoveryConfigPriv": true,
|
||||
"UserConfigPriv": true,
|
||||
"VirtualMediaPriv": true,
|
||||
"VirtualPowerAndResetPriv": true,
|
||||
"iLOConfigPriv": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserName": "foo"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Accounts",
|
||||
"@odata.etag": "W/\"72D11D4D\"",
|
||||
"@odata.id": "/redfish/v1/AccountService/Accounts/",
|
||||
"@odata.type": "#ManagerAccountCollection.ManagerAccountCollection",
|
||||
"Description": "iLO User Accounts",
|
||||
"Members":
|
||||
[
|
||||
{
|
||||
"@odata.id": "/redfish/v1/AccountService/Accounts/1/"
|
||||
}
|
||||
],
|
||||
"Members@odata.count": 1,
|
||||
"Name": "Accounts"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#AccountService",
|
||||
"@odata.etag": "W/\"677A002B\"",
|
||||
"@odata.id": "/redfish/v1/AccountService/",
|
||||
"@odata.type": "#AccountService.v1_0_2.AccountService",
|
||||
"Accounts":
|
||||
{
|
||||
"@odata.id": "/redfish/v1/AccountService/Accounts/"
|
||||
},
|
||||
"Description": "iLO User Accounts",
|
||||
"Id": "AccountService",
|
||||
"Name": "Account Service",
|
||||
"Oem":
|
||||
{
|
||||
"Hpe":
|
||||
{
|
||||
"@odata.type": "#HpeiLOAccountService.v2_0_0.HpeiLOAccountService",
|
||||
"AuthFailureDelayTimeSeconds": 10,
|
||||
"AuthFailureLoggingThreshold": 3,
|
||||
"AuthFailuresBeforeDelay": 1,
|
||||
"MinPasswordLength": 8
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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.
|
||||
|
||||
__author__ = 'HPE'
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from proliantutils.redfish.resources.account_service import account
|
||||
|
||||
|
||||
class HPEAccountCollectionTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(HPEAccountCollectionTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read()))
|
||||
|
||||
self.account_coll_obj = account.HPEAccountCollection(
|
||||
self.conn, '/redfish/v1/AccountService/Accounts',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test_get_member_details(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read()))
|
||||
|
||||
obj = self.account_coll_obj.get_member_details('foo')
|
||||
self.assertIsInstance(obj, account.HPEAccount)
|
||||
self.assertIsNone(self.account_coll_obj.get_member_details('bar'))
|
||||
|
||||
|
||||
class HPEAccountTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(HPEAccountTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account.json', 'r') as f:
|
||||
account_json = json.loads(f.read())
|
||||
|
||||
self.conn.get.return_value.json.return_value = account_json
|
||||
|
||||
self.acc_inst = account.HPEAccount(
|
||||
self.conn, '/redfish/v1/AccountService/Accounts/1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test_attributes(self):
|
||||
self.assertEqual('foo', self.acc_inst.username)
|
||||
|
||||
def test_update_credentials(self):
|
||||
target_uri = '/redfish/v1/AccountService/Accounts/1'
|
||||
self.acc_inst.update_credentials('fake-password')
|
||||
self.acc_inst._conn.patch.assert_called_once_with(
|
||||
target_uri, data={'Password': 'fake-password'})
|
|
@ -0,0 +1,67 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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.
|
||||
|
||||
__author__ = 'HPE'
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from proliantutils.redfish.resources.account_service import account
|
||||
from proliantutils.redfish.resources.account_service import account_service
|
||||
|
||||
|
||||
class HPEAccountServiceTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(HPEAccountServiceTestCase, self).setUp()
|
||||
self.conn = mock.MagicMock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.acc_inst = account_service.HPEAccountService(
|
||||
self.conn, '/redfish/v1/AccountService',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test_accounts(self):
|
||||
self.assertIsNone(self.acc_inst._accounts)
|
||||
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
accounts = self.acc_inst.accounts
|
||||
self.assertIsInstance(accounts, account.HPEAccountCollection)
|
||||
|
||||
def test_accounts_on_refresh(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
accounts = self.acc_inst.accounts
|
||||
self.assertIsInstance(accounts, account.HPEAccountCollection)
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.acc_inst.refresh()
|
||||
self.assertIsNone(self.acc_inst._accounts)
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.assertIsInstance(accounts, account.HPEAccountCollection)
|
|
@ -21,6 +21,7 @@ import testtools
|
|||
|
||||
from proliantutils import exception
|
||||
from proliantutils.redfish import main
|
||||
from proliantutils.redfish.resources.account_service import account_service
|
||||
from proliantutils.redfish.resources.manager import manager
|
||||
from proliantutils.redfish.resources.system import system
|
||||
from proliantutils.redfish.resources import update_service
|
||||
|
@ -88,3 +89,12 @@ class HPESushyTestCase(testtools.TestCase):
|
|||
mock_update_service.assert_called_once_with(
|
||||
self.hpe_sushy._conn, "/redfish/v1/UpdateService/",
|
||||
self.hpe_sushy.redfish_version)
|
||||
|
||||
@mock.patch.object(account_service, 'HPEAccountService', autospec=True)
|
||||
def test_get_account_service(self, mock_account_service):
|
||||
acc_inst = self.hpe_sushy.get_account_service()
|
||||
self.assertIsInstance(acc_inst,
|
||||
account_service.HPEAccountService.__class__)
|
||||
mock_account_service.assert_called_once_with(
|
||||
self.hpe_sushy._conn, "/redfish/v1/AccountService/",
|
||||
self.hpe_sushy.redfish_version)
|
||||
|
|
|
@ -22,6 +22,8 @@ import testtools
|
|||
from proliantutils import exception
|
||||
from proliantutils.redfish import main
|
||||
from proliantutils.redfish import redfish
|
||||
from proliantutils.redfish.resources.account_service import account
|
||||
from proliantutils.redfish.resources.account_service import account_service
|
||||
from proliantutils.redfish.resources.manager import manager
|
||||
from proliantutils.redfish.resources.manager import virtual_media
|
||||
from proliantutils.redfish.resources.system import constants as sys_cons
|
||||
|
@ -573,3 +575,73 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
'The Redfish controller failed to set one time boot.',
|
||||
self.rf_client.set_one_time_boot,
|
||||
'CDROM')
|
||||
|
||||
def _setup_reset_ilo_credential(self):
|
||||
self.conn = mock.Mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
account_mock = account_service.HPEAccountService(
|
||||
self.conn, '/redfish/v1/AccountService',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account_collection.json', 'r') as f:
|
||||
account_collection_json = json.loads(f.read())
|
||||
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/account.json', 'r') as f:
|
||||
account_json = json.loads(f.read())
|
||||
|
||||
return account_mock, account_collection_json, account_json
|
||||
|
||||
@mock.patch.object(main.HPESushy, 'get_account_service')
|
||||
def test_reset_ilo_credential(self, account_mock):
|
||||
account_mock.return_value, account_collection_json, account_json = (
|
||||
self._setup_reset_ilo_credential())
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
account_collection_json, account_json]
|
||||
|
||||
self.rf_client.reset_ilo_credential('fake-password')
|
||||
(self.sushy.get_account_service.return_value.
|
||||
accounts.get_member_details.return_value.
|
||||
update_credentials.assert_called_once_with('fake-password'))
|
||||
|
||||
@mock.patch.object(main.HPESushy, 'get_account_service')
|
||||
def test_reset_ilo_credential_fail(self, account_mock):
|
||||
account_mock.return_value, account_collection_json, account_json = (
|
||||
self._setup_reset_ilo_credential())
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
account_collection_json, account_json]
|
||||
|
||||
(self.sushy.get_account_service.return_value.accounts.
|
||||
get_member_details.return_value.
|
||||
update_credentials.side_effect) = sushy.exceptions.SushyError
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError,
|
||||
'The Redfish controller failed to update credentials',
|
||||
self.rf_client.reset_ilo_credential, 'fake-password')
|
||||
|
||||
@mock.patch.object(account.HPEAccount, 'update_credentials')
|
||||
def test_reset_ilo_credential_get_account_service_fail(self, update_mock):
|
||||
account_service_not_found_error = sushy.exceptions.SushyError
|
||||
account_service_not_found_error.message = (
|
||||
'HPEAccountService not found!!')
|
||||
self.sushy.get_account_service.side_effect = (
|
||||
account_service_not_found_error)
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError,
|
||||
'The Redfish controller failed to update credentials for foo. '
|
||||
'Error HPEAccountService not found!!',
|
||||
self.rf_client.reset_ilo_credential, 'fake-password')
|
||||
self.assertFalse(update_mock.called)
|
||||
|
||||
@mock.patch.object(main.HPESushy, 'get_account_service')
|
||||
def test_reset_ilo_credential_no_member(self, account_mock):
|
||||
(self.sushy.get_account_service.return_value.accounts.
|
||||
get_member_details.return_value) = None
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError,
|
||||
'No account found with username: foo',
|
||||
self.rf_client.reset_ilo_credential, 'fake-password')
|
||||
|
|
Loading…
Reference in New Issue