Blame cloudinit/sources/DataSourceHetzner.py

Packit bc9a3a
# Author: Jonas Keidel <jonas.keidel@hetzner.com>
Packit bc9a3a
# Author: Markus Schade <markus.schade@hetzner.com>
Packit bc9a3a
#
Packit bc9a3a
# This file is part of cloud-init. See LICENSE file for license information.
Packit bc9a3a
#
Packit bc9a3a
"""Hetzner Cloud API Documentation.
Packit bc9a3a
   https://docs.hetzner.cloud/"""
Packit bc9a3a
Packit bc9a3a
from cloudinit import log as logging
Packit bc9a3a
from cloudinit import net as cloudnet
Packit bc9a3a
from cloudinit import sources
Packit bc9a3a
from cloudinit import util
Packit bc9a3a
Packit bc9a3a
import cloudinit.sources.helpers.hetzner as hc_helper
Packit bc9a3a
Packit bc9a3a
LOG = logging.getLogger(__name__)
Packit bc9a3a
Packit bc9a3a
BASE_URL_V1 = 'http://169.254.169.254/hetzner/v1'
Packit bc9a3a
Packit bc9a3a
BUILTIN_DS_CONFIG = {
Packit bc9a3a
    'metadata_url': BASE_URL_V1 + '/metadata',
Packit bc9a3a
    'userdata_url': BASE_URL_V1 + '/userdata',
Packit bc9a3a
}
Packit bc9a3a
Packit bc9a3a
MD_RETRIES = 60
Packit bc9a3a
MD_TIMEOUT = 2
Packit bc9a3a
MD_WAIT_RETRY = 2
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class DataSourceHetzner(sources.DataSource):
Packit bc9a3a
Packit bc9a3a
    dsname = 'Hetzner'
Packit bc9a3a
Packit bc9a3a
    def __init__(self, sys_cfg, distro, paths):
Packit bc9a3a
        sources.DataSource.__init__(self, sys_cfg, distro, paths)
Packit bc9a3a
        self.distro = distro
Packit bc9a3a
        self.metadata = dict()
Packit bc9a3a
        self.ds_cfg = util.mergemanydict([
Packit bc9a3a
            util.get_cfg_by_path(sys_cfg, ["datasource", "Hetzner"], {}),
Packit bc9a3a
            BUILTIN_DS_CONFIG])
Packit bc9a3a
        self.metadata_address = self.ds_cfg['metadata_url']
Packit bc9a3a
        self.userdata_address = self.ds_cfg['userdata_url']
Packit bc9a3a
        self.retries = self.ds_cfg.get('retries', MD_RETRIES)
Packit bc9a3a
        self.timeout = self.ds_cfg.get('timeout', MD_TIMEOUT)
Packit bc9a3a
        self.wait_retry = self.ds_cfg.get('wait_retry', MD_WAIT_RETRY)
Packit bc9a3a
        self._network_config = None
Packit bc9a3a
        self.dsmode = sources.DSMODE_NETWORK
Packit bc9a3a
Packit bc9a3a
    def get_data(self):
Packit bc9a3a
        if not on_hetzner():
Packit bc9a3a
            return False
Packit bc9a3a
        nic = cloudnet.find_fallback_nic()
Packit bc9a3a
        with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,
Packit bc9a3a
                                           "169.254.255.255"):
Packit bc9a3a
            md = hc_helper.read_metadata(
Packit bc9a3a
                self.metadata_address, timeout=self.timeout,
Packit bc9a3a
                sec_between=self.wait_retry, retries=self.retries)
Packit bc9a3a
            ud = hc_helper.read_userdata(
Packit bc9a3a
                self.userdata_address, timeout=self.timeout,
Packit bc9a3a
                sec_between=self.wait_retry, retries=self.retries)
Packit bc9a3a
Packit bc9a3a
        self.userdata_raw = ud
Packit bc9a3a
        self.metadata_full = md
Packit bc9a3a
Packit bc9a3a
        """hostname is name provided by user at launch.  The API enforces
Packit bc9a3a
        it is a valid hostname, but it is not guaranteed to be resolvable
Packit bc9a3a
        in dns or fully qualified."""
Packit bc9a3a
        self.metadata['instance-id'] = md['instance-id']
Packit bc9a3a
        self.metadata['local-hostname'] = md['hostname']
Packit bc9a3a
        self.metadata['network-config'] = md.get('network-config', None)
Packit bc9a3a
        self.metadata['public-keys'] = md.get('public-keys', None)
Packit bc9a3a
        self.vendordata_raw = md.get("vendor_data", None)
Packit bc9a3a
Packit bc9a3a
        return True
Packit bc9a3a
Packit bc9a3a
    @property
Packit bc9a3a
    def network_config(self):
Packit bc9a3a
        """Configure the networking. This needs to be done each boot, since
Packit bc9a3a
           the IP information may have changed due to snapshot and/or
Packit bc9a3a
           migration.
Packit bc9a3a
        """
Packit bc9a3a
Packit bc9a3a
        if self._network_config:
Packit bc9a3a
            return self._network_config
Packit bc9a3a
Packit bc9a3a
        _net_config = self.metadata['network-config']
Packit bc9a3a
        if not _net_config:
Packit bc9a3a
            raise Exception("Unable to get meta-data from server....")
Packit bc9a3a
Packit bc9a3a
        self._network_config = _net_config
Packit bc9a3a
Packit bc9a3a
        return self._network_config
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
def on_hetzner():
Packit bc9a3a
    return util.read_dmi_data('system-manufacturer') == "Hetzner"
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
# Used to match classes to dependencies
Packit bc9a3a
datasources = [
Packit bc9a3a
    (DataSourceHetzner, (sources.DEP_FILESYSTEM, )),
Packit bc9a3a
]
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
# Return a list of data sources that match this set of dependencies
Packit bc9a3a
def get_datasource_list(depends):
Packit bc9a3a
    return sources.list_from_depends(depends, datasources)
Packit bc9a3a
Packit bc9a3a
# vi: ts=4 expandtab