Fix bug of eject virtual CDROM in scciclient
This change will fix the case when Ironic tries to detach virtual CD if there is no ISO file attached. This applies to virtual floppy case as well. Change-Id: I4df5f6aa160fea0aff745fe929680aa61282c33e Signed-off-by: Nguyen Quang Huy <huynq@vn.fujitsu.com>
This commit is contained in:
parent
3f45624aa6
commit
6c3487815b
@ -289,8 +289,20 @@ def scci_cmd(host, userid, password, cmd, port=443, auth_method='basic',
|
|||||||
data = file.read()
|
data = file.read()
|
||||||
config_type = '/biosupdate'
|
config_type = '/biosupdate'
|
||||||
else:
|
else:
|
||||||
|
# For EJECT command, validate parameters to handle abnormal case
|
||||||
|
if check_eject_cd_cmd(cmd):
|
||||||
|
if not validate_params_cd_fd("cmd_cd", protocol,
|
||||||
|
host, auth_obj,
|
||||||
|
do_async, client_timeout):
|
||||||
|
return
|
||||||
|
if check_eject_fd_cmd(cmd):
|
||||||
|
if not validate_params_cd_fd("cmd_fd", protocol,
|
||||||
|
host, auth_obj,
|
||||||
|
do_async, client_timeout):
|
||||||
|
return
|
||||||
data = cmd
|
data = cmd
|
||||||
config_type = '/config'
|
config_type = '/config'
|
||||||
|
|
||||||
r = requests.post(protocol + '://' + host + config_type,
|
r = requests.post(protocol + '://' + host + config_type,
|
||||||
data=data,
|
data=data,
|
||||||
headers=header,
|
headers=header,
|
||||||
@ -343,6 +355,119 @@ def scci_cmd(host, userid, password, cmd, port=443, auth_method='basic',
|
|||||||
raise SCCIClientError(requests_exception)
|
raise SCCIClientError(requests_exception)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_params_cd_fd(cmd_type, protocol, host, auth_obj,
|
||||||
|
do_async, client_timeout):
|
||||||
|
"""Validate parameters of CD/DVD or FD Image Virtual Media in iRMC
|
||||||
|
|
||||||
|
If one of parameters (ImageServer, ImageShareName or ImageName) set in
|
||||||
|
ServerView Config Space is empty, and you try to eject virtual FD/CD,
|
||||||
|
iRMC returns error. This function determines whether iRMC doesn't return
|
||||||
|
error when you try to eject virtual FD/CD.
|
||||||
|
:param cmd_type: command type has value switch between "cmd_cd" or "cmd_fd"
|
||||||
|
:param protocol:
|
||||||
|
:param host: hostname or IP of iRMC
|
||||||
|
:param auth_obj: irmc userid/password
|
||||||
|
:param do_async: async call if True, sync call otherwise
|
||||||
|
:param client_timeout: timeout for SCCI operations
|
||||||
|
:return: False if one of param is null. Otherwise, returns True.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if cmd_type == "cmd_cd":
|
||||||
|
oe_image_server = "1A60"
|
||||||
|
oe_image_server_share_name = "1A65"
|
||||||
|
oe_image_name = "1A66"
|
||||||
|
else:
|
||||||
|
oe_image_server = "1A50"
|
||||||
|
oe_image_server_share_name = "1A55"
|
||||||
|
oe_image_name = "1A56"
|
||||||
|
|
||||||
|
try:
|
||||||
|
param = {'P45': '1', 'SAVE_DATA': '1'}
|
||||||
|
header = {'Content-type': 'application/x-www-form-urlencoded'}
|
||||||
|
r = requests.get(protocol + '://' + host + '/iRMC_Settings.pre',
|
||||||
|
params=param,
|
||||||
|
headers=header,
|
||||||
|
verify=False,
|
||||||
|
timeout=client_timeout,
|
||||||
|
allow_redirects=False,
|
||||||
|
auth=auth_obj)
|
||||||
|
if not do_async:
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
print("---------------------------")
|
||||||
|
print("Current iRMC configuration:")
|
||||||
|
print(r.url)
|
||||||
|
|
||||||
|
if r.status_code not in (200, 201):
|
||||||
|
raise SCCIClientError(
|
||||||
|
('HTTP PROTOCOL ERROR, STATUS CODE = %s' %
|
||||||
|
str(r.status_code)))
|
||||||
|
|
||||||
|
result = r.text
|
||||||
|
cmdseq = ET.fromstring(result)
|
||||||
|
cfg_dict = {}
|
||||||
|
for cmd_tag in cmdseq.iter(tag='CMD'):
|
||||||
|
oe = cmd_tag.get('OE')
|
||||||
|
data = cmd_tag.find('DATA').text
|
||||||
|
cfg_dict[oe] = data
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
print("Server: ", cfg_dict[oe_image_server])
|
||||||
|
print("Share Name: ", cfg_dict[oe_image_server_share_name])
|
||||||
|
print("Image Name: ", cfg_dict[oe_image_name])
|
||||||
|
print("---------------------------")
|
||||||
|
|
||||||
|
if (cfg_dict[oe_image_server] is None) or \
|
||||||
|
(cfg_dict[oe_image_server_share_name] is None) or \
|
||||||
|
(cfg_dict[oe_image_name] is None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
except ET.ParseError as parse_error:
|
||||||
|
raise SCCIClientError(parse_error)
|
||||||
|
except requests.exceptions.RequestException as requests_exception:
|
||||||
|
raise SCCIClientError(requests_exception)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def check_eject_cd_cmd(xml_cmd):
|
||||||
|
"""To check command is MOUNT or UNMOUNT
|
||||||
|
|
||||||
|
:param xml_cmd: the command
|
||||||
|
:return: true if this is UNMOUNT command. Otherwise, return false.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
cmdseq = ET.fromstring(xml_cmd.strip())
|
||||||
|
cmd = cmdseq.find("./CMD")
|
||||||
|
data = cmd.find("./DATA")
|
||||||
|
if cmd.get("OC") == "ConnectRemoteCdImage" and \
|
||||||
|
cmd.get("Type") == "SET" and data.text == "0":
|
||||||
|
return True
|
||||||
|
except ET.ParseError as parse_error:
|
||||||
|
raise SCCIClientError(parse_error)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def check_eject_fd_cmd(xml_cmd):
|
||||||
|
"""To check command is MOUNT or UNMOUNT
|
||||||
|
|
||||||
|
:param xml_cmd: the command
|
||||||
|
:return: true if this is UNMOUNT command. Otherwise, return false.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
cmdseq = ET.fromstring(xml_cmd.strip())
|
||||||
|
cmd = cmdseq.find("./CMD")
|
||||||
|
data = cmd.find("./DATA")
|
||||||
|
if cmd.get("OC") == "ConnectRemoteFdImage" and \
|
||||||
|
cmd.get("Type") == "SET" and data.text == "0":
|
||||||
|
return True
|
||||||
|
except ET.ParseError as parse_error:
|
||||||
|
raise SCCIClientError(parse_error)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_client(host, userid, password, port=443, auth_method='basic',
|
def get_client(host, userid, password, port=443, auth_method='basic',
|
||||||
client_timeout=60, **kwargs):
|
client_timeout=60, **kwargs):
|
||||||
"""get SCCI command partial function
|
"""get SCCI command partial function
|
||||||
|
@ -35,6 +35,103 @@ if six.PY3:
|
|||||||
file = io.BytesIO
|
file = io.BytesIO
|
||||||
|
|
||||||
|
|
||||||
|
IRMC_CONFIG_PARTIAL = """<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||||
|
<CMDSEQ>
|
||||||
|
<!-- "Many Items Ommited..." -->
|
||||||
|
<!-- "ConfBmcRemoteFdImageServer" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A50" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">10.124.196.156</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageUserName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A51" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageUserPassword" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A52" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageUserDomain" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A53" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageShareType" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A54" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageShareName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A55" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">/srv/nfs</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteFdImageImageName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A56" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">virtual-media.img</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcMediaOptionsFdAttachMode" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A57" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcMediaOptionsFdNumber" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A58" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageServer" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A60" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">10.124.196.156</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageUserName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A61" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageUserPassword" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A62" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageUserDomain" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A63" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string"></DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageShareType" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A64" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageShareName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A65" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">/srv/nfs</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcRemoteCdImageImageName" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A66" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::string">virtual-media.iso</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcMediaOptionsCdAttachMode" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A67" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "ConfBmcMediaOptionsCdNumber" -->
|
||||||
|
<CMD Context="SCCI" OC="ConfigSpace" OE="1A68" OI="0" Type="SET">
|
||||||
|
<DATA Type="xsd::integer">1</DATA>
|
||||||
|
<STATUS>0</STATUS>
|
||||||
|
</CMD>
|
||||||
|
<!-- "Many Items Ommited..." -->
|
||||||
|
</CMDSEQ>"""
|
||||||
|
|
||||||
|
|
||||||
class SCCITestCase(testtools.TestCase):
|
class SCCITestCase(testtools.TestCase):
|
||||||
"""Tests for SCCI
|
"""Tests for SCCI
|
||||||
|
|
||||||
@ -664,6 +761,9 @@ class SCCITestCase(testtools.TestCase):
|
|||||||
<Message>No Error</Message>
|
<Message>No Error</Message>
|
||||||
</Status>""")
|
</Status>""")
|
||||||
|
|
||||||
|
self.requests_mock.get("http://" + self.irmc_address +
|
||||||
|
"/iRMC_Settings.pre", text=IRMC_CONFIG_PARTIAL)
|
||||||
|
|
||||||
client = scci.get_client(self.irmc_address,
|
client = scci.get_client(self.irmc_address,
|
||||||
self.irmc_username,
|
self.irmc_username,
|
||||||
self.irmc_password,
|
self.irmc_password,
|
||||||
|
Loading…
Reference in New Issue
Block a user