Sending OneView Client implementation

Co-Authored-By: Alberto Barros <albertoffb@lsd.ufcg.edu.br>
Co-Authored-By: André Aranha <afaranha@lsd.ufcg.edu.br>
Co-Authored-By: Caio Oliveira <caiobo@lsd.ufcg.edu.br>
Co-Authored-By: Diego Pereira <diegolp@lsd.ufcg.edu.br>
Co-Authored-By: Gabriel Bezerra <gabrielb@lsd.ufcg.edu.br>
Co-Authored-By: Lilia Sampaio <liliars@lsd.ufcg.edu.br>
Co-Authored-By: Thiago Paiva <thiagop@lsd.ufcg.edu.br>

Change-Id: I8c7457157f6d5a2599cccb9e86be240fc4283767
This commit is contained in:
Sinval Vieira 2015-08-13 21:18:15 +00:00 committed by Sinval Neto
parent fd754e26f2
commit 74cb42f9b4
10 changed files with 1273 additions and 64 deletions

View File

@ -1,16 +1,19 @@
# -*- coding: utf-8 -*-
# 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
# -*- encoding: utf-8 -*-
#
# http://www.apache.org/licenses/LICENSE-2.0
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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.
# 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 pbr.version

492
oneview_client/client.py Normal file
View File

@ -0,0 +1,492 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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 json
import time
import requests
import retrying
from oneview_client import exceptions
from oneview_client import states
SUPPORTED_ONEVIEW_VERSION = 200
WAIT_DO_REQUEST_IN_MILLISECONDS = 100
WAIT_TASK_IN_MILLISECONDS = 1000
GET_REQUEST_TYPE = 'GET'
PUT_REQUEST_TYPE = 'PUT'
POST_REQUEST_TYPE = 'POST'
DELETE_REQUEST_TYPE = 'DELETE'
MOMENTARY_PRESS = 'MomentaryPress'
PRESS_AND_HOLD = 'PressAndHold'
class Client(object):
def __init__(
self, manager_url, username, password,
allow_insecure_connections=False, tls_cacert_file='',
max_polling_attempts=20
):
self.manager_url = manager_url
self.username = username
self.password = password
self.allow_insecure_connections = allow_insecure_connections
self.tls_cacert_file = tls_cacert_file
self.max_polling_attempts = max_polling_attempts
self.session_id = self.get_session()
def get_session(self):
response = self._authenticate()
return response.json().get('sessionID')
def _authenticate(self):
url = '%s/rest/login-sessions' % self.manager_url
body = {
'userName': self.username,
'password': self.password
}
headers = {
'content-type': 'application/json'
}
verify_ssl = self._get_verify_connection_option()
r = requests.post(url,
data=json.dumps(body),
headers=headers,
verify=verify_ssl)
if r.status_code == 401:
raise exceptions.OneViewNotAuthorizedException()
else:
return r
def _get_verify_connection_option(self):
verify_status = False
user_cacert = self.tls_cacert_file
if self.allow_insecure_connections is False:
if not user_cacert:
verify_status = True
else:
verify_status = user_cacert
return verify_status
def verify_oneview_version(self):
if not self._is_oneview_version_compatible():
raise exceptions.IncompatibleOneViewAPIVersion(
"The version of the OneView's API is unsupported. Supported "
"version is '%s'" % SUPPORTED_ONEVIEW_VERSION)
def _is_oneview_version_compatible(self):
versions = self.get_oneview_version()
v = SUPPORTED_ONEVIEW_VERSION
min_version_compatible = versions.get('minimumVersion') <= v
max_version_compatible = versions.get("currentVersion") >= v
return min_version_compatible and max_version_compatible
def get_oneview_version(self):
url = '%s/rest/version' % self.manager_url
headers = {"Accept-Language": "en_US"}
verify_ssl = self._get_verify_connection_option()
try:
versions = requests.get(
url, headers=headers, verify=verify_ssl
).json()
return versions
except requests.RequestException as e:
raise exceptions.OneViewConnectionError(e.message)
# --- Power Driver ---
def get_node_power_state(self, node_info):
server_hardware_json = self.get_server_hardware(node_info)
power_state = server_hardware_json.get('powerState')
return power_state
def power_on(self, node_info):
if self.get_node_power_state(node_info) == states.ONEVIEW_POWER_ON:
ret = states.ONEVIEW_POWER_ON
else:
ret = self.set_node_power_state(
node_info, states.ONEVIEW_POWER_ON
)
return ret
def power_off(self, node_info):
if self.get_node_power_state(node_info) == states.ONEVIEW_POWER_OFF:
ret = states.ONEVIEW_POWER_OFF
else:
ret = self.set_node_power_state(
node_info, states.ONEVIEW_POWER_OFF, PRESS_AND_HOLD
)
return ret
def set_node_power_state(
self, node_info, state, press_type=MOMENTARY_PRESS
):
body = {'powerState': state, 'powerControl': press_type}
power_state_uri = (node_info.get('server_hardware_uri') +
'/powerState')
task = self._prepare_and_do_request(
uri=power_state_uri, body=body, request_type=PUT_REQUEST_TYPE
)
try:
self._wait_for_task_to_complete(task)
except exceptions.OneViewTaskError as e:
raise exceptions.OneViewErrorStateSettingPowerState(e.message)
current_state = self.get_node_power_state(node_info)
if current_state is states.ONEVIEW_ERROR:
message = (
"Error setting node power state to %(state)s" %
{"state": state}
)
raise exceptions.OneViewErrorStateSettingPowerState(message)
return current_state
# --- ManagementDriver ---
def get_server_hardware(self, node_info):
server_hardware_uri = node_info.get('server_hardware_uri')
server_hardware_json = self._prepare_and_do_request(
uri=server_hardware_uri
)
if server_hardware_json.get("uri") is None:
message = "OneView Server Hardware resource not found."
raise exceptions.OneViewResourceNotFoundError(message)
return server_hardware_json
def get_server_profile_from_hardware(self, node_info):
server_hardware_json = self.get_server_hardware(node_info)
server_profile_uri = server_hardware_json.get("serverProfileUri")
if server_profile_uri is None:
message = (
"There is no server profile assigned to"
" %(server_hardware_uri)s" %
{'server_hardware_uri': node_info.get('server_hardware_uri')}
)
raise exceptions.OneViewServerProfileAssociatedError(message)
server_profile_json = self._prepare_and_do_request(
uri=server_profile_uri
)
if server_profile_json.get("uri") is None:
message = "OneView Server Profile resource not found."
raise exceptions.OneViewResourceNotFoundError(message)
return server_profile_json
def get_server_profile_template(self, node_info):
server_profile_template_uri = (
node_info.get('server_profile_template_uri')
)
server_profile_template_json = self._prepare_and_do_request(
uri=server_profile_template_uri, request_type=GET_REQUEST_TYPE
)
if server_profile_template_json.get("uri") is None:
message = "OneView Server Profile Template resource not found."
raise exceptions.OneViewResourceNotFoundError(message)
return server_profile_template_json
def get_boot_order(self, node_info):
server_profile_json = self.get_server_profile_from_hardware(
node_info
)
return server_profile_json.get("boot").get("order")
def _make_boot_order_body(self, server_profile_dict, order):
manageBoot = server_profile_dict.get("boot").get("manageBoot")
server_profile_dict["boot"] = {
"manageBoot": manageBoot,
"order": order
}
return server_profile_dict
def set_boot_device(self, node_info, new_primary_boot_device):
boot_order = self.get_boot_order(node_info)
if new_primary_boot_device is None:
raise exceptions.OneViewBootDeviceInvalidError()
if new_primary_boot_device in boot_order:
boot_order.remove(new_primary_boot_device)
boot_order.insert(0, new_primary_boot_device)
server_profile_dict = self.get_server_profile_from_hardware(
node_info
)
boot_order_body = self._make_boot_order_body(
server_profile_dict,
boot_order
)
task = self._prepare_and_do_request(
uri=server_profile_dict.get('uri'), body=boot_order_body,
request_type=PUT_REQUEST_TYPE
)
try:
self._wait_for_task_to_complete(task)
except exceptions.OneViewTaskError as e:
raise exceptions.OneViewErrorSettingBootDevice(e.message)
# ---- Node validate ----
def validate_node_server_hardware(
self, node_info, node_memorymb, node_cpus
):
node_sh_uri = node_info.get('server_hardware_uri')
server_hardware_json = self.get_server_hardware(node_info)
server_hardware_memorymb = server_hardware_json.get('memoryMb')
server_hardware_cpus = (server_hardware_json.get('processorCoreCount')
* server_hardware_json.get('processorCount'))
if server_hardware_memorymb != node_memorymb:
message = (
"Node memory_mb is inconsistent with OneView's"
" server hardware %(server_hardware_uri)s memoryMb. Node"
" validation failed." % {'server_hardware_uri': node_sh_uri}
)
raise exceptions.OneViewInconsistentResource(message)
elif server_hardware_cpus != node_cpus:
message = (
"Node cpus is inconsistent with OneView's"
" server hardware %(server_hardware_uri)s cpus. Node"
" validation failed." % {'server_hardware_uri': node_sh_uri}
)
raise exceptions.OneViewInconsistentResource(message)
def validate_node_server_hardware_type(self, node_info):
node_sht_uri = node_info.get('server_hardware_type_uri')
server_hardware = self.get_server_hardware(node_info)
server_hardware_sht_uri = server_hardware.get('serverHardwareTypeUri')
if server_hardware_sht_uri != node_sht_uri:
message = (
"Node server_hardware_type_uri is inconsistent"
" with OneView's server hardware %(server_hardware_uri)s"
" serverHardwareTypeUri. Node validation failed." %
{'server_hardware_uri': node_info.get('server_hardware_uri')}
)
raise exceptions.OneViewInconsistentResource(message)
def check_server_profile_is_applied(self, node_info):
self.get_server_profile_from_hardware(node_info)
def validate_node_enclosure_group(self, node_info):
server_hardware = self.get_server_hardware(node_info)
sh_enclosure_group_uri = server_hardware.get('serverGroupUri')
node_enclosure_group_uri = node_info.get('enclosure_group_uri')
if node_enclosure_group_uri is not '':
if sh_enclosure_group_uri != node_enclosure_group_uri:
message = (
"Node enclosure_group_uri is inconsistent"
" with OneView's server hardware %(server_hardware_uri)s"
" serverGroupUri. Node validation failed." %
{'server_hardware_uri': node_info.
get('server_hardware_uri')}
)
raise exceptions.OneViewInconsistentResource(message)
def is_node_port_mac_compatible_with_server_profile(
self, node_info, ports
):
server_profile_json = self.get_server_profile_from_hardware(
node_info
)
primary_boot_connection = None
for connection in server_profile_json.get('connections'):
if connection.get('boot').get('priority') == 'Primary':
primary_boot_connection = connection
if primary_boot_connection is None:
message = (
"No primary boot connection configured for server profile"
" %s Node validation failed." % server_profile_json.get('uri')
)
raise exceptions.OneViewInconsistentResource(message)
server_profile_mac = primary_boot_connection.get('mac')
is_mac_address_compatible = True
for port in ports:
if port.__dict__.get('_obj_address').lower() != \
server_profile_mac.lower():
is_mac_address_compatible = False
if (not is_mac_address_compatible) or len(ports) == 0:
message = (
"The ports of the node are not compatible with its"
" server profile %(server_profile_uri)s. Node validation"
" failed." %
{'server_profile_uri': server_profile_json.get('uri')}
)
raise exceptions.OneViewInconsistentResource(message)
def validate_node_server_profile_template(self, node_info):
node_spt_uri = node_info.get('server_profile_template_uri')
server_profile_template_json = self.get_server_profile_template(
node_info
)
spt_server_hardware_type_uri = server_profile_template_json \
.get('serverHardwareTypeUri')
spt_enclosure_group_uri = server_profile_template_json \
.get('enclosureGroupUri')
server_hardware_json = self.get_server_hardware(node_info)
sh_server_hardware_type_uri = server_hardware_json \
.get('serverHardwareTypeUri')
sh_enclosure_group_uri_uri = server_hardware_json \
.get('serverGroupUri')
if spt_server_hardware_type_uri != sh_server_hardware_type_uri:
message = (
"Server profile template %(spt_uri)s serverHardwareTypeUri is"
" inconsistent with server hardware %(server_hardware_uri)s"
" serverHardwareTypeUri. Node validation failed." %
{'spt_uri': node_spt_uri,
'server_hardware_uri': node_info.get('server_hardware_uri')}
)
raise exceptions.OneViewInconsistentResource(message)
if spt_enclosure_group_uri != sh_enclosure_group_uri_uri:
message = (
"Server profile template %(spt_uri)s enclosureGroupUri is"
" inconsistent with server hardware %(server_hardware_uri)s"
" serverGroupUri. Node validation failed." %
{'spt_uri': node_spt_uri,
'server_hardware_uri': node_info.get('server_hardware_uri')}
)
raise exceptions.OneViewInconsistentResource(message)
# --- Requests ---
def _prepare_and_do_request(
self, uri, body={}, request_type=GET_REQUEST_TYPE
):
json_response = {}
try:
if not self.session_id:
self.session_id = self.get_session()
headers = {
'content-type': 'application/json',
'X-Api-Version': SUPPORTED_ONEVIEW_VERSION,
'Auth': self.session_id
}
url = '%s%s' % (self.manager_url, uri)
body = json.dumps(body)
response = self._do_request(url, headers, body, request_type)
json_response = response.json()
except requests.RequestException as e:
connection_error = str(e.message).split(':')[-1]
log_message = ("Can't connect to OneView: %s" % connection_error)
raise exceptions.OneViewConnectionError(log_message)
return json_response
def _do_request(self, url, headers, body, request_type):
verify_status = self._get_verify_connection_option()
@retrying.retry(
stop_max_attempt_number=self.max_polling_attempts,
retry_on_result=lambda response: _check_request_status(response),
wait_fixed=WAIT_DO_REQUEST_IN_MILLISECONDS
)
def request(url, headers, body, request_type):
if request_type == PUT_REQUEST_TYPE:
response = requests.put(
url, data=body, headers=headers, verify=verify_status
)
elif request_type == POST_REQUEST_TYPE:
response = requests.post(
url, data=body, headers=headers, verify=verify_status
)
elif request_type == DELETE_REQUEST_TYPE:
response = requests.delete(
url, headers=headers, verify=verify_status
)
else:
response = requests.get(
url, headers=headers, verify=verify_status
)
return response
return request(url, headers, body, request_type)
def _wait_for_task_to_complete(self, task):
@retrying.retry(
stop_max_attempt_number=self.max_polling_attempts,
retry_on_result=lambda task: task.get('percentComplete') < 100,
wait_fixed=WAIT_TASK_IN_MILLISECONDS,
retry_on_exception=lambda task: False
)
def wait(task):
uri = task.get('uri')
task = self._prepare_and_do_request(uri)
task_state = task.get("taskState")
error_code = task.get("errorCode")
if (not task_state) and error_code:
details = task.get("details")
if error_code == "RESOURCE_NOT_FOUND":
raise exceptions.OneViewResourceNotFoundError(details)
else:
raise exceptions.OneViewTaskError("%s - %s"
% (error_code, details))
elif task_state.lower() == 'error':
raise exceptions.OneViewTaskError("The task '%s' returned an "
"error state" % uri)
return task
return wait(task)
def _check_request_status(response):
repeat = False
status = response.status_code
if status == 404:
raise exceptions.OneViewResourceNotFoundError()
elif status in (409,):
time.sleep(10)
repeat = True
elif status == 500:
raise exceptions.OneViewInternalServerError(
"OneView returned HTTP 500"
)
# Any other unexpected status are logged
elif status not in (200, 202,):
message = (
"OneView appliance returned an unknown response status: %s"
% status
)
raise exceptions.UnknowOneViewResponseError(message)
return repeat

