Libvirt support in maasdriver
- Add validations that OOB configs for nodes are valid for the oob type defined - Add documentation for using Drydock/MAAS to deploy libvirt VMs - Add logic to update the MAAS node power parameters to allow power control of libvirt VMs Change-Id: Ia7d5fbd1659636d46cf1790fe3fc66ca6c6fee89
This commit is contained in:
parent
dbad75775b
commit
d107e65a98
|
@ -357,6 +357,55 @@ additional values. ``BaremetalNode`` *compute01* then adopts all values from the
|
|||
adopted from *defaults*) and can then again override or append any
|
||||
configuration that is specific to that node.
|
||||
|
||||
Defining Node Out-Of-Band Management
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Drydock supports plugin-based OOB management. At a minimum a
|
||||
OOB driver supports configuring a node to PXE boot during the next
|
||||
boot cycle and power cycling the node to initiate the provisioning
|
||||
process. Richer features might also be supported such as BIOS
|
||||
configuration or BMC log analysis. The value of ``oob.type`` in the
|
||||
host profile or baremetal node definition will define what additional
|
||||
parameters are required for that type and what capabilities are available
|
||||
via OOB driver tasks.
|
||||
|
||||
IPMI
|
||||
****
|
||||
|
||||
The ``ipmi`` OOB type requires additional configuration to allow OOB
|
||||
management:
|
||||
|
||||
1. The ``oob`` parameters ``account`` and ``credential`` must be populated with a valid
|
||||
account and password that can access the BMC via IPMI over LAN.
|
||||
2. The ``oob`` parameter ``network`` must reference which node network is used for OOB
|
||||
access.
|
||||
3. The ``addressing`` section of the node definition must contain an IP address assignment
|
||||
for the network referenced in ``oob.network``.
|
||||
|
||||
Currently the IPMI driver supports only basic management by setting nodes to PXE boot and
|
||||
power-cycling the node.
|
||||
|
||||
Libvirt
|
||||
*******
|
||||
|
||||
The ``libvirt`` OOB type requires additional configuration within the site definition
|
||||
as well as particular configuration in the deployment of Drydock (and likely the node
|
||||
provisioning driver.):
|
||||
|
||||
1. A SSH public/private key-pair should be generated with the public key being added
|
||||
to the authorized_keys file on all hypervisors hosting libvirt-based VMs being
|
||||
deployed. The account for this must be in the ``libvirt`` group.
|
||||
2. The private key should be provided in the Drydock and MAAS charts as an override to
|
||||
``conf.ssh.private_key``
|
||||
3. The Drydock and MAAS chart should override ``manifests.secret_ssh_key: true``.
|
||||
4. In the site definition, each libvirt-based node must define ``oob`` parameter
|
||||
``libvirt_uri`` of the form ``qemu+ssh://account@hostname/system`` where ``account``
|
||||
is an account in the libvirt group on the hypervisor with an authorized_key and
|
||||
``hostname`` is an IP address or FQDN for the hypervisor hosting the VM.
|
||||
|
||||
Currently the Libvirt driver supports only basic management by setting nodes to PXE boot and
|
||||
power-cycling the node.
|
||||
|
||||
Defining Node Interfaces and Network Addressing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -317,6 +317,42 @@ class Machine(model_base.ResourceBase):
|
|||
"Error setting node metadata, received HTTP %s from MaaS" %
|
||||
resp.status_code)
|
||||
|
||||
def set_power_parameters(self, power_type, **kwargs):
|
||||
"""Set power parameters for this node.
|
||||
|
||||
Only available after the node has been added to MAAS.
|
||||
|
||||
:param power_type: The type of power management for the node
|
||||
:param kwargs: Each kwargs key will be prepended with 'power_parameters_' and
|
||||
added to the list of updates for the node.
|
||||
"""
|
||||
if not power_type:
|
||||
raise errors.DriverError(
|
||||
"Cannot set power parameters. Must specify a power type.")
|
||||
|
||||
url = self.interpolate_url()
|
||||
|
||||
if kwargs:
|
||||
power_params = dict()
|
||||
|
||||
self.logger.debug("Setting node power type to %s." % power_type)
|
||||
self.power_type = power_type
|
||||
power_params['power_type'] = power_type
|
||||
|
||||
for k, v in kwargs.items():
|
||||
power_params['power_parameters_' + k] = v
|
||||
|
||||
self.logger.debug("Updating node %s power parameters: %s" %
|
||||
(self.hostname, str(power_params)))
|
||||
resp = self.api_client.put(url, files=power_params)
|
||||
|
||||
if resp.status_code == 200:
|
||||
return True
|
||||
|
||||
raise errors.DriverError(
|
||||
"Failed updating power parameters MAAS url %s - return code %s\n%s"
|
||||
% (url, resp.status_code.resp.text))
|
||||
|
||||
def to_dict(self):
|
||||
"""Serialize this resource instance into a dict.
|
||||
|
||||
|
@ -460,10 +496,22 @@ class Machines(model_base.ResourceCollectionBase):
|
|||
(maas_node.resource_id, node_model.get_id()))
|
||||
|
||||
if maas_node.hostname != node_model.name and update_name:
|
||||
maas_node.hostname = node_model.name
|
||||
maas_node.update()
|
||||
self.logger.debug("Updated MaaS resource %s hostname to %s" %
|
||||
(maas_node.resource_id, node_model.name))
|
||||
try:
|
||||
maas_node.hostname = node_model.name
|
||||
maas_node.update()
|
||||
if node_model.oob_type == 'libvirt':
|
||||
self.logger.debug(
|
||||
"Updating node %s MaaS power parameters for libvirt." %
|
||||
(node_model.name))
|
||||
oob_params = node_model.oob_parameters
|
||||
maas_node.set_power_parameters(
|
||||
'virsh',
|
||||
power_address=oob_params.get('libvirt_uri'),
|
||||
power_id=node_model.name)
|
||||
self.logger.debug("Updated MaaS resource %s hostname to %s" %
|
||||
(maas_node.resource_id, node_model.name))
|
||||
except Exception as ex:
|
||||
self.logger.debug("Error updating MAAS node: %s" % str(ex))
|
||||
|
||||
return maas_node
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# 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 drydock_provisioner.orchestrator.validations.validators import Validators
|
||||
|
||||
|
||||
class IpmiValidity(Validators):
|
||||
def __init__(self):
|
||||
super().__init__('Valid IPMI Configuration', 'DD4001')
|
||||
|
||||
def run_validation(self, site_design, orchestrator=None):
|
||||
"""For all IPMI-based nodes, check for a valid configuration.
|
||||
|
||||
1. Check that the node has an IP address assigned on the oob network
|
||||
2. Check that credentials are defined
|
||||
"""
|
||||
required_params = ['account', 'credential', 'network']
|
||||
|
||||
baremetal_node_list = site_design.baremetal_nodes or []
|
||||
|
||||
for baremetal_node in baremetal_node_list:
|
||||
if baremetal_node.oob_type == 'ipmi':
|
||||
for p in required_params:
|
||||
if not baremetal_node.oob_parameters.get(p, None):
|
||||
msg = (
|
||||
'OOB parameter %s for IPMI node %s missing.' % p,
|
||||
baremetal_node.name)
|
||||
self.report_error(msg, [baremetal_node.doc_ref],
|
||||
"Define OOB parameter %s" % p)
|
||||
oob_addr = None
|
||||
if baremetal_node.oob_parameters.get('network', None):
|
||||
oob_net = baremetal_node.oob_parameters.get('network')
|
||||
for a in baremetal_node.addressing:
|
||||
if a.network == oob_net:
|
||||
oob_addr = a.address
|
||||
if not oob_addr:
|
||||
msg = ('OOB address missing for IPMI node %s.' %
|
||||
baremetal_node.name)
|
||||
self.report_error(msg, [baremetal_node.doc_ref],
|
||||
"Provide address to node OOB interface.")
|
||||
return
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# 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 drydock_provisioner.orchestrator.validations.validators import Validators
|
||||
|
||||
|
||||
class LibvirtValidity(Validators):
|
||||
def __init__(self):
|
||||
super().__init__('Valid Libvirt Configuration', 'DD4002')
|
||||
|
||||
def run_validation(self, site_design, orchestrator=None):
|
||||
"""For all libvirt-based nodes, check for a valid configuration.
|
||||
|
||||
1. Check that the node has a valid libvirt_uri
|
||||
2. Check that boot MAC address is defined
|
||||
"""
|
||||
baremetal_node_list = site_design.baremetal_nodes or []
|
||||
|
||||
for baremetal_node in baremetal_node_list:
|
||||
if baremetal_node.oob_type == 'libvirt':
|
||||
libvirt_uri = baremetal_node.oob_parameters.get(
|
||||
'libvirt_uri', None)
|
||||
if not libvirt_uri:
|
||||
msg = ('OOB parameter libvirt_uri missing for node %s.' %
|
||||
baremetal_node.name)
|
||||
self.report_error(
|
||||
msg, [baremetal_node.doc_ref],
|
||||
"Provide libvirt URI to node hypervisor.")
|
||||
else:
|
||||
if not libvirt_uri.startswith("qemu+ssh"):
|
||||
msg = 'OOB parameter libvirt_uri has invalid scheme.'
|
||||
self.report_error(
|
||||
msg, [baremetal_node.doc_ref],
|
||||
"Only scheme 'qemu+ssh' is supported.")
|
||||
if not baremetal_node.boot_mac:
|
||||
msg = 'libvirt-based node requries defined boot MAC address.'
|
||||
self.report_error(msg, [
|
||||
baremetal_node.doc_ref
|
||||
], "Specify the node's PXE MAC address in metadata.boot_mac"
|
||||
)
|
||||
return
|
|
@ -28,6 +28,8 @@ from drydock_provisioner.orchestrator.validations.storage_partititioning import
|
|||
from drydock_provisioner.orchestrator.validations.storage_sizing import StorageSizing
|
||||
from drydock_provisioner.orchestrator.validations.unique_network_check import UniqueNetworkCheck
|
||||
from drydock_provisioner.orchestrator.validations.hostname_validity import HostnameValidity
|
||||
from drydock_provisioner.orchestrator.validations.oob_valid_ipmi import IpmiValidity
|
||||
from drydock_provisioner.orchestrator.validations.oob_valid_libvirt import LibvirtValidity
|
||||
|
||||
|
||||
class Validator():
|
||||
|
@ -88,4 +90,6 @@ rule_set = [
|
|||
StorageSizing(),
|
||||
UniqueNetworkCheck(),
|
||||
HostnameValidity(),
|
||||
IpmiValidity(),
|
||||
LibvirtValidity()
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue