Fix virtual media insertion of invalid url

This patch fixes 'insert_virutal_media' api to through an error
when the url given is either invalid or unreachable.

Closes-Bug: 1958976
Change-Id: I1d49086e214fe86a5bf5bc3986e7e886ee28ff30
This commit is contained in:
paresh-sao 2022-02-10 11:10:36 +00:00
parent 682eb63985
commit 792cd4185b
8 changed files with 69 additions and 16 deletions

View File

@ -1,3 +1,4 @@
# Copyright 2022 Hewlett Packard Enterprise Development Company, L.P.
# Copyright 2018 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -34,6 +35,7 @@ from proliantutils.ilo import firmware_controller
from proliantutils.ilo import mappings
from proliantutils.ilo import operations
from proliantutils import log
from proliantutils import utils
POWER_STATE = {
@ -423,6 +425,10 @@ class RIBCLOperations(operations.IloOperations):
'DEVICE': device.upper(),
'IMAGE_URL': url,
}
# Validate url
utils.validate_href(url)
data = self._execute_command(
'INSERT_VIRTUAL_MEDIA', 'RIB_INFO', 'write', dic)
return data

View File

@ -1,4 +1,4 @@
# Copyright 2018 Hewlett Packard Enterprise Development Company, L.P.
# Copyright 2018-2022 Hewlett Packard Enterprise 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
@ -1506,6 +1506,9 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations):
:raises: IloCommandNotSupportedError, if the command is not supported
on the server.
"""
# Validate url
utils.validate_href(url)
response, vm_device_uri = self._get_vm_device_status(device)
# Eject media if there is one. RIBCL was tolerant enough to overwrite

View File

@ -1,4 +1,4 @@
# Copyright 2018 Hewlett Packard Enterprise Development LP
# Copyright 2018-2022 Hewlett Packard Enterprise 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
@ -455,6 +455,8 @@ class RedfishOperations(operations.IloOperations):
:raises: IloError, on an error from iLO.
:raises: IloInvalidInputError, if the device is not valid.
"""
# Validate url
common_utils.validate_href(url)
self._validate_virtual_media(device)
manager = self._get_sushy_manager(PROLIANT_MANAGER_ID)
try:

View File

@ -1,3 +1,4 @@
# Copyright 2022 Hewlett Packard Enterprise Development Company, L.P.
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
@ -32,6 +33,7 @@ from proliantutils.ilo import common
from proliantutils.ilo import constants as cons
from proliantutils.ilo import ribcl
from proliantutils.tests.ilo import ribcl_sample_outputs as constants
from proliantutils import utils
class MaskedRequestDataTestCase(unittest.TestCase):
@ -275,11 +277,13 @@ class IloRibclTestCase(unittest.TestCase):
self.assertTrue(request_ilo_mock.called)
@mock.patch.object(ribcl.RIBCLOperations, '_request_ilo')
def test_insert_virtual_media(self, request_ilo_mock):
@mock.patch.object(utils, 'validate_href')
def test_insert_virtual_media(self, validate_href_mock, request_ilo_mock):
request_ilo_mock.return_value = constants.INSERT_VIRTUAL_MEDIA_XML
result = self.ilo.insert_virtual_media('any_url', 'floppy')
self.assertIsNone(result)
self.assertTrue(request_ilo_mock.called)
validate_href_mock.assert_called_once_with('any_url')
@mock.patch.object(ribcl.RIBCLOperations, 'get_vm_status')
@mock.patch.object(ribcl.RIBCLOperations, '_request_ilo')
@ -1036,11 +1040,13 @@ class IloRibclTestCaseBeforeRisSupport(unittest.TestCase):
self.assertTrue(request_ilo_mock.called)
@mock.patch.object(ribcl.IloClient, '_request_ilo')
def test_insert_virtual_media(self, request_ilo_mock):
@mock.patch.object(utils, 'validate_href')
def test_insert_virtual_media(self, validate_href_mock, request_ilo_mock):
request_ilo_mock.return_value = constants.INSERT_VIRTUAL_MEDIA_XML
result = self.ilo.insert_virtual_media('any_url', 'floppy')
self.assertIsNone(result)
self.assertTrue(request_ilo_mock.called)
validate_href_mock.assert_called_once_with('any_url')
@mock.patch.object(ribcl.RIBCLOperations, 'get_vm_status')
@mock.patch.object(ribcl.IloClient, '_request_ilo')