View File

@ -0,0 +1,75 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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.
class OneViewConnectionError(Exception):
message = "Can't connect to OneView"
class OneViewNotAuthorizedException(Exception):
message = ("Unauthorized access to OneView. Check the credentials used.")
class OneViewResourceNotFoundError(Exception):
message = ("Resource not found in OneView")
class OneViewServerProfileTemplateError(Exception):
message = ("Server Profile Template not found in the node's driver_info")
class OneViewMaxPollingAttemptsExceededError(Exception):
message = ("Max polling attempts to OneView exceeded")
class OneViewBootDeviceInvalidError(Exception):
message = ("Device selected is not a valid boot device")
class OneViewServerProfileAssociatedError(Exception):
message = ("There is no Server Profile assigned to this Server"
" Hardware")
class OneViewErrorStateSettingPowerState(Exception):
message = ("Server Hardware went to error state when trying to change"
" power state")
class OneViewErrorSettingBootDevice(Exception):
message = ("Server Hardware went to error state when trying to change"
" the primary boot device")
class OneViewTaskError(Exception):
message = ("The task for this action in OneView returned an error state")
class OneViewInconsistentResource(Exception):
message = ("The resource is inconsistent with its OneView counterpart")
class OneViewHealthStatusError(Exception):
message = ("There is a health status issue with an OneView Server Profile")
class IncompatibleOneViewAPIVersion(Exception):
message = ("The version of OneView's API is unsupported")
class UnknowOneViewResponseError(Exception):
message = ("OneView appliance returned an unknown response status")

