561 lines
21 KiB
Python
561 lines
21 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
# coding=utf-8
|
|
|
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
|
# All 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.
|
|
#
|
|
#
|
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
"""
|
|
Client side of the conductor RPC API.
|
|
"""
|
|
|
|
from oslo_log import log
|
|
import oslo_messaging as messaging
|
|
|
|
from inventory.common import rpc
|
|
from inventory.objects import base as objects_base
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
MANAGER_TOPIC = 'inventory.conductor_manager'
|
|
|
|
|
|
class ConductorAPI(object):
|
|
"""Client side of the conductor RPC API.
|
|
|
|
API version history:
|
|
|
|
1.0 - Initial version.
|
|
"""
|
|
|
|
RPC_API_VERSION = '1.0'
|
|
|
|
# The default namespace, which can be overridden in a subclass.
|
|
RPC_API_NAMESPACE = None
|
|
|
|
def __init__(self, topic=None):
|
|
super(ConductorAPI, self).__init__()
|
|
self.topic = topic
|
|
if self.topic is None:
|
|
self.topic = MANAGER_TOPIC
|
|
target = messaging.Target(topic=self.topic,
|
|
version='1.0')
|
|
serializer = objects_base.InventoryObjectSerializer()
|
|
# release_ver = versions.RELEASE_MAPPING.get(CONF.pin_release_version)
|
|
# version_cap = (release_ver['rpc'] if release_ver
|
|
# else self.RPC_API_VERSION)
|
|
version_cap = self.RPC_API_VERSION
|
|
self.client = rpc.get_client(target,
|
|
version_cap=version_cap,
|
|
serializer=serializer)
|
|
|
|
@staticmethod
|
|
def make_namespaced_msg(method, namespace, **kwargs):
|
|
return {'method': method, 'namespace': namespace, 'args': kwargs}
|
|
|
|
def make_msg(self, method, **kwargs):
|
|
return self.make_namespaced_msg(method, self.RPC_API_NAMESPACE,
|
|
**kwargs)
|
|
|
|
# This is to be in inventory? However, it'll need to know the ip_address!
|
|
def handle_dhcp_lease(self, context, tags, mac, ip_address, cid=None,
|
|
topic=None):
|
|
"""Synchronously, have a conductor handle a DHCP lease update.
|
|
|
|
Handling depends on the interface:
|
|
- management interface: creates an ihost
|
|
- infrastructure interface: just updated the dnsmasq config
|
|
|
|
:param context: request context.
|
|
:param tags: specifies the interface type (mgmt or infra)
|
|
:param mac: MAC for the lease
|
|
:param ip_address: IP address for the lease
|
|
:param cid: Client ID for the lease
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'handle_dhcp_lease',
|
|
tags=tags,
|
|
mac=mac,
|
|
ip_address=ip_address,
|
|
cid=cid)
|
|
|
|
def create_host(self, context, values, topic=None):
|
|
"""Synchronously, have a conductor create an ihost.
|
|
|
|
Create an ihost in the database and return an object.
|
|
|
|
:param context: request context.
|
|
:param values: dictionary with initial values for new ihost object
|
|
:returns: created ihost object, including all fields.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'create_host',
|
|
values=values)
|
|
|
|
def update_host(self, context, ihost_obj, topic=None):
|
|
"""Synchronously, have a conductor update the hosts's information.
|
|
|
|
Update the ihost's information in the database and return an object.
|
|
|
|
:param context: request context.
|
|
:param ihost_obj: a changed (but not saved) ihost object.
|
|
:returns: updated ihost object, including all fields.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'update_host',
|
|
ihost_obj=ihost_obj)
|
|
|
|
def configure_host(self, context, host_obj,
|
|
do_compute_apply=False,
|
|
topic=None):
|
|
"""Synchronously, have a conductor configure an ihost.
|
|
|
|
Does the following tasks:
|
|
- invoke systemconfig to perform host configuration
|
|
- Update puppet hiera configuration files for the ihost.
|
|
- Add (or update) a host entry in the dnsmasq.conf file.
|
|
- Set up PXE configuration to run installer
|
|
|
|
:param context: request context.
|
|
:param host_obj: an ihost object.
|
|
:param do_compute_apply: apply the newly created compute manifests.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'configure_host',
|
|
host_obj=host_obj,
|
|
do_compute_apply=do_compute_apply)
|
|
|
|
def unconfigure_host(self, context, host_obj, topic=None):
|
|
"""Synchronously, have a conductor unconfigure a host.
|
|
|
|
Does the following tasks:
|
|
- Remove hiera config files for the host.
|
|
- Remove the host entry from the dnsmasq.conf file.
|
|
- Remove the PXE configuration
|
|
|
|
:param context: request context.
|
|
:param host_obj: a host object.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'unconfigure_host',
|
|
host_obj=host_obj)
|
|
|
|
def get_host_by_macs(self, context, host_macs, topic=None):
|
|
"""Finds hosts db entry based upon the mac list
|
|
|
|
This method returns a host if it matches a mac
|
|
|
|
:param context: an admin context
|
|
:param host_macs: list of mac addresses
|
|
:returns: host object
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
|
|
return cctxt.call(context,
|
|
'get_host_by_macs',
|
|
host_macs=host_macs)
|
|
|
|
def get_host_by_hostname(self, context, hostname, topic=None):
|
|
"""Finds host db entry based upon the ihost hostname
|
|
|
|
This method returns an ihost if it matches the
|
|
hostname.
|
|
|
|
:param context: an admin context
|
|
:param hostname: host hostname
|
|
:returns: host object, including all fields.
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'get_host_by_hostname',
|
|
hostname=hostname)
|
|
|
|
def platform_update_by_host(self, context,
|
|
host_uuid, imsg_dict, topic=None):
|
|
"""Create or update memory for an ihost with the supplied data.
|
|
|
|
This method allows records for memory for ihost to be created,
|
|
or updated.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param imsg_dict: inventory message dict
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic,
|
|
version='1.0')
|
|
return cctxt.call(context,
|
|
'platform_update_by_host',
|
|
host_uuid=host_uuid,
|
|
imsg_dict=imsg_dict)
|
|
|
|
def subfunctions_update_by_host(self, context,
|
|
host_uuid, subfunctions, topic=None):
|
|
"""Create or update local volume group for an ihost with the supplied
|
|
data.
|
|
|
|
This method allows records for a local volume group for ihost to be
|
|
created, or updated.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param subfunctions: subfunctions of the host
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'subfunctions_update_by_host',
|
|
host_uuid=host_uuid,
|
|
subfunctions=subfunctions)
|
|
|
|
def mgmt_ip_set_by_host(self,
|
|
context,
|
|
host_uuid,
|
|
mgmt_ip,
|
|
topic=None):
|
|
"""Call inventory to update host mgmt_ip (removes previous entry if
|
|
necessary)
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid
|
|
:param mgmt_ip: mgmt_ip
|
|
:returns: Address
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'mgmt_ip_set_by_host',
|
|
host_uuid=host_uuid,
|
|
mgmt_ip=mgmt_ip)
|
|
|
|
def infra_ip_set_by_host(self,
|
|
context,
|
|
host_uuid,
|
|
infra_ip, topic=None):
|
|
"""Call inventory to update host infra_ip (removes previous entry if
|
|
necessary)
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid
|
|
:param infra_ip: infra_ip
|
|
:returns: Address
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'infra_ip_set_by_host',
|
|
host_uuid=host_uuid,
|
|
infra_ip=infra_ip)
|
|
|
|
def vim_host_add(self, context, api_token, host_uuid,
|
|
hostname, subfunctions, administrative,
|
|
operational, availability,
|
|
subfunction_oper, subfunction_avail, timeout, topic=None):
|
|
"""
|
|
Asynchronously, notify VIM of host add
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.cast(context,
|
|
'vim_host_add',
|
|
api_token=api_token,
|
|
host_uuid=host_uuid,
|
|
hostname=hostname,
|
|
personality=subfunctions,
|
|
administrative=administrative,
|
|
operational=operational,
|
|
availability=availability,
|
|
subfunction_oper=subfunction_oper,
|
|
subfunction_avail=subfunction_avail,
|
|
timeout=timeout)
|
|
|
|
def notify_subfunctions_config(self, context,
|
|
host_uuid, ihost_notify_dict, topic=None):
|
|
"""
|
|
Synchronously, notify inventory of host subfunctions config status
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'notify_subfunctions_config',
|
|
host_uuid=host_uuid,
|
|
ihost_notify_dict=ihost_notify_dict)
|
|
|
|
def bm_deprovision_by_host(self, context,
|
|
host_uuid, ibm_msg_dict, topic=None):
|
|
"""Update ihost upon notification of board management controller
|
|
deprovisioning.
|
|
|
|
This method also allows a dictionary of values to be passed in to
|
|
affort additional controls, if and as needed.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param ibm_msg_dict: values for additional controls or changes
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'bm_deprovision_by_host',
|
|
host_uuid=host_uuid,
|
|
ibm_msg_dict=ibm_msg_dict)
|
|
|
|
def configure_ttys_dcd(self, context, uuid, ttys_dcd, topic=None):
|
|
"""Synchronously, have a conductor configure the dcd.
|
|
|
|
Does the following tasks:
|
|
- sends a message to conductor
|
|
- who sends a message to all inventory agents
|
|
- who has the uuid updates dcd
|
|
|
|
:param context: request context.
|
|
:param uuid: the host uuid
|
|
:param ttys_dcd: the flag to enable/disable dcd
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
LOG.debug("ConductorApi.configure_ttys_dcd: sending (%s %s) to "
|
|
"conductor" % (uuid, ttys_dcd))
|
|
return cctxt.call(context,
|
|
'configure_ttys_dcd',
|
|
uuid=uuid,
|
|
ttys_dcd=ttys_dcd)
|
|
|
|
def get_host_ttys_dcd(self, context, ihost_id, topic=None):
|
|
"""Synchronously, have a agent collect carrier detect state for this
|
|
ihost.
|
|
|
|
:param context: request context.
|
|
:param ihost_id: id of this host
|
|
:returns: ttys_dcd.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'get_host_ttys_dcd',
|
|
ihost_id=ihost_id)
|
|
|
|
def port_update_by_host(self, context,
|
|
host_uuid, inic_dict_array, topic=None):
|
|
"""Create iports for an ihost with the supplied data.
|
|
|
|
This method allows records for iports for ihost to be created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param inic_dict_array: initial values for iport objects
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'port_update_by_host',
|
|
host_uuid=host_uuid,
|
|
inic_dict_array=inic_dict_array)
|
|
|
|
def lldp_agent_update_by_host(self, context, host_uuid, agent_dict_array,
|
|
topic=None):
|
|
"""Create lldp_agents for an ihost with the supplied data.
|
|
|
|
This method allows records for lldp_agents for a host to be created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: host uuid unique id
|
|
:param agent_dict_array: initial values for lldp_agent objects
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'lldp_agent_update_by_host',
|
|
host_uuid=host_uuid,
|
|
agent_dict_array=agent_dict_array)
|
|
|
|
def lldp_neighbour_update_by_host(self, context,
|
|
host_uuid, neighbour_dict_array,
|
|
topic=None):
|
|
"""Create lldp_neighbours for an ihost with the supplied data.
|
|
|
|
This method allows records for lldp_neighbours for a host to be
|
|
created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param neighbour_dict_array: initial values for lldp_neighbour objects
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(
|
|
context,
|
|
'lldp_neighbour_update_by_host',
|
|
host_uuid=host_uuid,
|
|
neighbour_dict_array=neighbour_dict_array)
|
|
|
|
def pci_device_update_by_host(self, context,
|
|
host_uuid, pci_device_dict_array,
|
|
topic=None):
|
|
"""Create pci_devices for an ihost with the supplied data.
|
|
|
|
This method allows records for pci_devices for ihost to be created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param pci_device_dict_array: initial values for device objects
|
|
:returns: pass or fail
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'pci_device_update_by_host',
|
|
host_uuid=host_uuid,
|
|
pci_device_dict_array=pci_device_dict_array)
|
|
|
|
def numas_update_by_host(self,
|
|
context,
|
|
host_uuid,
|
|
inuma_dict_array,
|
|
topic=None):
|
|
"""Create inumas for an ihost with the supplied data.
|
|
|
|
This method allows records for inumas for ihost to be created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param inuma_dict_array: initial values for inuma objects
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'numas_update_by_host',
|
|
host_uuid=host_uuid,
|
|
inuma_dict_array=inuma_dict_array)
|
|
|
|
def cpus_update_by_host(self,
|
|
context,
|
|
host_uuid,
|
|
icpu_dict_array,
|
|
force_grub_update,
|
|
topic=None):
|
|
"""Create cpus for an ihost with the supplied data.
|
|
|
|
This method allows records for cpus for ihost to be created.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param icpu_dict_array: initial values for cpu objects
|
|
:param force_grub_update: bool value to force grub update
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'cpus_update_by_host',
|
|
host_uuid=host_uuid,
|
|
icpu_dict_array=icpu_dict_array,
|
|
force_grub_update=force_grub_update)
|
|
|
|
def memory_update_by_host(self, context,
|
|
host_uuid, imemory_dict_array,
|
|
force_update=False,
|
|
topic=None):
|
|
"""Create or update memory for an ihost with the supplied data.
|
|
|
|
This method allows records for memory for ihost to be created,
|
|
or updated.
|
|
|
|
:param context: an admin context
|
|
:param host_uuid: ihost uuid unique id
|
|
:param imemory_dict_array: initial values for memory objects
|
|
:param force_update: force a memory update
|
|
:returns: pass or fail
|
|
"""
|
|
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'memory_update_by_host',
|
|
host_uuid=host_uuid,
|
|
imemory_dict_array=imemory_dict_array,
|
|
force_update=force_update)
|
|
|
|
def update_cpu_config(self, context, topic=None):
|
|
"""Synchronously, have the conductor update the cpu
|
|
configuration.
|
|
|
|
:param context: request context.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context, 'update_cpu_config')
|
|
|
|
def create_barbican_secret(self, context, name, payload, topic=None):
|
|
"""Calls Barbican API to create a secret
|
|
|
|
:param context: request context.
|
|
:param name: secret name
|
|
:param payload: secret payload
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'create_barbican_secret',
|
|
name=name,
|
|
payload=payload)
|
|
|
|
def delete_barbican_secret(self, context, name, topic=None):
|
|
"""Calls Barbican API to delete a secret
|
|
|
|
:param context: request context.
|
|
:param name: secret name
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'delete_barbican_secret',
|
|
name=name)
|
|
|
|
def reload_snmp_config(self, context, topic=None):
|
|
"""Synchronously, have a conductor reload the SNMP configuration.
|
|
|
|
Does the following tasks:
|
|
- sighup snmpd to reload the snmpd configuration.
|
|
|
|
:param context: request context.
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context,
|
|
'reload_snmp_config')
|
|
|
|
def region_has_ceph_backend(self, context, topic=None):
|
|
"""
|
|
Send a request to primary region to see if ceph backend is configured
|
|
"""
|
|
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
|
return cctxt.call(context, 'region_has_ceph_backend')
|