View File

@ -1,3 +1,4 @@
# Copyright 2022 Hewlett Packard Enterprise Development Company, L.P.
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
@ -837,7 +838,9 @@ class IloRisTestCase(testtools.TestCase):
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, '_get_vm_device_status')
def test_insert_virtual_media(self, get_vm_device_mock, patch_mock):
@mock.patch.object(utils, 'validate_href')
def test_insert_virtual_media(
self, validate_href_mock, get_vm_device_mock, patch_mock):
vm_uri = '/rest/v1/Managers/1/VirtualMedia/2'
cdrom_resp = json.loads(ris_outputs.RESP_VM_STATUS_CDROM_EMPTY)
@ -852,11 +855,14 @@ class IloRisTestCase(testtools.TestCase):
device='CDROM')
get_vm_device_mock.assert_called_once_with('CDROM')
patch_mock.assert_called_once_with(vm_uri, None, vm_patch)
validate_href_mock.assert_called_once_with('http://1.1.1.1/cdrom.iso')
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, 'eject_virtual_media')
@mock.patch.object(ris.RISOperations, '_get_vm_device_status')
@mock.patch.object(utils, 'validate_href')
def test_insert_virtual_media_media_attached(self,
validate_href_mock,
get_vm_device_mock,
eject_virtual_media_mock,
patch_mock):
@ -875,10 +881,13 @@ class IloRisTestCase(testtools.TestCase):
get_vm_device_mock.assert_called_once_with('CDROM')
eject_virtual_media_mock.assert_called_once_with('CDROM')
patch_mock.assert_called_once_with(vm_uri, None, vm_patch)
validate_href_mock.assert_called_once_with('http://1.1.1.1/cdrom.iso')
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, '_get_vm_device_status')
def test_insert_virtual_media_fail(self, get_vm_device_mock, patch_mock):
@mock.patch.object(utils, 'validate_href')
def test_insert_virtual_media_fail(
self, validate_href_mock, get_vm_device_mock, patch_mock):
vm_uri = '/rest/v1/Managers/1/VirtualMedia/2'
cdrom_resp = json.loads(ris_outputs.RESP_VM_STATUS_CDROM_EMPTY)
@ -894,6 +903,7 @@ class IloRisTestCase(testtools.TestCase):
'http://1.1.1.1/cdrom.iso', device='CDROM')
get_vm_device_mock.assert_called_once_with('CDROM')
patch_mock.assert_called_once_with(vm_uri, None, vm_patch)
validate_href_mock.assert_called_once_with('http://1.1.1.1/cdrom.iso')
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, '_get_vm_device_status')

View File