32
oneview_client/states.py Normal file
View File

@ -0,0 +1,32 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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.
# Power states on OneView
ONEVIEW_POWER_ON = 'On'
ONEVIEW_POWER_OFF = 'Off'
ONEVIEW_POWERING_ON = 'PoweringOn'
ONEVIEW_POWERING_OFF = 'PoweringOff'
ONEVIEW_RESETTING = 'Resetting'
# Error states
ONEVIEW_ERROR = 'error'

View File

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# 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 oslotest import base
class TestCase(base.BaseTestCase):
"""Test case base class for all unit tests."""

View File

@ -0,0 +1,656 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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 json
import mock
import requests
import retrying
import six.moves.http_client as http_client
import unittest
from oneview_client import client
from oneview_client import exceptions
from oneview_client import states
PROPERTIES_DICT = {"cpu_arch": "x86_64",
"cpus": "8",
"local_gb": "10",
"memory_mb": "4096",
"capabilities": "server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri"}
DRIVER_INFO_DICT = {'server_hardware_uri': 'fake_sh_uri',
'server_profile_template_uri': 'fake_spt_uri'}
class OneViewClientAuthTestCase(unittest.TestCase):
def setUp(self):
super(OneViewClientAuthTestCase, self).setUp()
self.manager_url = 'https://1.2.3.4'
self.username = 'user'
self.password = 'password'
@mock.patch.object(requests, 'post')
def test_authenticate(self, mock_post):
client.Client(self.manager_url,
self.username,
self.password)
mock_post.assert_called_once_with(
'https://1.2.3.4/rest/login-sessions',
data=json.dumps({"userName": "user", "password": "password"}),
headers={'content-type': 'application/json'},
verify=True
)
@mock.patch.object(requests, 'post')
def test_authenticate_insecure(self, mock_post):
client.Client(self.manager_url,
self.username,
self.password,
allow_insecure_connections=True)
mock_post.assert_called_once_with(
'https://1.2.3.4/rest/login-sessions',
data=json.dumps({"userName": "user", "password": "password"}),
headers={'content-type': 'application/json'},
verify=False
)
@mock.patch.object(requests, 'post')
def test_authenticate_invalid_credentials(self, mock_post):
response = mock_post.return_value
response.status_code = http_client.UNAUTHORIZED
mock_post.return_value = response
self.assertRaises(
exceptions.OneViewNotAuthorizedException,
client.Client,
self.manager_url,
'any',
'any'
)
@mock.patch.object(client.Client, '_authenticate', autospec=True)
def test_get_session(self, mock__authenticate):
reference = "xyz"
response = mock__authenticate.return_value
response.status_code = http_client.OK
response.json = mock.MagicMock(return_value={"sessionID": reference})
mock__authenticate.return_value = response
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
session_id = oneview_client.get_session()
self.assertEqual(reference, session_id)
@mock.patch.object(client.Client, '_authenticate', autospec=True)
class OneViewClientTestCase(unittest.TestCase):
def setUp(self):
super(OneViewClientTestCase, self).setUp()
self.manager_url = 'https://1.2.3.4'
self.username = 'user'
self.password = 'password'
@mock.patch.object(client.Client, 'set_node_power_state', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_power_on_server_on(self, mock_get_pstate, mock_set_pstate,
mock__authenticate):
driver_info = {"server_hardware_uri": "/any"}
mock_get_pstate.return_value = states.ONEVIEW_POWER_ON
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
oneview_client.power_on(driver_info)
mock_get_pstate.assert_called_once_with(oneview_client, driver_info)
self.assertFalse(mock_set_pstate.called)
@mock.patch.object(client.Client, 'set_node_power_state', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_power_on_server_off(self, mock_get_pstate, mock_set_pstate,
mock__authenticate):
driver_info = {"server_hardware_uri": "/any"}
mock_get_pstate.return_value = states.ONEVIEW_POWER_OFF
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
oneview_client.power_on(driver_info)
mock_get_pstate.assert_called_once_with(oneview_client, driver_info)
mock_set_pstate.assert_called_once_with(oneview_client, driver_info,
states.ONEVIEW_POWER_ON)
@mock.patch.object(client.Client, 'set_node_power_state', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_power_off_server_off(self, mock_get_pstate, mock_set_pstate,
mock__authenticate):
driver_info = {"server_hardware_uri": "/any"}
mock_get_pstate.return_value = states.ONEVIEW_POWER_OFF
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
oneview_client.power_off(driver_info)
mock_get_pstate.assert_called_once_with(oneview_client, driver_info)
self.assertFalse(mock_set_pstate.called)
@mock.patch.object(client.Client, 'set_node_power_state', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_power_off_server_on(self, mock_get_pstate, mock_set_pstate,
mock__authenticate):
driver_info = {"server_hardware_uri": "/any"}
mock_get_pstate.return_value = states.ONEVIEW_POWER_ON
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
oneview_client.power_off(driver_info)
mock_get_pstate.assert_called_once_with(oneview_client, driver_info)
mock_set_pstate.assert_called_once_with(oneview_client, driver_info,
states.ONEVIEW_POWER_OFF,
client.PRESS_AND_HOLD)
@mock.patch.object(client.Client, '_wait_for_task_to_complete',
autospec=True)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_set_power_state_server_hardware(self, mock_get_node_power,
mock__prepare_do_request,
mock__wait_for_task,
mock__authenticate):
mock_get_node_power.return_value = states.ONEVIEW_POWER_ON
mock__prepare_do_request.return_value = {}
driver_info = {"server_hardware_uri": "/any"}
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
oneview_client.set_node_power_state(
driver_info,
states.ONEVIEW_POWER_ON
)
mock__prepare_do_request.assert_called_once_with(
oneview_client,
uri='/any/powerState',
body={'powerControl': client.MOMENTARY_PRESS,
'powerState': states.ONEVIEW_POWER_ON},
request_type=client.PUT_REQUEST_TYPE,
)
@mock.patch.object(requests, 'put', autospec=True)
def test_set_power_state_nonexistent_server_hardware(
self, mock_do_request, mock__authenticate):
class Response(object):
status_code = 404
def json(self):
return {
"errorCode": "RESOURCE_NOT_FOUND",
"details": "Resource not found, ID = /any_invalid",
}
mock_do_request.return_value = Response()
driver_info = {"server_hardware_uri": "/any_invalid"}
target_state = states.ONEVIEW_POWER_ON
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewResourceNotFoundError,
oneview_client.set_node_power_state, driver_info, target_state
)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
@mock.patch.object(client.Client, 'get_node_power_state', autospec=True)
def test_set_power_state_server_hardware_power_status_error(
self, mock_get_node_power, mock__prepare_do_request, mock__authenticate
):
power = states.ONEVIEW_ERROR
mock_get_node_power.return_value = power
mock__prepare_do_request.return_value = {
"taskState": "Error",
"percentComplete": 100
}
driver_info = {"server_hardware_uri": "/any"}
target_state = "On"
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewErrorStateSettingPowerState,
oneview_client.set_node_power_state, driver_info, target_state
)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
def test_get_server_hardware_nonexistent(self, mock__prepare_do_request,
mock__authenticate):
mock__prepare_do_request.return_value = {"error": "resource not found"}
driver_info = {"server_hardware_uri": ""}
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewResourceNotFoundError,
oneview_client.get_server_hardware,
driver_info
)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
@mock.patch.object(client.Client, 'get_server_profile_from_hardware',
autospec=True)
def test_set_boot_device_nonexistent_resource_uri(self,
mock_get_server_profile,
mock__prepare_do_request,
mock__authenticate):
driver_info = {}
new_first_boot_device = "None"
mock__prepare_do_request.return_value = {
"errorCode": "RESOURCE_NOT_FOUND",
"data": None
}
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewResourceNotFoundError,
oneview_client.set_boot_device,
driver_info,
new_first_boot_device
)
@mock.patch.object(client.Client, 'get_boot_order', autospec=True)
def test_set_boot_device_nonexistent_resource_first_boot_device(
self, mock_get_boot_order, mock__authenticate
):
driver_info = {}
new_first_boot_device = None
mock_get_boot_order.return_value = []
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewBootDeviceInvalidError,
oneview_client.set_boot_device,
driver_info,
new_first_boot_device
)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
@mock.patch.object(client.Client, 'get_boot_order', autospec=True)
def test_get_server_profile_from_hardware(self, mock_get_boot_order,
mock_get_server_hardware,
mock__prepare_do_request,
mock__authenticate):
driver_info = {}
new_first_boot_device = "any_boot_device"
mock_get_boot_order.return_value = []
mock_get_server_hardware.return_value = {}
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaises(
exceptions.OneViewServerProfileAssociatedError,
oneview_client.set_boot_device,
driver_info,
new_first_boot_device
)
mock_get_server_hardware.return_value = {"serverProfileUri": "any_uri"}
mock__prepare_do_request.return_value = {}
self.assertRaises(
exceptions.OneViewResourceNotFoundError,
oneview_client.set_boot_device,
driver_info,
new_first_boot_device
)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
def test__wait_for_task_to_complete(self, mock__prepare_do_request,
mock__authenticate):
task = {
"uri": "/any_uri",
"taskState": "Something",
"percentComplete": 100
}
oneview_client = client.Client(self.manager_url,
self.username,
self.password,
max_polling_attempts=1)
mock__prepare_do_request.return_value = task
oneview_client._wait_for_task_to_complete(task)
@mock.patch.object(client.Client, '_prepare_and_do_request', autospec=True)
def test__wait_for_task_to_complete_timeout(self, mock__prepare_do_request,
mock__authenticate):
task = {
"uri": "/any_uri",
"taskState": "Something",
"percentComplete": 30
}
oneview_client = client.Client(self.manager_url,
self.username,
self.password,
max_polling_attempts=1)
mock__prepare_do_request.return_value = task
self.assertRaises(
retrying.RetryError,
oneview_client._wait_for_task_to_complete,
task,
)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_hardware_inconsistent_memorymb_value(
self, mock_get_server_hardware, mock__authenticate
):
mock_get_server_hardware.return_value = {
"memoryMb": 1,
"processorCoreCount": 1,
"processorCount": 1,
}
driver_info = {
"server_hardware_uri": "/any_uri",
}
node_memorymb = 2
node_cpus = 1
exc_expected_msg = (
"Node memory_mb is inconsistent with OneView's server"
" hardware /any_uri memoryMb. Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_server_hardware,
driver_info,
node_memorymb,
node_cpus
)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_hardware_inconsistent_cpus_value(
self, mock_get_server_hardware, mock__authenticate
):
mock_get_server_hardware.return_value = {
"memoryMb": 1,
"processorCoreCount": 2,
"processorCount": 3,
}
driver_info = {
"server_hardware_uri": "/any_uri",
}
node_memorymb = 1
node_cpus = 3
exc_expected_msg = (
"Node cpus is inconsistent with OneView's server"
" hardware /any_uri cpus. Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_server_hardware,
driver_info,
node_memorymb,
node_cpus
)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_hardware_type_inconsistent_sht_uri(
self, mock_get_server_hardware, mock__authenticate
):
mock_get_server_hardware.return_value = {
"serverHardwareTypeUri": "/incosistent_uri"
}
driver_info = {
"server_hardware_uri": "/any_serveruri",
"server_hardware_type_uri": "/any_uri",
}
exc_expected_msg = (
"Node server_hardware_type_uri is inconsistent with"
" OneView's server hardware /any_serveruri serverHardwareTypeUri."
" Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_server_hardware_type,
driver_info
)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_enclosure_group_inconsistent(
self, mock_get_server_hardware, mock__authenticate
):
driver_info = {
"server_hardware_uri": "/any_uri",
"enclosure_group_uri": "/inconsistent_uri"
}
exc_expected_msg = (
"Node enclosure_group_uri is inconsistent with"
" OneView's server hardware /any_uri serverGroupUri."
" Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_enclosure_group,
driver_info
)
@mock.patch.object(client.Client, 'get_server_profile_from_hardware',
autospec=True)
def test_check_node_port_mac_incompatible_with_server_profile(
self, mock_server_profile, mock__authenticate
):
mock_server_profile.return_value = {
"uri": "/anyuri",
"connections": [
{'boot': {'priority': u'Primary'},
'mac': u'56:88:7B:C0:00:0B'}
]
}
exc_expected_msg = (
"The ports of the node are not compatible with its"
" server profile /anyuri. Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client
.is_node_port_mac_compatible_with_server_profile,
{},
{}
)
@mock.patch.object(client.Client, 'get_server_profile_from_hardware',
autospec=True)
def test_check_node_port_mac_no_primary_boot_connection(
self, mock_server_profile, mock__authenticate
):
mock_server_profile.return_value = {
"uri": "/anyuri",
"connections": [
{'boot': {'priority': u'NotBootable'},
'mac': u'56:88:7B:C0:00:0B'}
]
}
exc_expected_msg = (
"No primary boot connection configured for server profile"
" /anyuri Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client
.is_node_port_mac_compatible_with_server_profile,
{},
{}
)
@mock.patch.object(client.Client, 'get_server_profile_template',
autospec=True)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_profile_template_inconsistent_sht(
self, mock_server_hardware, mock_server_template, mock__authenticate
):
mock_server_hardware.return_value = {
'serverHardwareTypeUri': '/sht_uri',
'serverGroupUri': 'eg_uri'}
mock_server_template.return_value = {
'serverHardwareTypeUri': '/inconsistent_uri',
'enclosureGroupUri': '/inconsistent_uri'}
driver_info = {
"server_hardware_uri": "/any_uri",
"server_profile_template_uri": "/profile_uri"
}
exc_expected_msg = (
"Server profile template /profile_uri serverHardwareTypeUri is"
" inconsistent with server hardware /any_uri"
" serverHardwareTypeUri. Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_server_profile_template,
driver_info
)
@mock.patch.object(client.Client, 'get_server_profile_template',
autospec=True)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_profile_template_inconsistent_eg(
self, mock_server_hardware, mock_server_template, mock__authenticate
):
mock_server_hardware.return_value = {
'serverHardwareTypeUri': '/sht_uri',
'serverGroupUri': 'eg_uri'}
mock_server_template.return_value = {
'serverHardwareTypeUri': '/sht_uri',
'enclosureGroupUri': '/inconsistent_uri'}
driver_info = {
"server_hardware_uri": "/any_uri",
"server_profile_template_uri": "/profile_uri"
}
exc_expected_msg = (
"Server profile template /profile_uri enclosureGroupUri is"
" inconsistent with server hardware /any_uri"
" serverGroupUri. Node validation failed."
)
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
self.assertRaisesRegexp(
exceptions.OneViewInconsistentResource,
exc_expected_msg,
oneview_client.validate_node_server_profile_template,
driver_info
)
@mock.patch.object(client.Client, 'get_oneview_version')
def test_verify_oneview_version(self, mock_get_oneview_version,
mock__authenticate):
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
mock_get_oneview_version.return_value = {
'minimumVersion': 120,
'currentVersion': 200
}
oneview_client.verify_oneview_version()
mock_get_oneview_version.assert_called_once_with()
@mock.patch.object(client.Client, 'get_oneview_version')
def test_verify_oneview_version_fail(self, mock_get_oneview_version,
mock__authenticate):
oneview_client = client.Client(self.manager_url,
self.username,
self.password)
mock_get_oneview_version.return_value = {
'minimumVersion': 120,
'currentVersion': 120
}
self.assertRaises(
exceptions.IncompatibleOneViewAPIVersion,
oneview_client.verify_oneview_version
)

View File

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
# 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.
"""
test_python-oneviewclient
----------------------------------
Tests for `python-oneviewclient` module.
"""
from python-oneviewclient.tests import base
class TestPython-oneviewclient(base.TestCase):
def test_something(self):
pass

View File

@ -4,3 +4,5 @@
pbr>=0.6,!=0.7,<1.0
Babel>=1.3
retrying>=1.2.3
six>=1.9.0

View File

@ -22,7 +22,7 @@ classifier =
[files]
packages =
python-oneviewclient
oneview_client
[build_sphinx]
source-dir = doc/source

View File

@ -1,6 +1,6 @@
[tox]
minversion = 1.6
envlist = py33,py34,py26,py27,pypy,pep8
envlist = py34,py27,pep8
skipsdist = True
[testenv]