Files
sushy-tools/sushy_tools/emulator/controllers/virtual_media.py
Dmitry Tantsur a654a033de Expose VirtualMedia on Systems in addition to Managers
VirtualMedia on Managers is deprecated, so make System the primary
source while keeping compatibility.

Change-Id: I933d0d5c9f78109f46eb314bef05cc8d653d7137
2023-12-11 13:44:30 +01:00

226 lines
7.6 KiB
Python

# 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 flask
from sushy_tools.emulator import api_utils
from sushy_tools import error
virtual_media = flask.Blueprint(
'VirtualMedia', __name__,
url_prefix='/redfish/v1/Systems/<identity>/VirtualMedia')
@virtual_media.route('', methods=['GET'])
@api_utils.returns_json
def virtual_media_collection_resource(identity):
api_utils.debug('Serving virtual media resources for system "%s"',
identity)
return flask.render_template(
'virtual_media_collection.json',
identity=identity,
uuid=flask.current_app.systems.uuid(identity),
devices=flask.current_app.vmedia.devices
)
@virtual_media.route('/<device>', methods=['GET'])
@api_utils.returns_json
def virtual_media_resource(identity, device):
device_name = flask.current_app.vmedia.get_device_name(
identity, device)
media_types = flask.current_app.vmedia.get_device_media_types(
identity, device)
device_info = flask.current_app.vmedia.get_device_image_info(
identity, device)
api_utils.debug('Serving virtual media %s at system "%s"',
device, identity)
return flask.render_template(
'virtual_media.json',
identity=identity,
device=device,
name=device_name,
media_types=media_types,
image_url=device_info.image_url,
image_name=device_info.image_name,
inserted=device_info.inserted,
write_protected=device_info.write_protected,
username=device_info.username,
password=device_info.password,
verify_certificate=device_info.verify,
)
@virtual_media.route('/<device>', methods=['PATCH'])
@api_utils.returns_json
def virtual_media_patch(identity, device):
flask.current_app.systems.uuid(identity)
if not flask.request.json:
raise error.BadRequest("Empty or malformed patch")
api_utils.debug('Updating virtual media %s at system "%s"',
device, identity)
verify = flask.request.json.get('VerifyCertificate')
if verify is not None:
if not isinstance(verify, bool):
raise error.BadRequest("VerifyCertificate must be a boolean")
flask.current_app.vmedia.update_device_info(
identity, device, verify=verify)
return '', 204
else:
raise error.BadRequest("Empty or malformed patch")
@virtual_media.route('/<device>/Certificates', methods=['GET'])
@api_utils.returns_json
def virtual_media_certificates(identity, device):
flask.current_app.systems.uuid(identity)
location = \
f'/redfish/v1/Systems/{identity}/VirtualMedia/{device}/Certificates'
certificates = flask.current_app.vmedia.list_certificates(identity, device)
return flask.render_template(
'certificate_collection.json',
location=location,
certificates=[cert.id for cert in certificates],
)
@virtual_media.route('/<device>/Certificates', methods=['POST'])
@api_utils.returns_json
def virtual_media_add_certificate(identity, device):
flask.current_app.systems.uuid(identity)
if not flask.request.json:
raise error.BadRequest("Empty or malformed certificate")
try:
cert_string = flask.request.json['CertificateString']
cert_type = flask.request.json['CertificateType']
except KeyError as exc:
raise error.BadRequest(f"Missing required parameter {exc}")
if cert_type != 'PEM':
raise error.BadRequest(
f"Only PEM certificates are supported, got {cert_type}")
api_utils.debug('Adding certificate for virtual media %s at '
'system "%s"', device, identity)
cert = flask.current_app.vmedia.add_certificate(
identity, device, cert_string, cert_type)
location = (
f'/redfish/v1/Systems/{identity}/VirtualMedia/{device}'
f'/Certificates/{cert.id}'
)
return '', 204, {'Location': location}
@virtual_media.route('/<device>/Certificates/<cert_id>', methods=['GET'])
@api_utils.returns_json
def virtual_media_get_certificate(identity, device, cert_id):
flask.current_app.systems.uuid(identity)
location = (
f'/redfish/v1/Systems/{identity}/VirtualMedia/{device}'
f'/Certificates/{cert_id}'
)
certificates = flask.current_app.vmedia.list_certificates(identity, device)
try:
cert = next(c for c in certificates if c.id == cert_id)
except StopIteration:
raise error.NotFound()
return flask.render_template(
'certificate.json',
location=location,
cert_id=cert.id,
cert_string=cert.string,
cert_type=cert.type_,
)
@virtual_media.route('/<device>/Certificates/<cert_id>', methods=['DELETE'])
@api_utils.returns_json
def virtual_media_delete_certificate(identity, device, cert_id):
flask.current_app.systems.uuid(identity)
api_utils.debug('Removing certificate %s for virtual media %s at '
'system "%s"', cert_id, device, identity)
flask.current_app.vmedia.delete_certificate(identity, device, cert_id)
return '', 204
@virtual_media.route('/<device>/Actions/VirtualMedia.InsertMedia',
methods=['POST'])
@api_utils.returns_json
def virtual_media_insert(identity, device):
image = flask.request.json.get('Image')
inserted = flask.request.json.get('Inserted', True)
write_protected = flask.request.json.get('WriteProtected', True)
username = flask.request.json.get('UserName', '')
password = flask.request.json.get('Password', '')
if (not username and password) or (username and not password):
message = "UserName and Password must be passed together"
return flask.render_template('error.json', message=message), 400
system = flask.current_app.systems.uuid(identity)
image_path = flask.current_app.vmedia.insert_image(
identity, device, image, inserted, write_protected,
username=username, password=password)
try:
flask.current_app.systems.set_boot_image(
system, device, boot_image=image_path,
write_protected=write_protected)
except error.NotSupportedError as ex:
api_utils.warning(
'System %s failed to set boot image %s on device %s: '
'%s', system, image_path, device, ex)
else:
api_utils.info(
'Virtual media placed into device %(dev)s for '
'system %(sys)s. Image %(img)s inserted %(ins)s',
{'dev': device, 'sys': identity,
'img': image or '<empty>', 'ins': inserted})
return '', 204
@virtual_media.route('/<device>/Actions/VirtualMedia.EjectMedia',
methods=['POST'])
@api_utils.returns_json
def virtual_media_eject(identity, device):
flask.current_app.vmedia.eject_image(identity, device)
try:
flask.current_app.systems.set_boot_image(identity, device)
except error.NotSupportedError as ex:
api_utils.warning(
'System %s failed to remove boot image from device %s: '
'%s', identity, device, ex)
else:
api_utils.info(
'Virtual media ejected from device %s system %s',
device, identity)
return '', 204