|
Packit Service |
a04d08 |
# Copyright (C) 2012 Canonical Ltd.
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012 Yahoo! Inc.
|
|
Packit Service |
a04d08 |
#
|
|
Packit Service |
a04d08 |
# Author: Scott Moser <scott.moser@canonical.com>
|
|
Packit Service |
a04d08 |
# Author: Joshua Harlow <harlowja@yahoo-inc.com>
|
|
Packit Service |
a04d08 |
#
|
|
Packit Service |
a04d08 |
# This file is part of cloud-init. See LICENSE file for license information.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
import abc
|
|
Packit Service |
a04d08 |
import base64
|
|
Packit Service |
a04d08 |
import copy
|
|
Packit Service |
a04d08 |
import functools
|
|
Packit Service |
a04d08 |
import os
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
from cloudinit import ec2_utils
|
|
Packit Service |
a04d08 |
from cloudinit import log as logging
|
|
Packit Service |
a04d08 |
from cloudinit import net
|
|
Packit Service |
a04d08 |
from cloudinit import sources
|
|
Packit Service |
9bfd13 |
from cloudinit import subp
|
|
Packit Service |
a04d08 |
from cloudinit import url_helper
|
|
Packit Service |
a04d08 |
from cloudinit import util
|
|
Packit Service |
a04d08 |
from cloudinit.sources import BrokenMetadata
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# See https://docs.openstack.org/user-guide/cli-config-drive.html
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
LOG = logging.getLogger(__name__)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
FILES_V1 = {
|
|
Packit Service |
a04d08 |
# Path <-> (metadata key name, translator function, default value)
|
|
Packit Service |
a04d08 |
'etc/network/interfaces': ('network_config', lambda x: x, ''),
|
|
Packit Service |
a04d08 |
'meta.js': ('meta_js', util.load_json, {}),
|
|
Packit Service |
a04d08 |
"root/.ssh/authorized_keys": ('authorized_keys', lambda x: x, ''),
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
KEY_COPIES = (
|
|
Packit Service |
a04d08 |
# Cloud-init metadata names <-> (metadata key, is required)
|
|
Packit Service |
a04d08 |
('local-hostname', 'hostname', False),
|
|
Packit Service |
a04d08 |
('instance-id', 'uuid', True),
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Versions and names taken from nova source nova/api/metadata/base.py
|
|
Packit Service |
a04d08 |
OS_LATEST = 'latest'
|
|
Packit Service |
a04d08 |
OS_FOLSOM = '2012-08-10'
|
|
Packit Service |
a04d08 |
OS_GRIZZLY = '2013-04-04'
|
|
Packit Service |
a04d08 |
OS_HAVANA = '2013-10-17'
|
|
Packit Service |
a04d08 |
OS_LIBERTY = '2015-10-15'
|
|
Packit Service |
a04d08 |
# NEWTON_ONE adds 'devices' to md (sriov-pf-passthrough-neutron-port-vlan)
|
|
Packit Service |
a04d08 |
OS_NEWTON_ONE = '2016-06-30'
|
|
Packit Service |
a04d08 |
# NEWTON_TWO adds vendor_data2.json (vendordata-reboot)
|
|
Packit Service |
a04d08 |
OS_NEWTON_TWO = '2016-10-06'
|
|
Packit Service |
a04d08 |
# OS_OCATA adds 'vif' field to devices (sriov-pf-passthrough-neutron-port-vlan)
|
|
Packit Service |
a04d08 |
OS_OCATA = '2017-02-22'
|
|
Packit Service |
a04d08 |
# OS_ROCKY adds a vf_trusted field to devices (sriov-trusted-vfs)
|
|
Packit Service |
a04d08 |
OS_ROCKY = '2018-08-27'
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# keep this in chronological order. new supported versions go at the end.
|
|
Packit Service |
a04d08 |
OS_VERSIONS = (
|
|
Packit Service |
a04d08 |
OS_FOLSOM,
|
|
Packit Service |
a04d08 |
OS_GRIZZLY,
|
|
Packit Service |
a04d08 |
OS_HAVANA,
|
|
Packit Service |
a04d08 |
OS_LIBERTY,
|
|
Packit Service |
a04d08 |
OS_NEWTON_ONE,
|
|
Packit Service |
a04d08 |
OS_NEWTON_TWO,
|
|
Packit Service |
a04d08 |
OS_OCATA,
|
|
Packit Service |
a04d08 |
OS_ROCKY,
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
KNOWN_PHYSICAL_TYPES = (
|
|
Packit Service |
a04d08 |
None,
|
|
Packit Service |
a04d08 |
'bgpovs', # not present in OpenStack upstream but used on OVH cloud.
|
|
Packit Service |
a04d08 |
'bridge',
|
|
Packit Service |
9bfd13 |
'cascading', # not present in OpenStack upstream, used on OpenTelekomCloud
|
|
Packit Service |
a04d08 |
'dvs',
|
|
Packit Service |
a04d08 |
'ethernet',
|
|
Packit Service |
a04d08 |
'hw_veb',
|
|
Packit Service |
a04d08 |
'hyperv',
|
|
Packit Service |
a04d08 |
'ovs',
|
|
Packit Service |
a04d08 |
'phy',
|
|
Packit Service |
a04d08 |
'tap',
|
|
Packit Service |
a04d08 |
'vhostuser',
|
|
Packit Service |
a04d08 |
'vif',
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class NonReadable(IOError):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class SourceMixin(object):
|
|
Packit Service |
a04d08 |
def _ec2_name_to_device(self, name):
|
|
Packit Service |
a04d08 |
if not self.ec2_metadata:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
bdm = self.ec2_metadata.get('block-device-mapping', {})
|
|
Packit Service |
a04d08 |
for (ent_name, device) in bdm.items():
|
|
Packit Service |
a04d08 |
if name == ent_name:
|
|
Packit Service |
a04d08 |
return device
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_public_ssh_keys(self):
|
|
Packit Service |
a04d08 |
name = "public_keys"
|
|
Packit Service |
a04d08 |
if self.version == 1:
|
|
Packit Service |
a04d08 |
name = "public-keys"
|
|
Packit Service |
a04d08 |
return sources.normalize_pubkey_data(self.metadata.get(name))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _os_name_to_device(self, name):
|
|
Packit Service |
a04d08 |
device = None
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
criteria = 'LABEL=%s' % (name)
|
|
Packit Service |
a04d08 |
if name == 'swap':
|
|
Packit Service |
a04d08 |
criteria = 'TYPE=%s' % (name)
|
|
Packit Service |
a04d08 |
dev_entries = util.find_devs_with(criteria)
|
|
Packit Service |
a04d08 |
if dev_entries:
|
|
Packit Service |
a04d08 |
device = dev_entries[0]
|
|
Packit Service |
9bfd13 |
except subp.ProcessExecutionError:
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
return device
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _validate_device_name(self, device):
|
|
Packit Service |
a04d08 |
if not device:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
if not device.startswith("/"):
|
|
Packit Service |
a04d08 |
device = "/dev/%s" % device
|
|
Packit Service |
a04d08 |
if os.path.exists(device):
|
|
Packit Service |
a04d08 |
return device
|
|
Packit Service |
a04d08 |
# Durn, try adjusting the mapping
|
|
Packit Service |
a04d08 |
remapped = self._remap_device(os.path.basename(device))
|
|
Packit Service |
a04d08 |
if remapped:
|
|
Packit Service |
a04d08 |
LOG.debug("Remapped device name %s => %s", device, remapped)
|
|
Packit Service |
a04d08 |
return remapped
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def device_name_to_device(self, name):
|
|
Packit Service |
a04d08 |
# Translate a 'name' to a 'physical' device
|
|
Packit Service |
a04d08 |
if not name:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
# Try the ec2 mapping first
|
|
Packit Service |
a04d08 |
names = [name]
|
|
Packit Service |
a04d08 |
if name == 'root':
|
|
Packit Service |
a04d08 |
names.insert(0, 'ami')
|
|
Packit Service |
a04d08 |
if name == 'ami':
|
|
Packit Service |
a04d08 |
names.append('root')
|
|
Packit Service |
a04d08 |
device = None
|
|
Packit Service |
a04d08 |
LOG.debug("Using ec2 style lookup to find device %s", names)
|
|
Packit Service |
a04d08 |
for n in names:
|
|
Packit Service |
a04d08 |
device = self._ec2_name_to_device(n)
|
|
Packit Service |
a04d08 |
device = self._validate_device_name(device)
|
|
Packit Service |
a04d08 |
if device:
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
# Try the openstack way second
|
|
Packit Service |
a04d08 |
if not device:
|
|
Packit Service |
a04d08 |
LOG.debug("Using openstack style lookup to find device %s", names)
|
|
Packit Service |
a04d08 |
for n in names:
|
|
Packit Service |
a04d08 |
device = self._os_name_to_device(n)
|
|
Packit Service |
a04d08 |
device = self._validate_device_name(device)
|
|
Packit Service |
a04d08 |
if device:
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
# Ok give up...
|
|
Packit Service |
a04d08 |
if not device:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Mapped %s to device %s", name, device)
|
|
Packit Service |
a04d08 |
return device
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
class BaseReader(metaclass=abc.ABCMeta):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __init__(self, base_path):
|
|
Packit Service |
a04d08 |
self.base_path = base_path
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@abc.abstractmethod
|
|
Packit Service |
a04d08 |
def _path_join(self, base, *add_ons):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@abc.abstractmethod
|
|
Packit Service |
a04d08 |
def _path_read(self, path, decode=False):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@abc.abstractmethod
|
|
Packit Service |
a04d08 |
def _fetch_available_versions(self):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@abc.abstractmethod
|
|
Packit Service |
a04d08 |
def _read_ec2_metadata(self):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _find_working_version(self):
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
versions_available = self._fetch_available_versions()
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
LOG.debug("Unable to read openstack versions from %s due to: %s",
|
|
Packit Service |
a04d08 |
self.base_path, e)
|
|
Packit Service |
a04d08 |
versions_available = []
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# openstack.OS_VERSIONS is stored in chronological order, so
|
|
Packit Service |
a04d08 |
# reverse it to check newest first.
|
|
Packit Service |
a04d08 |
supported = [v for v in reversed(list(OS_VERSIONS))]
|
|
Packit Service |
a04d08 |
selected_version = OS_LATEST
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for potential_version in supported:
|
|
Packit Service |
a04d08 |
if potential_version not in versions_available:
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
selected_version = potential_version
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
LOG.debug("Selected version '%s' from %s", selected_version,
|
|
Packit Service |
a04d08 |
versions_available)
|
|
Packit Service |
a04d08 |
return selected_version
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _read_content_path(self, item, decode=False):
|
|
Packit Service |
a04d08 |
path = item.get('content_path', '').lstrip("/")
|
|
Packit Service |
a04d08 |
path_pieces = path.split("/")
|
|
Packit Service |
a04d08 |
valid_pieces = [p for p in path_pieces if len(p)]
|
|
Packit Service |
a04d08 |
if not valid_pieces:
|
|
Packit Service |
a04d08 |
raise BrokenMetadata("Item %s has no valid content path" % (item))
|
|
Packit Service |
a04d08 |
path = self._path_join(self.base_path, "openstack", *path_pieces)
|
|
Packit Service |
a04d08 |
return self._path_read(path, decode=decode)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def read_v2(self):
|
|
Packit Service |
a04d08 |
"""Reads a version 2 formatted location.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
Return a dict with metadata, userdata, ec2-metadata, dsmode,
|
|
Packit Service |
a04d08 |
network_config, files and version (2).
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
If not a valid location, raise a NonReadable exception.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
load_json_anytype = functools.partial(
|
|
Packit Service |
9bfd13 |
util.load_json, root_types=(dict, list, str))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def datafiles(version):
|
|
Packit Service |
a04d08 |
files = {}
|
|
Packit Service |
a04d08 |
files['metadata'] = (
|
|
Packit Service |
a04d08 |
# File path to read
|
|
Packit Service |
a04d08 |
self._path_join("openstack", version, 'meta_data.json'),
|
|
Packit Service |
a04d08 |
# Is it required?
|
|
Packit Service |
a04d08 |
True,
|
|
Packit Service |
a04d08 |
# Translator function (applied after loading)
|
|
Packit Service |
a04d08 |
util.load_json,
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
files['userdata'] = (
|
|
Packit Service |
a04d08 |
self._path_join("openstack", version, 'user_data'),
|
|
Packit Service |
a04d08 |
False,
|
|
Packit Service |
a04d08 |
lambda x: x,
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
files['vendordata'] = (
|
|
Packit Service |
a04d08 |
self._path_join("openstack", version, 'vendor_data.json'),
|
|
Packit Service |
a04d08 |
False,
|
|
Packit Service |
a04d08 |
load_json_anytype,
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
files['networkdata'] = (
|
|
Packit Service |
a04d08 |
self._path_join("openstack", version, 'network_data.json'),
|
|
Packit Service |
a04d08 |
False,
|
|
Packit Service |
a04d08 |
load_json_anytype,
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
return files
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
results = {
|
|
Packit Service |
a04d08 |
'userdata': '',
|
|
Packit Service |
a04d08 |
'version': 2,
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
data = datafiles(self._find_working_version())
|
|
Packit Service |
a04d08 |
for (name, (path, required, translator)) in data.items():
|
|
Packit Service |
a04d08 |
path = self._path_join(self.base_path, path)
|
|
Packit Service |
a04d08 |
data = None
|
|
Packit Service |
a04d08 |
found = False
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
data = self._path_read(path)
|
|
Packit Service |
a04d08 |
except IOError as e:
|
|
Packit Service |
a04d08 |
if not required:
|
|
Packit Service |
a04d08 |
LOG.debug("Failed reading optional path %s due"
|
|
Packit Service |
a04d08 |
" to: %s", path, e)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Failed reading mandatory path %s due"
|
|
Packit Service |
a04d08 |
" to: %s", path, e)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
found = True
|
|
Packit Service |
a04d08 |
if required and not found:
|
|
Packit Service |
a04d08 |
raise NonReadable("Missing mandatory path: %s" % path)
|
|
Packit Service |
a04d08 |
if found and translator:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
data = translator(data)
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Failed to process path %s: %s" % (path, e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
if found:
|
|
Packit Service |
a04d08 |
results[name] = data
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
metadata = results['metadata']
|
|
Packit Service |
a04d08 |
if 'random_seed' in metadata:
|
|
Packit Service |
a04d08 |
random_seed = metadata['random_seed']
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
metadata['random_seed'] = base64.b64decode(random_seed)
|
|
Packit Service |
a04d08 |
except (ValueError, TypeError) as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Badly formatted metadata random_seed entry: %s" % e
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# load any files that were provided
|
|
Packit Service |
a04d08 |
files = {}
|
|
Packit Service |
a04d08 |
metadata_files = metadata.get('files', [])
|
|
Packit Service |
a04d08 |
for item in metadata_files:
|
|
Packit Service |
a04d08 |
if 'path' not in item:
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
path = item['path']
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
files[path] = self._read_content_path(item)
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Failed to read provided file %s: %s" % (path, e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
results['files'] = files
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# The 'network_config' item in metadata is a content pointer
|
|
Packit Service |
a04d08 |
# to the network config that should be applied. It is just a
|
|
Packit Service |
a04d08 |
# ubuntu/debian '/etc/network/interfaces' file.
|
|
Packit Service |
a04d08 |
net_item = metadata.get("network_config", None)
|
|
Packit Service |
a04d08 |
if net_item:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
content = self._read_content_path(net_item, decode=True)
|
|
Packit Service |
a04d08 |
results['network_config'] = content
|
|
Packit Service |
a04d08 |
except IOError as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Failed to read network configuration: %s" % (e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# To openstack, user can specify meta ('nova boot --meta=key=value')
|
|
Packit Service |
a04d08 |
# and those will appear under metadata['meta'].
|
|
Packit Service |
a04d08 |
# if they specify 'dsmode' they're indicating the mode that they intend
|
|
Packit Service |
a04d08 |
# for this datasource to operate in.
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
results['dsmode'] = metadata['meta']['dsmode']
|
|
Packit Service |
a04d08 |
except KeyError:
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Read any ec2-metadata (if applicable)
|
|
Packit Service |
a04d08 |
results['ec2-metadata'] = self._read_ec2_metadata()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Perform some misc. metadata key renames...
|
|
Packit Service |
a04d08 |
for (target_key, source_key, is_required) in KEY_COPIES:
|
|
Packit Service |
a04d08 |
if is_required and source_key not in metadata:
|
|
Packit Service |
a04d08 |
raise BrokenMetadata("No '%s' entry in metadata" % source_key)
|
|
Packit Service |
a04d08 |
if source_key in metadata:
|
|
Packit Service |
a04d08 |
metadata[target_key] = metadata.get(source_key)
|
|
Packit Service |
a04d08 |
return results
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class ConfigDriveReader(BaseReader):
|
|
Packit Service |
a04d08 |
def __init__(self, base_path):
|
|
Packit Service |
a04d08 |
super(ConfigDriveReader, self).__init__(base_path)
|
|
Packit Service |
a04d08 |
self._versions = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _path_join(self, base, *add_ons):
|
|
Packit Service |
a04d08 |
components = [base] + list(add_ons)
|
|
Packit Service |
a04d08 |
return os.path.join(*components)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _path_read(self, path, decode=False):
|
|
Packit Service |
a04d08 |
return util.load_file(path, decode=decode)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _fetch_available_versions(self):
|
|
Packit Service |
a04d08 |
if self._versions is None:
|
|
Packit Service |
a04d08 |
path = self._path_join(self.base_path, 'openstack')
|
|
Packit Service |
a04d08 |
found = [d for d in os.listdir(path)
|
|
Packit Service |
a04d08 |
if os.path.isdir(os.path.join(path))]
|
|
Packit Service |
a04d08 |
self._versions = sorted(found)
|
|
Packit Service |
a04d08 |
return self._versions
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _read_ec2_metadata(self):
|
|
Packit Service |
a04d08 |
path = self._path_join(self.base_path,
|
|
Packit Service |
a04d08 |
'ec2', 'latest', 'meta-data.json')
|
|
Packit Service |
a04d08 |
if not os.path.exists(path):
|
|
Packit Service |
a04d08 |
return {}
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
return util.load_json(self._path_read(path))
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Failed to process path %s: %s" % (path, e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def read_v1(self):
|
|
Packit Service |
a04d08 |
"""Reads a version 1 formatted location.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
Return a dict with metadata, userdata, dsmode, files and version (1).
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
If not a valid path, raise a NonReadable exception.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
found = {}
|
|
Packit Service |
a04d08 |
for name in FILES_V1.keys():
|
|
Packit Service |
a04d08 |
path = self._path_join(self.base_path, name)
|
|
Packit Service |
a04d08 |
if os.path.exists(path):
|
|
Packit Service |
a04d08 |
found[name] = path
|
|
Packit Service |
a04d08 |
if len(found) == 0:
|
|
Packit Service |
a04d08 |
raise NonReadable("%s: no files found" % (self.base_path))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
md = {}
|
|
Packit Service |
a04d08 |
for (name, (key, translator, default)) in FILES_V1.items():
|
|
Packit Service |
a04d08 |
if name in found:
|
|
Packit Service |
a04d08 |
path = found[name]
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
contents = self._path_read(path)
|
|
Packit Service |
9bfd13 |
except IOError as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata("Failed to read: %s" % path) from e
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
9bfd13 |
# Disable not-callable pylint check; pylint isn't able to
|
|
Packit Service |
9bfd13 |
# determine that every member of FILES_V1 has a callable in
|
|
Packit Service |
9bfd13 |
# the appropriate position
|
|
Packit Service |
9bfd13 |
md[key] = translator(contents) # pylint: disable=E1102
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
9bfd13 |
raise BrokenMetadata(
|
|
Packit Service |
9bfd13 |
"Failed to process path %s: %s" % (path, e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
md[key] = copy.deepcopy(default)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
keydata = md['authorized_keys']
|
|
Packit Service |
a04d08 |
meta_js = md['meta_js']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# keydata in meta_js is preferred over "injected"
|
|
Packit Service |
a04d08 |
keydata = meta_js.get('public-keys', keydata)
|
|
Packit Service |
a04d08 |
if keydata:
|
|
Packit Service |
a04d08 |
lines = keydata.splitlines()
|
|
Packit Service |
9bfd13 |
md['public-keys'] = [
|
|
Packit Service |
9bfd13 |
line
|
|
Packit Service |
9bfd13 |
for line in lines
|
|
Packit Service |
9bfd13 |
if len(line) and not line.startswith("#")
|
|
Packit Service |
9bfd13 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# config-drive-v1 has no way for openstack to provide the instance-id
|
|
Packit Service |
a04d08 |
# so we copy that into metadata from the user input
|
|
Packit Service |
a04d08 |
if 'instance-id' in meta_js:
|
|
Packit Service |
a04d08 |
md['instance-id'] = meta_js['instance-id']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
results = {
|
|
Packit Service |
a04d08 |
'version': 1,
|
|
Packit Service |
a04d08 |
'metadata': md,
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# allow the user to specify 'dsmode' in a meta tag
|
|
Packit Service |
a04d08 |
if 'dsmode' in meta_js:
|
|
Packit Service |
a04d08 |
results['dsmode'] = meta_js['dsmode']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# config-drive-v1 has no way of specifying user-data, so the user has
|
|
Packit Service |
a04d08 |
# to cheat and stuff it in a meta tag also.
|
|
Packit Service |
a04d08 |
results['userdata'] = meta_js.get('user-data', '')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# this implementation does not support files other than
|
|
Packit Service |
a04d08 |
# network/interfaces and authorized_keys...
|
|
Packit Service |
a04d08 |
results['files'] = {}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return results
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class MetadataReader(BaseReader):
|
|
Packit Service |
a04d08 |
def __init__(self, base_url, ssl_details=None, timeout=5, retries=5):
|
|
Packit Service |
a04d08 |
super(MetadataReader, self).__init__(base_url)
|
|
Packit Service |
a04d08 |
self.ssl_details = ssl_details
|
|
Packit Service |
a04d08 |
self.timeout = float(timeout)
|
|
Packit Service |
a04d08 |
self.retries = int(retries)
|
|
Packit Service |
a04d08 |
self._versions = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _fetch_available_versions(self):
|
|
Packit Service |
a04d08 |
# <baseurl>/openstack/ returns a newline separated list of versions
|
|
Packit Service |
a04d08 |
if self._versions is not None:
|
|
Packit Service |
a04d08 |
return self._versions
|
|
Packit Service |
a04d08 |
found = []
|
|
Packit Service |
a04d08 |
version_path = self._path_join(self.base_path, "openstack")
|
|
Packit Service |
a04d08 |
content = self._path_read(version_path, decode=True)
|
|
Packit Service |
a04d08 |
for line in content.splitlines():
|
|
Packit Service |
a04d08 |
line = line.strip()
|
|
Packit Service |
a04d08 |
if not line:
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
found.append(line)
|
|
Packit Service |
a04d08 |
self._versions = found
|
|
Packit Service |
a04d08 |
return self._versions
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _path_read(self, path, decode=False):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def should_retry_cb(_request_args, cause):
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
code = int(cause.code)
|
|
Packit Service |
a04d08 |
if code >= 400:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
except (TypeError, ValueError):
|
|
Packit Service |
a04d08 |
# Older versions of requests didn't have a code.
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
return True
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
response = url_helper.readurl(path,
|
|
Packit Service |
a04d08 |
retries=self.retries,
|
|
Packit Service |
a04d08 |
ssl_details=self.ssl_details,
|
|
Packit Service |
a04d08 |
timeout=self.timeout,
|
|
Packit Service |
a04d08 |
exception_cb=should_retry_cb)
|
|
Packit Service |
a04d08 |
if decode:
|
|
Packit Service |
a04d08 |
return response.contents.decode()
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return response.contents
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _path_join(self, base, *add_ons):
|
|
Packit Service |
a04d08 |
return url_helper.combine_url(base, *add_ons)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _read_ec2_metadata(self):
|
|
Packit Service |
a04d08 |
return ec2_utils.get_instance_metadata(ssl_details=self.ssl_details,
|
|
Packit Service |
a04d08 |
timeout=self.timeout,
|
|
Packit Service |
a04d08 |
retries=self.retries)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Convert OpenStack ConfigDrive NetworkData json to network_config yaml
|
|
Packit Service |
a04d08 |
def convert_net_json(network_json=None, known_macs=None):
|
|
Packit Service |
a04d08 |
"""Return a dictionary of network_config by parsing provided
|
|
Packit Service |
a04d08 |
OpenStack ConfigDrive NetworkData json format
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
OpenStack network_data.json provides a 3 element dictionary
|
|
Packit Service |
a04d08 |
- "links" (links are network devices, physical or virtual)
|
|
Packit Service |
a04d08 |
- "networks" (networks are ip network configurations for one or more
|
|
Packit Service |
a04d08 |
links)
|
|
Packit Service |
a04d08 |
- services (non-ip services, like dns)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
networks and links are combined via network items referencing specific
|
|
Packit Service |
a04d08 |
links via a 'link_id' which maps to a links 'id' field.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
To convert this format to network_config yaml, we first iterate over the
|
|
Packit Service |
a04d08 |
links and then walk the network list to determine if any of the networks
|
|
Packit Service |
a04d08 |
utilize the current link; if so we generate a subnet entry for the device
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
We also need to map network_data.json fields to network_config fields. For
|
|
Packit Service |
a04d08 |
example, the network_data links 'id' field is equivalent to network_config
|
|
Packit Service |
a04d08 |
'name' field for devices. We apply more of this mapping to the various
|
|
Packit Service |
a04d08 |
link types that we encounter.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
There are additional fields that are populated in the network_data.json
|
|
Packit Service |
a04d08 |
from OpenStack that are not relevant to network_config yaml, so we
|
|
Packit Service |
a04d08 |
enumerate a dictionary of valid keys for network_yaml and apply filtering
|
|
Packit Service |
a04d08 |
to drop these superflous keys from the network_config yaml.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
if network_json is None:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# dict of network_config key for filtering network_json
|
|
Packit Service |
a04d08 |
valid_keys = {
|
|
Packit Service |
a04d08 |
'physical': [
|
|
Packit Service |
a04d08 |
'name',
|
|
Packit Service |
a04d08 |
'type',
|
|
Packit Service |
a04d08 |
'mac_address',
|
|
Packit Service |
a04d08 |
'subnets',
|
|
Packit Service |
a04d08 |
'params',
|
|
Packit Service |
a04d08 |
'mtu',
|
|
Packit Service |
a04d08 |
],
|
|
Packit Service |
a04d08 |
'subnet': [
|
|
Packit Service |
a04d08 |
'type',
|
|
Packit Service |
a04d08 |
'address',
|
|
Packit Service |
a04d08 |
'netmask',
|
|
Packit Service |
a04d08 |
'broadcast',
|
|
Packit Service |
a04d08 |
'metric',
|
|
Packit Service |
a04d08 |
'gateway',
|
|
Packit Service |
a04d08 |
'pointopoint',
|
|
Packit Service |
a04d08 |
'scope',
|
|
Packit Service |
a04d08 |
'dns_nameservers',
|
|
Packit Service |
a04d08 |
'dns_search',
|
|
Packit Service |
a04d08 |
'routes',
|
|
Packit Service |
a04d08 |
],
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
links = network_json.get('links', [])
|
|
Packit Service |
a04d08 |
networks = network_json.get('networks', [])
|
|
Packit Service |
a04d08 |
services = network_json.get('services', [])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
link_updates = []
|
|
Packit Service |
a04d08 |
link_id_info = {}
|
|
Packit Service |
a04d08 |
bond_name_fmt = "bond%d"
|
|
Packit Service |
a04d08 |
bond_number = 0
|
|
Packit Service |
a04d08 |
config = []
|
|
Packit Service |
a04d08 |
for link in links:
|
|
Packit Service |
a04d08 |
subnets = []
|
|
Packit Service |
a04d08 |
cfg = dict((k, v) for k, v in link.items()
|
|
Packit Service |
a04d08 |
if k in valid_keys['physical'])
|
|
Packit Service |
a04d08 |
# 'name' is not in openstack spec yet, but we will support it if it is
|
|
Packit Service |
a04d08 |
# present. The 'id' in the spec is currently implemented as the host
|
|
Packit Service |
a04d08 |
# nic's name, meaning something like 'tap-adfasdffd'. We do not want
|
|
Packit Service |
a04d08 |
# to name guest devices with such ugly names.
|
|
Packit Service |
a04d08 |
if 'name' in link:
|
|
Packit Service |
a04d08 |
cfg['name'] = link['name']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
link_mac_addr = None
|
|
Packit Service |
a04d08 |
if link.get('ethernet_mac_address'):
|
|
Packit Service |
a04d08 |
link_mac_addr = link.get('ethernet_mac_address').lower()
|
|
Packit Service |
a04d08 |
link_id_info[link['id']] = link_mac_addr
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
curinfo = {'name': cfg.get('name'), 'mac': link_mac_addr,
|
|
Packit Service |
a04d08 |
'id': link['id'], 'type': link['type']}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for network in [n for n in networks
|
|
Packit Service |
a04d08 |
if n['link'] == link['id']]:
|
|
Packit Service |
a04d08 |
subnet = dict((k, v) for k, v in network.items()
|
|
Packit Service |
a04d08 |
if k in valid_keys['subnet'])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if network['type'] == 'ipv4_dhcp':
|
|
Packit Service |
a04d08 |
subnet.update({'type': 'dhcp4'})
|
|
Packit Service |
a04d08 |
elif network['type'] == 'ipv6_dhcp':
|
|
Packit Service |
a04d08 |
subnet.update({'type': 'dhcp6'})
|
|
Packit Service |
a04d08 |
elif network['type'] in ['ipv6_slaac', 'ipv6_dhcpv6-stateless',
|
|
Packit Service |
a04d08 |
'ipv6_dhcpv6-stateful']:
|
|
Packit Service |
a04d08 |
subnet.update({'type': network['type']})
|
|
Packit Service |
be4044 |
elif network['type'] in ['ipv4', 'ipv6']:
|
|
Packit Service |
a04d08 |
subnet.update({
|
|
Packit Service |
a04d08 |
'type': 'static',
|
|
Packit Service |
a04d08 |
'address': network.get('ip_address'),
|
|
Packit Service |
a04d08 |
})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Enable accept_ra for stateful and legacy ipv6_dhcp types
|
|
Packit Service |
a04d08 |
if network['type'] in ['ipv6_dhcpv6-stateful', 'ipv6_dhcp']:
|
|
Packit Service |
a04d08 |
cfg.update({'accept-ra': True})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if network['type'] == 'ipv4':
|
|
Packit Service |
a04d08 |
subnet['ipv4'] = True
|
|
Packit Service |
a04d08 |
if network['type'] == 'ipv6':
|
|
Packit Service |
a04d08 |
subnet['ipv6'] = True
|
|
Packit Service |
a04d08 |
subnets.append(subnet)
|
|
Packit Service |
a04d08 |
cfg.update({'subnets': subnets})
|
|
Packit Service |
a04d08 |
if link['type'] in ['bond']:
|
|
Packit Service |
a04d08 |
params = {}
|
|
Packit Service |
a04d08 |
if link_mac_addr:
|
|
Packit Service |
a04d08 |
params['mac_address'] = link_mac_addr
|
|
Packit Service |
a04d08 |
for k, v in link.items():
|
|
Packit Service |
a04d08 |
if k == 'bond_links':
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
elif k.startswith('bond'):
|
|
Packit Service |
a04d08 |
params.update({k: v})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# openstack does not provide a name for the bond.
|
|
Packit Service |
a04d08 |
# they do provide an 'id', but that is possibly non-sensical.
|
|
Packit Service |
a04d08 |
# so we just create our own name.
|
|
Packit Service |
a04d08 |
link_name = bond_name_fmt % bond_number
|
|
Packit Service |
a04d08 |
bond_number += 1
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# bond_links reference links by their id, but we need to add
|
|
Packit Service |
a04d08 |
# to the network config by their nic name.
|
|
Packit Service |
a04d08 |
# store that in bond_links_needed, and update these later.
|
|
Packit Service |
a04d08 |
link_updates.append(
|
|
Packit Service |
a04d08 |
(cfg, 'bond_interfaces', '%s',
|
|
Packit Service |
a04d08 |
copy.deepcopy(link['bond_links']))
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
cfg.update({'params': params, 'name': link_name})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
curinfo['name'] = link_name
|
|
Packit Service |
a04d08 |
elif link['type'] in ['vlan']:
|
|
Packit Service |
a04d08 |
name = "%s.%s" % (link['vlan_link'], link['vlan_id'])
|
|
Packit Service |
a04d08 |
cfg.update({
|
|
Packit Service |
a04d08 |
'name': name,
|
|
Packit Service |
a04d08 |
'vlan_id': link['vlan_id'],
|
|
Packit Service |
a04d08 |
'mac_address': link['vlan_mac_address'],
|
|
Packit Service |
a04d08 |
})
|
|
Packit Service |
a04d08 |
link_updates.append((cfg, 'vlan_link', '%s', link['vlan_link']))
|
|
Packit Service |
a04d08 |
link_updates.append((cfg, 'name', "%%s.%s" % link['vlan_id'],
|
|
Packit Service |
a04d08 |
link['vlan_link']))
|
|
Packit Service |
a04d08 |
curinfo.update({'mac': link['vlan_mac_address'],
|
|
Packit Service |
a04d08 |
'name': name})
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
if link['type'] not in KNOWN_PHYSICAL_TYPES:
|
|
Packit Service |
a04d08 |
LOG.warning('Unknown network_data link type (%s); treating as'
|
|
Packit Service |
a04d08 |
' physical', link['type'])
|
|
Packit Service |
a04d08 |
cfg.update({'type': 'physical', 'mac_address': link_mac_addr})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
config.append(cfg)
|
|
Packit Service |
a04d08 |
link_id_info[curinfo['id']] = curinfo
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
need_names = [d for d in config
|
|
Packit Service |
a04d08 |
if d.get('type') == 'physical' and 'name' not in d]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if need_names or link_updates:
|
|
Packit Service |
a04d08 |
if known_macs is None:
|
|
Packit Service |
a04d08 |
known_macs = net.get_interfaces_by_mac()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# go through and fill out the link_id_info with names
|
|
Packit Service |
a04d08 |
for _link_id, info in link_id_info.items():
|
|
Packit Service |
a04d08 |
if info.get('name'):
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
if info.get('mac') in known_macs:
|
|
Packit Service |
a04d08 |
info['name'] = known_macs[info['mac']]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for d in need_names:
|
|
Packit Service |
a04d08 |
mac = d.get('mac_address')
|
|
Packit Service |
a04d08 |
if not mac:
|
|
Packit Service |
a04d08 |
raise ValueError("No mac_address or name entry for %s" % d)
|
|
Packit Service |
a04d08 |
if mac not in known_macs:
|
|
Packit Service |
a04d08 |
raise ValueError("Unable to find a system nic for %s" % d)
|
|
Packit Service |
a04d08 |
d['name'] = known_macs[mac]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
for cfg, key, fmt, targets in link_updates:
|
|
Packit Service |
9bfd13 |
if isinstance(targets, (list, tuple)):
|
|
Packit Service |
9bfd13 |
cfg[key] = [
|
|
Packit Service |
9bfd13 |
fmt % link_id_info[target]['name'] for target in targets
|
|
Packit Service |
9bfd13 |
]
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
9bfd13 |
cfg[key] = fmt % link_id_info[targets]['name']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Infiniband interfaces may be referenced in network_data.json by a 6 byte
|
|
Packit Service |
a04d08 |
# Ethernet MAC-style address, and we use that address to look up the
|
|
Packit Service |
a04d08 |
# interface name above. Now ensure that the hardware address is set to the
|
|
Packit Service |
a04d08 |
# full 20 byte address.
|
|
Packit Service |
a04d08 |
ib_known_hwaddrs = net.get_ib_hwaddrs_by_interface()
|
|
Packit Service |
a04d08 |
if ib_known_hwaddrs:
|
|
Packit Service |
a04d08 |
for cfg in config:
|
|
Packit Service |
a04d08 |
if cfg['name'] in ib_known_hwaddrs:
|
|
Packit Service |
a04d08 |
cfg['mac_address'] = ib_known_hwaddrs[cfg['name']]
|
|
Packit Service |
a04d08 |
cfg['type'] = 'infiniband'
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for service in services:
|
|
Packit Service |
a04d08 |
cfg = service
|
|
Packit Service |
a04d08 |
cfg.update({'type': 'nameserver'})
|
|
Packit Service |
a04d08 |
config.append(cfg)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return {'version': 1, 'config': config}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# vi: ts=4 expandtab
|