@ -1,4 +1,4 @@
# Copyright 2019 Hewlett Packard Enterprise Development LP
# Copyright 2019-2022 Hewlett Packard Enterprise Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -44,6 +44,7 @@ from proliantutils.redfish.resources.system.storage import array_controller
from proliantutils.redfish.resources.system.storage \
import common as common_storage
from proliantutils.redfish.resources.system import system as pro_sys
from proliantutils import utils as common_utils
@ddt.ddt
@ -334,7 +335,9 @@ class RedfishOperationsTestCase(testtools.TestCase):
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
@mock.patch.object(virtual_media.VirtualMedia, 'eject_media')
@mock.patch.object(virtual_media.VirtualMedia, 'insert_media')
def test_insert_virtual_media(self, insert_mock, eject_mock, manager_mock):
@mock.patch.object(common_utils, 'validate_href')
def test_insert_virtual_media(
self, validate_href_mock, insert_mock, eject_mock, manager_mock):
manager_mock.return_value, vmedia_collection_json, vmedia_json = (
self._setup_virtual_media())
self.conn.get.return_value.json.side_effect = [
@ -345,12 +348,14 @@ class RedfishOperationsTestCase(testtools.TestCase):
self.assertFalse(eject_mock.called)
insert_mock.assert_called_once_with(url)
validate_href_mock.assert_called_once_with(url)
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
@mock.patch.object(virtual_media.VirtualMedia, 'eject_media')
@mock.patch.object(virtual_media.VirtualMedia, 'insert_media')
def test_insert_virtual_media_floppy(self, insert_mock, eject_mock,
manager_mock):
@mock.patch.object(common_utils, 'validate_href')
def test_insert_virtual_media_floppy(
self, validate_href_mock, insert_mock, eject_mock, manager_mock):
manager_mock.return_value, vmedia_collection_json, vmedia_json = (
self._setup_virtual_media())
self.conn.get.return_value.json.side_effect = [
@ -361,12 +366,14 @@ class RedfishOperationsTestCase(testtools.TestCase):
self.assertFalse(eject_mock.called)
insert_mock.assert_called_once_with(url)
validate_href_mock.assert_called_once_with(url)
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
@mock.patch.object(virtual_media.VirtualMedia, 'eject_media')
@mock.patch.object(virtual_media.VirtualMedia, 'insert_media')
def test_insert_virtual_media_inserted(self, insert_mock, eject_mock,
manager_mock):
@mock.patch.object(common_utils, 'validate_href')
def test_insert_virtual_media_inserted(
self, validate_href_mock, insert_mock, eject_mock, manager_mock):
manager_mock.return_value, vmedia_collection_json, vmedia_json = (
self._setup_virtual_media())
self.conn.get.return_value.json.side_effect = [
@ -377,12 +384,14 @@ class RedfishOperationsTestCase(testtools.TestCase):
eject_mock.assert_called_once_with()
insert_mock.assert_called_once_with(url)
validate_href_mock.assert_called_once_with(url)
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
@mock.patch.object(virtual_media.VirtualMedia, 'eject_media')
@mock.patch.object(virtual_media.VirtualMedia, 'insert_media')
def test_insert_virtual_media_fail(self, insert_mock, eject_mock,
manager_mock):
@mock.patch.object(common_utils, 'validate_href')
def test_insert_virtual_media_fail(
self, validate_href_mock, insert_mock, eject_mock, manager_mock):
manager_mock.return_value, vmedia_collection_json, vmedia_json = (
self._setup_virtual_media())
insert_mock.side_effect = sushy.exceptions.SushyError
@ -395,6 +404,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
self.assertRaisesRegex(exception.IloError, msg,
self.rf_client.insert_virtual_media,
url, 'CDROM')
validate_href_mock.assert_called_once_with(url)
@mock.patch.object(virtual_media.VirtualMedia, 'set_vm_status')
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')

View File

@ -1,4 +1,4 @@
# Copyright 2016 Hewlett Packard Enterprise Company, L.P.
# Copyright 2016-2022 Hewlett Packard Enterprise Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -260,6 +260,14 @@ class UtilsTestCase(testtools.TestCase):
utils.validate_href, href)
head_mock.assert_called_once_with(href)
@mock.patch.object(requests, 'head', autospec=True)
def test_validate_href_error_no_base_image(self, head_mock):
href = 'http://1.2.3.4/'
head_mock.return_value.status_code = http_client.OK
self.assertRaises(exception.ImageRefValidationFailed,
utils.validate_href, href)
head_mock.assert_called_once_with(href)
def test_apply_bios_properties_filter(self):
data = {
"AdminName": "Administrator",

View File

@ -1,4 +1,4 @@
# Copyright 2016 Hewlett Packard Enterprise Company, L.P.
# Copyright 2016-2022 Hewlett Packard Enterprise 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
@ -16,7 +16,9 @@
Non-iLO related utilities and helper functions.
"""
import hashlib
import os
import re
from urllib import parse
import requests
import six
@ -150,6 +152,12 @@ def validate_href(image_href):
image_href=image_href,
reason=("Got HTTP code %s instead of 200 in response to "
"HEAD request." % response.status_code))
path = parse.urlsplit(image_href).path
if os.path.basename(path) == '':
raise exception.ImageRefValidationFailed(
image_href=image_href,
reason=("Given URL is not reachable."))
except requests.RequestException as e:
raise exception.ImageRefValidationFailed(image_href=image_href,
reason=e)