
This patch serves to correct the problem presented in UFCG OneView CI, in which the node was being created and changed the state to manageable, and only validate the memory_mb after that. Change-Id: Id0ef20b320a622da6990f6ffaf26256059582743
869 lines
32 KiB
Python
869 lines
32 KiB
Python
# (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 abc
|
|
import json
|
|
import six
|
|
import time
|
|
|
|
import requests
|
|
import retrying
|
|
|
|
from oneview_client import auditing
|
|
from oneview_client import exceptions
|
|
from oneview_client import ilo_utils
|
|
from oneview_client import managers
|
|
from oneview_client import states
|
|
from oneview_client import utils
|
|
|
|
SUPPORTED_ONEVIEW_VERSION = 200
|
|
|
|
WAIT_DO_REQUEST_IN_MILLISECONDS = 1000
|
|
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'
|
|
|
|
SERVER_HARDWARE_PREFIX_URI = '/rest/server-hardware/'
|
|
SERVER_PROFILE_TEMPLATE_PREFIX_URI = '/rest/server-profile-templates/'
|
|
SERVER_PROFILE_PREFIX_URI = '/rest/server-profiles/'
|
|
|
|
|
|
@six.add_metaclass(abc.ABCMeta)
|
|
class BaseClient(object):
|
|
def __init__(
|
|
self, manager_url, username, password,
|
|
allow_insecure_connections=False, tls_cacert_file='',
|
|
max_polling_attempts=20, audit_enabled=False,
|
|
audit_map_file='', audit_output_file=''
|
|
):
|
|
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.audit_enabled = audit_enabled
|
|
self.audit_map_file = audit_map_file
|
|
self.audit_output_file = audit_output_file
|
|
self.audit_case_methods = []
|
|
|
|
if self.allow_insecure_connections:
|
|
requests.packages.urllib3.disable_warnings(
|
|
requests.packages.urllib3.exceptions.InsecureRequestWarning
|
|
)
|
|
|
|
if self.audit_enabled:
|
|
self.audit_case_methods = auditing.read_audit_map_file(
|
|
self.audit_map_file
|
|
)
|
|
|
|
self.session_id = self.get_session()
|
|
|
|
@auditing.audit
|
|
def verify_credentials(self):
|
|
return self._authenticate()
|
|
|
|
@auditing.audit
|
|
def get_session(self):
|
|
response = self._authenticate()
|
|
return response.json().get('sessionID')
|
|
|
|
@auditing.audit
|
|
def _authenticate(self):
|
|
if self.manager_url in ("", None):
|
|
raise exceptions.OneViewConnectionError(
|
|
"Can't connect to OneView: 'manager_url' configuration"
|
|
"parameter is blank")
|
|
|
|
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 == 400:
|
|
raise exceptions.OneViewNotAuthorizedException()
|
|
else:
|
|
return r
|
|
|
|
@auditing.audit
|
|
def _logout(self):
|
|
if self.manager_url in ("", None):
|
|
raise exceptions.OneViewConnectionError(
|
|
"Can't connect to OneView: 'manager_url' configuration"
|
|
"parameter is blank")
|
|
|
|
url = '%s/rest/login-sessions' % self.manager_url
|
|
headers = {
|
|
'X-Api-Version': str(SUPPORTED_ONEVIEW_VERSION),
|
|
'Auth': self.session_id
|
|
}
|
|
|
|
verify_ssl = self._get_verify_connection_option()
|
|
|
|
r = requests.delete(url,
|
|
headers=headers,
|
|
verify=verify_ssl)
|
|
if r.status_code == 400:
|
|
raise exceptions.OneViewNotAuthorizedException()
|
|
|
|
@auditing.audit
|
|
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
|
|
|
|
@auditing.audit
|
|
def verify_oneview_version(self):
|
|
if not self._is_oneview_version_compatible():
|
|
msg = ("The version of the OneView's API is unsupported. "
|
|
"Supported version is '%s'" % SUPPORTED_ONEVIEW_VERSION)
|
|
raise exceptions.IncompatibleOneViewAPIVersion(msg)
|
|
|
|
@auditing.audit
|
|
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
|
|
|
|
@auditing.audit
|
|
def get_oneview_version(self):
|
|
url = '%s/rest/version' % self.manager_url
|
|
headers = {"Accept-Language": "en_US"}
|
|
|
|
verify_ssl = self._get_verify_connection_option()
|
|
|
|
response = requests.get(
|
|
url, headers=headers, verify=verify_ssl
|
|
)
|
|
self._check_request_status(response, url)
|
|
versions = response.json()
|
|
return versions
|
|
|
|
# --- 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': str(SUPPORTED_ONEVIEW_VERSION),
|
|
'Auth': self.session_id
|
|
}
|
|
url = '%s%s' % (self.manager_url, uri)
|
|
body = json.dumps(body)
|
|
try:
|
|
response = self._do_request(url, headers, body, request_type)
|
|
except exceptions.OneViewNotAuthorizedException:
|
|
self.session_id = self.get_session()
|
|
headers['Auth'] = self.session_id
|
|
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
|
|
|
|
@auditing.audit
|
|
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: self._check_request_status(
|
|
response, url
|
|
),
|
|
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)
|
|
|
|
@auditing.audit
|
|
def _wait_for_task_to_complete(self, task):
|
|
@retrying.retry(
|
|
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)
|
|
|
|
@auditing.audit
|
|
def _get_ilo_access(self, server_hardware_uuid):
|
|
uri = ("/rest/server-hardware/%s/remoteConsoleUrl"
|
|
% server_hardware_uuid)
|
|
json = self._prepare_and_do_request(uri)
|
|
url = json.get("remoteConsoleUrl")
|
|
ip_key = "addr="
|
|
host_ip = url[url.rfind(ip_key) + len(ip_key):]
|
|
host_ip = host_ip[:host_ip.find("&")]
|
|
session_key = "sessionkey="
|
|
token = url[url.rfind(session_key) + len(session_key):]
|
|
|
|
return host_ip, token
|
|
|
|
@auditing.audit
|
|
def get_sh_mac_from_ilo(self, server_hardware_uuid, nic_index=0):
|
|
host_ip, ilo_token = self._get_ilo_access(server_hardware_uuid)
|
|
try:
|
|
return ilo_utils.get_mac_from_ilo(host_ip,
|
|
ilo_token,
|
|
nic_index,
|
|
self.allow_insecure_connections)
|
|
finally:
|
|
ilo_utils.ilo_logout(host_ip, ilo_token)
|
|
|
|
@auditing.audit
|
|
def _set_onetime_boot(self, server_hardware_uuid, boot_device):
|
|
host_ip, ilo_token = self._get_ilo_access(server_hardware_uuid)
|
|
oneview_ilo_mapping = {
|
|
'HardDisk': 'Hdd',
|
|
'PXE': 'Pxe',
|
|
'CD': 'Cd',
|
|
'USB': 'Usb',
|
|
}
|
|
try:
|
|
ilo_device = oneview_ilo_mapping[boot_device]
|
|
return ilo_utils.set_onetime_boot(host_ip, ilo_token,
|
|
ilo_device,
|
|
self.allow_insecure_connections)
|
|
except exceptions.IloException as e:
|
|
raise e
|
|
except KeyError as e:
|
|
raise exceptions.IloException(
|
|
"Set one-time boot to %s is not supported." % boot_device
|
|
)
|
|
finally:
|
|
ilo_utils.ilo_logout(host_ip, ilo_token)
|
|
|
|
def _check_request_status(self, response, url):
|
|
repeat = False
|
|
status = response.status_code
|
|
|
|
if status in (401, 403):
|
|
error_code = response.json().get('errorCode')
|
|
raise exceptions.OneViewNotAuthorizedException(error_code)
|
|
elif status == 404:
|
|
raise exceptions.OneViewResourceNotFoundError(url)
|
|
elif status in (408, 409,):
|
|
time.sleep(10)
|
|
repeat = True
|
|
elif status == 500:
|
|
raise exceptions.OneViewInternalServerError()
|
|
# 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
|
|
|
|
|
|
class ClientV2(BaseClient):
|
|
def __init__(
|
|
self, manager_url, username, password,
|
|
allow_insecure_connections=False, tls_cacert_file='',
|
|
max_polling_attempts=20, audit_enabled=False,
|
|
audit_map_file='', audit_output_file=''
|
|
):
|
|
super(ClientV2, self).__init__(manager_url, username, password,
|
|
allow_insecure_connections,
|
|
tls_cacert_file, max_polling_attempts,
|
|
audit_enabled, audit_map_file,
|
|
audit_output_file)
|
|
|
|
# Next generation
|
|
self.enclosure = managers.EnclosureManager(self)
|
|
self.enclosure_group = managers.EnclosureGroupManager(self)
|
|
self.server_hardware = managers.ServerHardwareManager(self)
|
|
self.server_hardware_index = managers.ServerHardwareIndexManager(self)
|
|
self.server_hardware_type = managers.ServerHardwareTypeManager(self)
|
|
self.server_profile = managers.ServerProfileManager(self)
|
|
self.server_profile_template = managers.ServerProfileTemplateManager(
|
|
self
|
|
)
|
|
|
|
|
|
class Client(BaseClient):
|
|
def __init__(
|
|
self, manager_url, username, password,
|
|
allow_insecure_connections=False, tls_cacert_file='',
|
|
max_polling_attempts=20, audit_enabled=False,
|
|
audit_map_file='', audit_output_file=''
|
|
):
|
|
super(Client, self).__init__(manager_url, username, password,
|
|
allow_insecure_connections,
|
|
tls_cacert_file, max_polling_attempts,
|
|
audit_enabled, audit_map_file,
|
|
audit_output_file)
|
|
# Next generation
|
|
self._enclosure_group = managers.EnclosureGroupManager(self)
|
|
self._server_hardware = managers.ServerHardwareManager(self)
|
|
self._server_profile_template = managers.ServerProfileTemplateManager(
|
|
self
|
|
)
|
|
self._server_profile = managers.ServerProfileManager(self)
|
|
|
|
# --- Power Driver ---
|
|
@auditing.audit
|
|
def get_node_power_state(self, node_info):
|
|
return self.get_server_hardware(node_info).power_state
|
|
|
|
@auditing.audit
|
|
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
|
|
|
|
@auditing.audit
|
|
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
|
|
|
|
@auditing.audit
|
|
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)
|
|
|
|
return state
|
|
|
|
# --- Management Driver ---
|
|
@auditing.audit
|
|
def get_server_hardware(self, node_info):
|
|
uuid = node_info['server_hardware_uri'].split("/")[-1]
|
|
return self._server_hardware.get(uuid)
|
|
|
|
@auditing.audit
|
|
def get_server_hardware_by_uuid(self, uuid):
|
|
return self._server_hardware.get(uuid)
|
|
|
|
@auditing.audit
|
|
def get_server_profile_from_hardware(self, node_info):
|
|
server_hardware = self.get_server_hardware(node_info)
|
|
server_profile_uri = server_hardware.server_profile_uri
|
|
|
|
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_uuid = server_profile_uri.split("/")[-1]
|
|
return self._server_profile.get(server_profile_uuid)
|
|
|
|
@auditing.audit
|
|
def get_server_profile_template(self, node_info):
|
|
uuid = node_info['server_profile_template_uri'].split("/")[-1]
|
|
return self._server_profile_template.get(uuid)
|
|
|
|
@auditing.audit
|
|
def get_server_profile_template_by_uuid(self, uuid):
|
|
return self._server_profile_template.get(uuid)
|
|
|
|
@auditing.audit
|
|
def get_server_profile_by_uuid(self, uuid):
|
|
return self._server_profile.get(uuid)
|
|
|
|
@auditing.audit
|
|
def get_boot_order(self, node_info):
|
|
server_profile = self.get_server_profile_from_hardware(
|
|
node_info
|
|
)
|
|
return server_profile.boot.get("order")
|
|
|
|
@auditing.audit
|
|
def set_boot_device(self, node_info, new_primary_boot_device,
|
|
onetime=False):
|
|
if new_primary_boot_device is None:
|
|
raise exceptions.OneViewBootDeviceInvalidError()
|
|
|
|
boot_order = self.get_boot_order(node_info)
|
|
if new_primary_boot_device == boot_order[0]:
|
|
return
|
|
|
|
if onetime:
|
|
try:
|
|
sh_uuid = utils.get_uuid_from_uri(
|
|
node_info['server_hardware_uri']
|
|
)
|
|
self._set_onetime_boot(sh_uuid, new_primary_boot_device)
|
|
return
|
|
except exceptions.IloException:
|
|
# Falls back to persistent in case of failure
|
|
pass
|
|
|
|
self._persistent_set_boot_device(node_info, boot_order,
|
|
new_primary_boot_device)
|
|
|
|
@auditing.audit
|
|
def _persistent_set_boot_device(self, node_info, boot_order,
|
|
new_primary_boot_device):
|
|
|
|
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 = self.get_server_profile_from_hardware(
|
|
node_info
|
|
)
|
|
|
|
manage_boot = server_profile.boot.get("manageBoot")
|
|
server_profile.boot = {
|
|
"manageBoot": manage_boot,
|
|
"order": boot_order
|
|
}
|
|
|
|
boot_order_dict = server_profile.to_oneview_dict()
|
|
|
|
task = self._prepare_and_do_request(
|
|
uri=server_profile.uri, body=boot_order_dict,
|
|
request_type=PUT_REQUEST_TYPE
|
|
)
|
|
try:
|
|
self._wait_for_task_to_complete(task)
|
|
except exceptions.OneViewTaskError as e:
|
|
raise exceptions.OneViewErrorSettingBootDevice(e.message)
|
|
|
|
# ---- Deploy Driver ----
|
|
@auditing.audit
|
|
def clone_template_and_apply(self,
|
|
server_profile_name,
|
|
server_hardware_uuid,
|
|
server_profile_template_uuid):
|
|
|
|
if not server_profile_name:
|
|
raise ValueError(
|
|
'Missing Server Profile name.'
|
|
)
|
|
|
|
if not server_hardware_uuid:
|
|
raise ValueError(
|
|
'Missing Server Hardware uuid.'
|
|
)
|
|
|
|
if not server_profile_template_uuid:
|
|
raise ValueError(
|
|
'Missing Server Profile Template uuid.'
|
|
)
|
|
|
|
server_hardware_uri = '%s%s' % (
|
|
SERVER_HARDWARE_PREFIX_URI,
|
|
server_hardware_uuid
|
|
)
|
|
|
|
server_profile_template_uri = '%s%s' % (
|
|
SERVER_PROFILE_TEMPLATE_PREFIX_URI,
|
|
server_profile_template_uuid
|
|
)
|
|
|
|
generate_new_profile_uri = '%s/new-profile' % (
|
|
server_profile_template_uri
|
|
)
|
|
|
|
server_profile_from_template_json = self._prepare_and_do_request(
|
|
uri=generate_new_profile_uri
|
|
)
|
|
|
|
server_profile_from_template_json['serverHardwareUri'] = (
|
|
server_hardware_uri
|
|
)
|
|
server_profile_from_template_json['name'] = server_profile_name
|
|
server_profile_from_template_json['serverProfileTemplateUri'] = ""
|
|
|
|
post_profile_task = self._prepare_and_do_request(
|
|
uri=SERVER_PROFILE_PREFIX_URI,
|
|
body=server_profile_from_template_json,
|
|
request_type=POST_REQUEST_TYPE
|
|
)
|
|
|
|
try:
|
|
complete_task = self._wait_for_task_to_complete(
|
|
post_profile_task
|
|
)
|
|
except exceptions.OneViewTaskError as e:
|
|
raise exceptions.OneViewServerProfileAssignmentError(e.message)
|
|
|
|
server_profile_uri = (
|
|
complete_task.get('associatedResource').get('resourceUri')
|
|
)
|
|
|
|
uuid = server_profile_uri.split("/")[-1]
|
|
server_profile = self.get_server_profile_by_uuid(uuid)
|
|
|
|
return server_profile
|
|
|
|
@auditing.audit
|
|
def delete_server_profile(self, uuid):
|
|
if not uuid:
|
|
raise ValueError('Missing Server Profile uuid.')
|
|
|
|
delete_profile_task = self._prepare_and_do_request(
|
|
uri='%s%s' % (SERVER_PROFILE_PREFIX_URI, uuid),
|
|
request_type=DELETE_REQUEST_TYPE
|
|
)
|
|
try:
|
|
complete_task = self._wait_for_task_to_complete(
|
|
delete_profile_task
|
|
)
|
|
except exceptions.OneViewTaskError as e:
|
|
raise exceptions.OneViewServerProfileDeletionError(e.message)
|
|
|
|
return complete_task.get('associatedResource').get('resourceUri')
|
|
|
|
# ---- Node Validate ----
|
|
@auditing.audit
|
|
def validate_connections(self, oneview_info, ports, network_interface):
|
|
if network_interface != 'neutron':
|
|
self._is_node_port_mac_compatible_with_server_hardware(
|
|
oneview_info, ports)
|
|
self._validate_server_profile_template_mac_type(oneview_info)
|
|
elif oneview_info.get('use_oneview_ml2_driver'):
|
|
valid_ports = utils.get_oneview_connection_ports(ports)
|
|
self._validate_node_and_port_server_hardware_uri(
|
|
oneview_info, valid_ports)
|
|
self._validate_connection_mac(oneview_info, valid_ports)
|
|
|
|
def is_node_port_mac_compatible_with_server_hardware(
|
|
self, node_info, ports
|
|
):
|
|
# NOTE(mrtenio): While the connection validation patch
|
|
# is not accepted, we need to refer to the new validation.
|
|
self._is_node_port_mac_compatible_with_server_hardware(
|
|
node_info, ports)
|
|
|
|
@auditing.audit
|
|
def _is_node_port_mac_compatible_with_server_hardware(
|
|
self, node_info, ports
|
|
):
|
|
if not ports:
|
|
return
|
|
server_hardware = self.get_server_hardware(node_info)
|
|
try:
|
|
mac = server_hardware.get_mac(nic_index=0)
|
|
except exceptions.OneViewException:
|
|
mac = self.get_sh_mac_from_ilo(server_hardware.uuid, nic_index=0)
|
|
|
|
for port in ports:
|
|
if port.address.lower() == mac:
|
|
return
|
|
|
|
message = (
|
|
"The ports of the node are not compatible with its "
|
|
"server hardware %(server_hardware_uri)s." %
|
|
{'server_hardware_uri': server_hardware.uri}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
def validate_server_profile_template_mac_type(self, spt_uuid):
|
|
info = {"server_profile_template_uri": spt_uuid}
|
|
self._validate_server_profile_template_mac_type(info)
|
|
|
|
@auditing.audit
|
|
def _validate_server_profile_template_mac_type(self, oneview_info):
|
|
server_profile_template = self.get_server_profile_template(
|
|
oneview_info
|
|
)
|
|
if server_profile_template.mac_type != 'Physical':
|
|
message = (
|
|
"The server profile template %s is not set to use "
|
|
"physical MAC." % server_profile_template.uri
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def _validate_node_and_port_server_hardware_uri(self, oneview_info, ports):
|
|
node_hardware_id = utils.get_uuid_from_uri(
|
|
oneview_info.get('server_hardware_uri')
|
|
)
|
|
for port in ports:
|
|
switch_info = utils.get_switch_info(port)
|
|
port_hardware_id = switch_info.get('server_hardware_id')
|
|
if port_hardware_id.lower() != node_hardware_id.lower():
|
|
raise exceptions.OneViewInconsistentResource(
|
|
"The Server Hardware ID of the port %(port_id)s "
|
|
"doesn't match the Server Hardware ID %(server_hardware)s "
|
|
"of the node." % {
|
|
'port_id': port.uuid,
|
|
'server_hardware': node_hardware_id
|
|
}
|
|
)
|
|
|
|
@auditing.audit
|
|
def _validate_connection_mac(self, oneview_info, ports):
|
|
server_hardware = self.get_server_hardware(oneview_info)
|
|
for port in ports:
|
|
if port.address.lower() not in utils.get_all_macs(server_hardware):
|
|
raise exceptions.OneViewInconsistentResource(
|
|
"The MAC address %(mac)s of the port %(port_id)s doesn't"
|
|
" have a corresponding MAC address in the Server Hardware"
|
|
" %(server_hardware_uri)s" % {
|
|
'mac': port.address,
|
|
'port_id': port.uuid,
|
|
'server_hardware_uri': server_hardware.uri
|
|
}
|
|
)
|
|
|
|
@auditing.audit
|
|
def validate_node_server_hardware(
|
|
self, node_info, node_memorymb, node_cpus
|
|
):
|
|
# NOTE(fellypefca): This is temporary to fix the problems of CI.
|
|
pass
|
|
|
|
@auditing.audit
|
|
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.server_hardware_type_uri
|
|
|
|
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." %
|
|
{'server_hardware_uri': node_info.get('server_hardware_uri')}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def check_server_profile_is_applied(self, node_info):
|
|
self.get_server_profile_from_hardware(node_info)
|
|
|
|
@auditing.audit
|
|
def validate_node_enclosure_group(self, node_info):
|
|
server_hardware = self.get_server_hardware(node_info)
|
|
sh_enclosure_group_uri = server_hardware.enclosure_group_uri
|
|
node_enclosure_group_uri = node_info.get('enclosure_group_uri')
|
|
|
|
if node_enclosure_group_uri not in ('', 'None', None):
|
|
if sh_enclosure_group_uri != node_enclosure_group_uri:
|
|
message = (
|
|
"Node enclosure_group_uri '%(node_enclosure_group_uri)s' "
|
|
"is inconsistent with OneView's server hardware "
|
|
"serverGroupUri '%(sh_enclosure_group_uri)s' of "
|
|
"ServerHardware %(server_hardware)s"
|
|
% {
|
|
'node_enclosure_group_uri': node_enclosure_group_uri,
|
|
'sh_enclosure_group_uri': sh_enclosure_group_uri,
|
|
'server_hardware': server_hardware.uuid,
|
|
}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def is_node_port_mac_compatible_with_server_profile(
|
|
self, node_info, ports
|
|
):
|
|
server_profile = self.get_server_profile_from_hardware(
|
|
node_info
|
|
)
|
|
|
|
if server_profile.connections:
|
|
primary_boot_connection = None
|
|
|
|
for connection in server_profile.connections:
|
|
boot = connection.get('boot')
|
|
if (boot is not None and
|
|
boot.get('priority').lower() == 'primary'):
|
|
primary_boot_connection = connection
|
|
|
|
if primary_boot_connection is None:
|
|
message = (
|
|
"No primary boot connection configured for server profile"
|
|
" %s." % server_profile.uri
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
mac = primary_boot_connection.get('mac')
|
|
|
|
else:
|
|
# If no connections on Server Profile, the connections are not
|
|
# being managed or the server is rack based. In both cases, fall
|
|
# back to 1st nic from iLO
|
|
server_hardware = self.get_server_hardware(node_info)
|
|
mac = self.get_sh_mac_from_ilo(server_hardware.uuid, nic_index=0)
|
|
|
|
for port in ports:
|
|
if port.address.lower() == mac.lower():
|
|
return
|
|
|
|
message = (
|
|
"The ports of the node are not compatible with its"
|
|
" server profile %(server_profile_uri)s." %
|
|
{'server_profile_uri': server_profile.uri}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def validate_node_server_profile_template(self, node_info):
|
|
server_profile_template = self.get_server_profile_template(node_info)
|
|
server_hardware = self.get_server_hardware(node_info)
|
|
|
|
self._validate_spt_server_hardware_type(
|
|
server_profile_template, server_hardware
|
|
)
|
|
self._validate_spt_enclosure_group(
|
|
server_profile_template, server_hardware
|
|
)
|
|
self._validate_spt_manage_boot(server_profile_template)
|
|
|
|
@auditing.audit
|
|
def _validate_spt_server_hardware_type(
|
|
self, server_profile_template, server_hardware
|
|
):
|
|
spt_server_hardware_type_uri = (
|
|
server_profile_template.server_hardware_type_uri
|
|
)
|
|
sh_server_hardware_type_uri = server_hardware.server_hardware_type_uri
|
|
|
|
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." %
|
|
{'spt_uri': server_profile_template.uri,
|
|
'server_hardware_uri': server_hardware.uri}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def _validate_spt_enclosure_group(
|
|
self, server_profile_template, server_hardware
|
|
):
|
|
spt_enclosure_group_uri = server_profile_template.enclosure_group_uri
|
|
sh_enclosure_group_uri = server_hardware.enclosure_group_uri
|
|
|
|
if spt_enclosure_group_uri != sh_enclosure_group_uri:
|
|
message = (
|
|
"Server profile template %(spt_uri)s enclosureGroupUri is"
|
|
" inconsistent with server hardware %(server_hardware_uri)s"
|
|
" serverGroupUri." %
|
|
{'spt_uri': server_profile_template.uri,
|
|
'server_hardware_uri': server_hardware.uri}
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def _validate_spt_manage_boot(self, server_profile_template):
|
|
manage_boot = server_profile_template.boot.get('manageBoot')
|
|
|
|
if not manage_boot:
|
|
message = (
|
|
"Server Profile Template: %s, does not allow to manage "
|
|
"boot order." % server_profile_template.uri
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|
|
|
|
@auditing.audit
|
|
def _validate_spt_boot_connections(self, server_profile_template):
|
|
spt_connections = server_profile_template.connections
|
|
|
|
for connection in spt_connections:
|
|
boot = connection.get('boot')
|
|
if boot and boot.get('priority').lower() == 'primary':
|
|
return
|
|
message = (
|
|
"No primary boot connection configured for server profile"
|
|
" template %s." % server_profile_template.uri
|
|
)
|
|
raise exceptions.OneViewInconsistentResource(message)
|