|
Packit Service |
a04d08 |
# Copyright (C) 2012 Canonical Ltd.
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012 Yahoo! Inc.
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012-2013 CERIT Scientific Cloud
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012-2013 OpenNebula.org
|
|
Packit Service |
a04d08 |
# Copyright (C) 2014 Consejo Superior de Investigaciones Cientificas
|
|
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 |
# Author: Vlastimil Holer <xholer@mail.muni.cz>
|
|
Packit Service |
a04d08 |
# Author: Javier Fontan <jfontan@opennebula.org>
|
|
Packit Service |
a04d08 |
# Author: Enol Fernandez <enolfc@ifca.unican.es>
|
|
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 collections
|
|
Packit Service |
9bfd13 |
import functools
|
|
Packit Service |
a04d08 |
import os
|
|
Packit Service |
a04d08 |
import pwd
|
|
Packit Service |
a04d08 |
import re
|
|
Packit Service |
a04d08 |
import string
|
|
Packit Service |
a04d08 |
|
|
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 util
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
LOG = logging.getLogger(__name__)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
DEFAULT_IID = "iid-dsopennebula"
|
|
Packit Service |
a04d08 |
DEFAULT_PARSEUSER = 'nobody'
|
|
Packit Service |
a04d08 |
CONTEXT_DISK_FILES = ["context.sh"]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class DataSourceOpenNebula(sources.DataSource):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
dsname = "OpenNebula"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __init__(self, sys_cfg, distro, paths):
|
|
Packit Service |
a04d08 |
sources.DataSource.__init__(self, sys_cfg, distro, paths)
|
|
Packit Service |
a04d08 |
self.seed = None
|
|
Packit Service |
a04d08 |
self.seed_dir = os.path.join(paths.seed_dir, 'opennebula')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __str__(self):
|
|
Packit Service |
a04d08 |
root = sources.DataSource.__str__(self)
|
|
Packit Service |
a04d08 |
return "%s [seed=%s][dsmode=%s]" % (root, self.seed, self.dsmode)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_data(self):
|
|
Packit Service |
a04d08 |
defaults = {"instance-id": DEFAULT_IID}
|
|
Packit Service |
a04d08 |
results = None
|
|
Packit Service |
a04d08 |
seed = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# decide parseuser for context.sh shell reader
|
|
Packit Service |
a04d08 |
parseuser = DEFAULT_PARSEUSER
|
|
Packit Service |
a04d08 |
if 'parseuser' in self.ds_cfg:
|
|
Packit Service |
a04d08 |
parseuser = self.ds_cfg.get('parseuser')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
candidates = [self.seed_dir]
|
|
Packit Service |
a04d08 |
candidates.extend(find_candidate_devs())
|
|
Packit Service |
a04d08 |
for cdev in candidates:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
if os.path.isdir(self.seed_dir):
|
|
Packit Service |
9bfd13 |
results = read_context_disk_dir(
|
|
Packit Service |
9bfd13 |
cdev, self.distro, asuser=parseuser
|
|
Packit Service |
9bfd13 |
)
|
|
Packit Service |
a04d08 |
elif cdev.startswith("/dev"):
|
|
Packit Service |
9bfd13 |
# util.mount_cb only handles passing a single argument
|
|
Packit Service |
9bfd13 |
# through to the wrapped function, so we have to partially
|
|
Packit Service |
9bfd13 |
# apply the function to pass in `distro`. See LP: #1884979
|
|
Packit Service |
9bfd13 |
partially_applied_func = functools.partial(
|
|
Packit Service |
9bfd13 |
read_context_disk_dir,
|
|
Packit Service |
9bfd13 |
asuser=parseuser,
|
|
Packit Service |
9bfd13 |
distro=self.distro,
|
|
Packit Service |
9bfd13 |
)
|
|
Packit Service |
9bfd13 |
results = util.mount_cb(cdev, partially_applied_func)
|
|
Packit Service |
a04d08 |
except NonContextDiskDir:
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
except BrokenContextDiskDir as exc:
|
|
Packit Service |
a04d08 |
raise exc
|
|
Packit Service |
a04d08 |
except util.MountFailedError:
|
|
Packit Service |
a04d08 |
LOG.warning("%s was not mountable", cdev)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if results:
|
|
Packit Service |
a04d08 |
seed = cdev
|
|
Packit Service |
a04d08 |
LOG.debug("found datasource in %s", cdev)
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if not seed:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# merge fetched metadata with datasource defaults
|
|
Packit Service |
a04d08 |
md = results['metadata']
|
|
Packit Service |
a04d08 |
md = util.mergemanydict([md, defaults])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# check for valid user specified dsmode
|
|
Packit Service |
a04d08 |
self.dsmode = self._determine_dsmode(
|
|
Packit Service |
a04d08 |
[results.get('DSMODE'), self.ds_cfg.get('dsmode')])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if self.dsmode == sources.DSMODE_DISABLED:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
self.seed = seed
|
|
Packit Service |
a04d08 |
self.network = results.get('network-interfaces')
|
|
Packit Service |
a04d08 |
self.metadata = md
|
|
Packit Service |
a04d08 |
self.userdata_raw = results.get('userdata')
|
|
Packit Service |
a04d08 |
return True
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_subplatform(self):
|
|
Packit Service |
a04d08 |
"""Return the subplatform metadata source details."""
|
|
Packit Service |
a04d08 |
if self.seed_dir in self.seed:
|
|
Packit Service |
a04d08 |
subplatform_type = 'seed-dir'
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
subplatform_type = 'config-disk'
|
|
Packit Service |
a04d08 |
return '%s (%s)' % (subplatform_type, self.seed)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@property
|
|
Packit Service |
a04d08 |
def network_config(self):
|
|
Packit Service |
a04d08 |
if self.network is not None:
|
|
Packit Service |
a04d08 |
return self.network
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False):
|
|
Packit Service |
a04d08 |
if resolve_ip is None:
|
|
Packit Service |
a04d08 |
if self.dsmode == sources.DSMODE_NETWORK:
|
|
Packit Service |
a04d08 |
resolve_ip = True
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
resolve_ip = False
|
|
Packit Service |
a04d08 |
return sources.DataSource.get_hostname(self, fqdn, resolve_ip)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class NonContextDiskDir(Exception):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class BrokenContextDiskDir(Exception):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class OpenNebulaNetwork(object):
|
|
Packit Service |
9bfd13 |
def __init__(self, context, distro, system_nics_by_mac=None):
|
|
Packit Service |
a04d08 |
self.context = context
|
|
Packit Service |
a04d08 |
if system_nics_by_mac is None:
|
|
Packit Service |
9bfd13 |
system_nics_by_mac = get_physical_nics_by_mac(distro)
|
|
Packit Service |
a04d08 |
self.ifaces = collections.OrderedDict(
|
|
Packit Service |
a04d08 |
[k for k in sorted(system_nics_by_mac.items(),
|
|
Packit Service |
a04d08 |
key=lambda k: net.natural_sort_key(k[1]))])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# OpenNebula 4.14+ provide macaddr for ETHX in variable ETH_MAC.
|
|
Packit Service |
a04d08 |
# context_devname provides {mac.lower():ETHX, mac2.lower():ETHX}
|
|
Packit Service |
a04d08 |
self.context_devname = {}
|
|
Packit Service |
a04d08 |
for k, v in context.items():
|
|
Packit Service |
a04d08 |
m = re.match(r'^(.+)_MAC$', k)
|
|
Packit Service |
a04d08 |
if m:
|
|
Packit Service |
a04d08 |
self.context_devname[v.lower()] = m.group(1)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def mac2ip(self, mac):
|
|
Packit Service |
a04d08 |
return '.'.join([str(int(c, 16)) for c in mac.split(':')[2:]])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def mac2network(self, mac):
|
|
Packit Service |
a04d08 |
return self.mac2ip(mac).rpartition(".")[0] + ".0"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_nameservers(self, dev):
|
|
Packit Service |
a04d08 |
nameservers = {}
|
|
Packit Service |
a04d08 |
dns = self.get_field(dev, "dns", "").split()
|
|
Packit Service |
a04d08 |
dns.extend(self.context.get('DNS', "").split())
|
|
Packit Service |
a04d08 |
if dns:
|
|
Packit Service |
a04d08 |
nameservers['addresses'] = dns
|
|
Packit Service |
a04d08 |
search_domain = self.get_field(dev, "search_domain", "").split()
|
|
Packit Service |
a04d08 |
if search_domain:
|
|
Packit Service |
a04d08 |
nameservers['search'] = search_domain
|
|
Packit Service |
a04d08 |
return nameservers
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_mtu(self, dev):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "mtu")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_ip(self, dev, mac):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "ip", self.mac2ip(mac))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_ip6(self, dev):
|
|
Packit Service |
a04d08 |
addresses6 = []
|
|
Packit Service |
a04d08 |
ip6 = self.get_field(dev, "ip6")
|
|
Packit Service |
a04d08 |
if ip6:
|
|
Packit Service |
a04d08 |
addresses6.append(ip6)
|
|
Packit Service |
a04d08 |
ip6_ula = self.get_field(dev, "ip6_ula")
|
|
Packit Service |
a04d08 |
if ip6_ula:
|
|
Packit Service |
a04d08 |
addresses6.append(ip6_ula)
|
|
Packit Service |
a04d08 |
return addresses6
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_ip6_prefix(self, dev):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "ip6_prefix_length", "64")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_gateway(self, dev):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "gateway")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_gateway6(self, dev):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "gateway6")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_mask(self, dev):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "mask", "255.255.255.0")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_network(self, dev, mac):
|
|
Packit Service |
a04d08 |
return self.get_field(dev, "network", self.mac2network(mac))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_field(self, dev, name, default=None):
|
|
Packit Service |
a04d08 |
"""return the field name in context for device dev.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
context stores <dev>_<NAME> (example: eth0_DOMAIN).
|
|
Packit Service |
a04d08 |
an empty string for value will return default."""
|
|
Packit Service |
a04d08 |
val = self.context.get('_'.join((dev, name,)).upper())
|
|
Packit Service |
a04d08 |
# allow empty string to return the default.
|
|
Packit Service |
a04d08 |
return default if val in (None, "") else val
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def gen_conf(self):
|
|
Packit Service |
a04d08 |
netconf = {}
|
|
Packit Service |
a04d08 |
netconf['version'] = 2
|
|
Packit Service |
a04d08 |
netconf['ethernets'] = {}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
ethernets = {}
|
|
Packit Service |
a04d08 |
for mac, dev in self.ifaces.items():
|
|
Packit Service |
a04d08 |
mac = mac.lower()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# c_dev stores name in context 'ETHX' for this device.
|
|
Packit Service |
a04d08 |
# dev stores the current system name.
|
|
Packit Service |
a04d08 |
c_dev = self.context_devname.get(mac, dev)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
devconf = {}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set MAC address
|
|
Packit Service |
a04d08 |
devconf['match'] = {'macaddress': mac}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set IPv4 address
|
|
Packit Service |
a04d08 |
devconf['addresses'] = []
|
|
Packit Service |
a04d08 |
mask = self.get_mask(c_dev)
|
|
Packit Service |
a04d08 |
prefix = str(net.mask_to_net_prefix(mask))
|
|
Packit Service |
a04d08 |
devconf['addresses'].append(
|
|
Packit Service |
a04d08 |
self.get_ip(c_dev, mac) + '/' + prefix)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set IPv6 Global and ULA address
|
|
Packit Service |
a04d08 |
addresses6 = self.get_ip6(c_dev)
|
|
Packit Service |
a04d08 |
if addresses6:
|
|
Packit Service |
a04d08 |
prefix6 = self.get_ip6_prefix(c_dev)
|
|
Packit Service |
a04d08 |
devconf['addresses'].extend(
|
|
Packit Service |
a04d08 |
[i + '/' + prefix6 for i in addresses6])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set IPv4 default gateway
|
|
Packit Service |
a04d08 |
gateway = self.get_gateway(c_dev)
|
|
Packit Service |
a04d08 |
if gateway:
|
|
Packit Service |
a04d08 |
devconf['gateway4'] = gateway
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set IPv6 default gateway
|
|
Packit Service |
a04d08 |
gateway6 = self.get_gateway6(c_dev)
|
|
Packit Service |
a04d08 |
if gateway6:
|
|
Packit Service |
a04d08 |
devconf['gateway6'] = gateway6
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set DNS servers and search domains
|
|
Packit Service |
a04d08 |
nameservers = self.get_nameservers(c_dev)
|
|
Packit Service |
a04d08 |
if nameservers:
|
|
Packit Service |
a04d08 |
devconf['nameservers'] = nameservers
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Set MTU size
|
|
Packit Service |
a04d08 |
mtu = self.get_mtu(c_dev)
|
|
Packit Service |
a04d08 |
if mtu:
|
|
Packit Service |
a04d08 |
devconf['mtu'] = mtu
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
ethernets[dev] = devconf
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
netconf['ethernets'] = ethernets
|
|
Packit Service |
a04d08 |
return(netconf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def find_candidate_devs():
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
Return a list of devices that may contain the context disk.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
combined = []
|
|
Packit Service |
a04d08 |
for f in ('LABEL=CONTEXT', 'LABEL=CDROM', 'TYPE=iso9660'):
|
|
Packit Service |
a04d08 |
devs = util.find_devs_with(f)
|
|
Packit Service |
a04d08 |
devs.sort()
|
|
Packit Service |
a04d08 |
for d in devs:
|
|
Packit Service |
a04d08 |
if d not in combined:
|
|
Packit Service |
a04d08 |
combined.append(d)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return combined
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def switch_user_cmd(user):
|
|
Packit Service |
a04d08 |
return ['sudo', '-u', user]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def parse_shell_config(content, keylist=None, bash=None, asuser=None,
|
|
Packit Service |
a04d08 |
switch_user_cb=None):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if isinstance(bash, str):
|
|
Packit Service |
a04d08 |
bash = [bash]
|
|
Packit Service |
a04d08 |
elif bash is None:
|
|
Packit Service |
a04d08 |
bash = ['bash', '-e']
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if switch_user_cb is None:
|
|
Packit Service |
a04d08 |
switch_user_cb = switch_user_cmd
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# allvars expands to all existing variables by using '${!x*}' notation
|
|
Packit Service |
a04d08 |
# where x is lower or upper case letters or '_'
|
|
Packit Service |
a04d08 |
allvars = ["${!%s*}" % x for x in string.ascii_letters + "_"]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
keylist_in = keylist
|
|
Packit Service |
a04d08 |
if keylist is None:
|
|
Packit Service |
a04d08 |
keylist = allvars
|
|
Packit Service |
a04d08 |
keylist_in = []
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
setup = '\n'.join(('__v="";', '',))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def varprinter(vlist):
|
|
Packit Service |
a04d08 |
# output '\0'.join(['_start_', key=value NULL for vars in vlist]
|
|
Packit Service |
a04d08 |
return '\n'.join((
|
|
Packit Service |
a04d08 |
'printf "%s\\0" _start_',
|
|
Packit Service |
a04d08 |
'for __v in %s; do' % ' '.join(vlist),
|
|
Packit Service |
a04d08 |
' printf "%s=%s\\0" "$__v" "${!__v}";',
|
|
Packit Service |
a04d08 |
'done',
|
|
Packit Service |
a04d08 |
''
|
|
Packit Service |
a04d08 |
))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# the rendered 'bcmd' is bash syntax that does
|
|
Packit Service |
a04d08 |
# setup: declare variables we use (so they show up in 'all')
|
|
Packit Service |
a04d08 |
# varprinter(allvars): print all variables known at beginning
|
|
Packit Service |
a04d08 |
# content: execute the provided content
|
|
Packit Service |
a04d08 |
# varprinter(keylist): print all variables known after content
|
|
Packit Service |
a04d08 |
#
|
|
Packit Service |
a04d08 |
# output is then a null terminated array of:
|
|
Packit Service |
a04d08 |
# literal '_start_'
|
|
Packit Service |
a04d08 |
# key=value (for each preset variable)
|
|
Packit Service |
a04d08 |
# literal '_start_'
|
|
Packit Service |
a04d08 |
# key=value (for each post set variable)
|
|
Packit Service |
a04d08 |
bcmd = ('unset IFS\n' +
|
|
Packit Service |
a04d08 |
setup +
|
|
Packit Service |
a04d08 |
varprinter(allvars) +
|
|
Packit Service |
a04d08 |
'{\n%s\n\n:\n} > /dev/null\n' % content +
|
|
Packit Service |
a04d08 |
'unset IFS\n' +
|
|
Packit Service |
a04d08 |
varprinter(keylist) + "\n")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
cmd = []
|
|
Packit Service |
a04d08 |
if asuser is not None:
|
|
Packit Service |
a04d08 |
cmd = switch_user_cb(asuser)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
cmd.extend(bash)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
(output, _error) = subp.subp(cmd, data=bcmd)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# exclude vars in bash that change on their own or that we used
|
|
Packit Service |
a04d08 |
excluded = (
|
|
Packit Service |
a04d08 |
"EPOCHREALTIME", "EPOCHSECONDS", "RANDOM", "LINENO", "SECONDS", "_",
|
|
Packit Service |
a04d08 |
"__v")
|
|
Packit Service |
a04d08 |
preset = {}
|
|
Packit Service |
a04d08 |
ret = {}
|
|
Packit Service |
a04d08 |
target = None
|
|
Packit Service |
a04d08 |
output = output[0:-1] # remove trailing null
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# go through output. First _start_ is for 'preset', second for 'target'.
|
|
Packit Service |
a04d08 |
# Add to ret only things were changed and not in excluded.
|
|
Packit Service |
a04d08 |
for line in output.split("\x00"):
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
(key, val) = line.split("=", 1)
|
|
Packit Service |
a04d08 |
if target is preset:
|
|
Packit Service |
a04d08 |
preset[key] = val
|
|
Packit Service |
a04d08 |
elif (key not in excluded and
|
|
Packit Service |
a04d08 |
(key in keylist_in or preset.get(key) != val)):
|
|
Packit Service |
a04d08 |
ret[key] = val
|
|
Packit Service |
a04d08 |
except ValueError:
|
|
Packit Service |
a04d08 |
if line != "_start_":
|
|
Packit Service |
a04d08 |
raise
|
|
Packit Service |
a04d08 |
if target is None:
|
|
Packit Service |
a04d08 |
target = preset
|
|
Packit Service |
a04d08 |
elif target is preset:
|
|
Packit Service |
a04d08 |
target = ret
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return ret
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
def read_context_disk_dir(source_dir, distro, asuser=None):
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
read_context_disk_dir(source_dir):
|
|
Packit Service |
a04d08 |
read source_dir and return a tuple with metadata dict and user-data
|
|
Packit Service |
a04d08 |
string populated. If not a valid dir, raise a NonContextDiskDir
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
found = {}
|
|
Packit Service |
a04d08 |
for af in CONTEXT_DISK_FILES:
|
|
Packit Service |
a04d08 |
fn = os.path.join(source_dir, af)
|
|
Packit Service |
a04d08 |
if os.path.isfile(fn):
|
|
Packit Service |
a04d08 |
found[af] = fn
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if not found:
|
|
Packit Service |
a04d08 |
raise NonContextDiskDir("%s: %s" % (source_dir, "no files found"))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
context = {}
|
|
Packit Service |
a04d08 |
results = {'userdata': None, 'metadata': {}}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if "context.sh" in found:
|
|
Packit Service |
a04d08 |
if asuser is not None:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
pwd.getpwnam(asuser)
|
|
Packit Service |
9bfd13 |
except KeyError as e:
|
|
Packit Service |
a04d08 |
raise BrokenContextDiskDir(
|
|
Packit Service |
a04d08 |
"configured user '{user}' does not exist".format(
|
|
Packit Service |
9bfd13 |
user=asuser)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
path = os.path.join(source_dir, 'context.sh')
|
|
Packit Service |
a04d08 |
content = util.load_file(path)
|
|
Packit Service |
a04d08 |
context = parse_shell_config(content, asuser=asuser)
|
|
Packit Service |
9bfd13 |
except subp.ProcessExecutionError as e:
|
|
Packit Service |
9bfd13 |
raise BrokenContextDiskDir(
|
|
Packit Service |
9bfd13 |
"Error processing context.sh: %s" % (e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
except IOError as e:
|
|
Packit Service |
9bfd13 |
raise NonContextDiskDir(
|
|
Packit Service |
9bfd13 |
"Error reading context.sh: %s" % (e)
|
|
Packit Service |
9bfd13 |
) from e
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
raise NonContextDiskDir("Missing context.sh")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if not context:
|
|
Packit Service |
a04d08 |
return results
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
results['metadata'] = context
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# process single or multiple SSH keys
|
|
Packit Service |
a04d08 |
ssh_key_var = None
|
|
Packit Service |
a04d08 |
if "SSH_KEY" in context:
|
|
Packit Service |
a04d08 |
ssh_key_var = "SSH_KEY"
|
|
Packit Service |
a04d08 |
elif "SSH_PUBLIC_KEY" in context:
|
|
Packit Service |
a04d08 |
ssh_key_var = "SSH_PUBLIC_KEY"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if ssh_key_var:
|
|
Packit Service |
a04d08 |
lines = context.get(ssh_key_var).splitlines()
|
|
Packit Service |
9bfd13 |
results['metadata']['public-keys'] = [
|
|
Packit Service |
9bfd13 |
line for line in lines if len(line) and not line.startswith("#")
|
|
Packit Service |
9bfd13 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# custom hostname -- try hostname or leave cloud-init
|
|
Packit Service |
a04d08 |
# itself create hostname from IP address later
|
|
Packit Service |
a04d08 |
for k in ('HOSTNAME', 'PUBLIC_IP', 'IP_PUBLIC', 'ETH0_IP'):
|
|
Packit Service |
a04d08 |
if k in context:
|
|
Packit Service |
a04d08 |
results['metadata']['local-hostname'] = context[k]
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# raw user data
|
|
Packit Service |
a04d08 |
if "USER_DATA" in context:
|
|
Packit Service |
a04d08 |
results['userdata'] = context["USER_DATA"]
|
|
Packit Service |
a04d08 |
elif "USERDATA" in context:
|
|
Packit Service |
a04d08 |
results['userdata'] = context["USERDATA"]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# b64decode user data if necessary (default)
|
|
Packit Service |
a04d08 |
if 'userdata' in results:
|
|
Packit Service |
a04d08 |
encoding = context.get('USERDATA_ENCODING',
|
|
Packit Service |
a04d08 |
context.get('USER_DATA_ENCODING'))
|
|
Packit Service |
a04d08 |
if encoding == "base64":
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
results['userdata'] = util.b64d(results['userdata'])
|
|
Packit Service |
a04d08 |
except TypeError:
|
|
Packit Service |
a04d08 |
LOG.warning("Failed base64 decoding of userdata")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# generate Network Configuration v2
|
|
Packit Service |
a04d08 |
# only if there are any required context variables
|
|
Packit Service |
a04d08 |
# http://docs.opennebula.org/5.4/operation/references/template.html#context-section
|
|
Packit Service |
a04d08 |
ipaddr_keys = [k for k in context if re.match(r'^ETH\d+_IP.*$', k)]
|
|
Packit Service |
a04d08 |
if ipaddr_keys:
|
|
Packit Service |
9bfd13 |
onet = OpenNebulaNetwork(context, distro)
|
|
Packit Service |
a04d08 |
results['network-interfaces'] = onet.gen_conf()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return results
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
def get_physical_nics_by_mac(distro):
|
|
Packit Service |
a04d08 |
devs = net.get_interfaces_by_mac()
|
|
Packit Service |
9bfd13 |
return dict(
|
|
Packit Service |
9bfd13 |
[(m, n) for m, n in devs.items() if distro.networking.is_physical(n)]
|
|
Packit Service |
9bfd13 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Legacy: Must be present in case we load an old pkl object
|
|
Packit Service |
a04d08 |
DataSourceOpenNebulaNet = DataSourceOpenNebula
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Used to match classes to dependencies
|
|
Packit Service |
a04d08 |
datasources = [
|
|
Packit Service |
a04d08 |
(DataSourceOpenNebula, (sources.DEP_FILESYSTEM, )),
|
|
Packit Service |
a04d08 |
]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Return a list of data sources that match this set of dependencies
|
|
Packit Service |
a04d08 |
def get_datasource_list(depends):
|
|
Packit Service |
a04d08 |
return sources.list_from_depends(depends, datasources)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# vi: ts=4 expandtab
|