summaryrefslogtreecommitdiff
path: root/cloudinit/sources/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/sources/helpers')
-rw-r--r--cloudinit/sources/helpers/__init__.py13
-rw-r--r--cloudinit/sources/helpers/azure.py279
-rw-r--r--cloudinit/sources/helpers/openstack.py648
-rw-r--r--cloudinit/sources/helpers/vmware/__init__.py13
-rw-r--r--cloudinit/sources/helpers/vmware/imc/__init__.py13
-rw-r--r--cloudinit/sources/helpers/vmware/imc/boot_proto.py25
-rw-r--r--cloudinit/sources/helpers/vmware/imc/config.py95
-rw-r--r--cloudinit/sources/helpers/vmware/imc/config_file.py129
-rw-r--r--cloudinit/sources/helpers/vmware/imc/config_namespace.py25
-rw-r--r--cloudinit/sources/helpers/vmware/imc/config_nic.py247
-rw-r--r--cloudinit/sources/helpers/vmware/imc/config_source.py23
-rw-r--r--cloudinit/sources/helpers/vmware/imc/guestcust_error.py24
-rw-r--r--cloudinit/sources/helpers/vmware/imc/guestcust_event.py27
-rw-r--r--cloudinit/sources/helpers/vmware/imc/guestcust_state.py25
-rw-r--r--cloudinit/sources/helpers/vmware/imc/guestcust_util.py128
-rw-r--r--cloudinit/sources/helpers/vmware/imc/ipv4_mode.py45
-rw-r--r--cloudinit/sources/helpers/vmware/imc/nic.py147
-rw-r--r--cloudinit/sources/helpers/vmware/imc/nic_base.py154
18 files changed, 0 insertions, 2060 deletions
diff --git a/cloudinit/sources/helpers/__init__.py b/cloudinit/sources/helpers/__init__.py
deleted file mode 100644
index 386225d5..00000000
--- a/cloudinit/sources/helpers/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# vi: ts=4 expandtab
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py
deleted file mode 100644
index 63ccf10e..00000000
--- a/cloudinit/sources/helpers/azure.py
+++ /dev/null
@@ -1,279 +0,0 @@
-import logging
-import os
-import re
-import socket
-import struct
-import tempfile
-import time
-
-from contextlib import contextmanager
-from xml.etree import ElementTree
-
-from cloudinit import util
-
-
-LOG = logging.getLogger(__name__)
-
-
-@contextmanager
-def cd(newdir):
- prevdir = os.getcwd()
- os.chdir(os.path.expanduser(newdir))
- try:
- yield
- finally:
- os.chdir(prevdir)
-
-
-class AzureEndpointHttpClient(object):
-
- headers = {
- 'x-ms-agent-name': 'WALinuxAgent',
- 'x-ms-version': '2012-11-30',
- }
-
- def __init__(self, certificate):
- self.extra_secure_headers = {
- "x-ms-cipher-name": "DES_EDE3_CBC",
- "x-ms-guest-agent-public-x509-cert": certificate,
- }
-
- def get(self, url, secure=False):
- headers = self.headers
- if secure:
- headers = self.headers.copy()
- headers.update(self.extra_secure_headers)
- return util.read_file_or_url(url, headers=headers)
-
- def post(self, url, data=None, extra_headers=None):
- headers = self.headers
- if extra_headers is not None:
- headers = self.headers.copy()
- headers.update(extra_headers)
- return util.read_file_or_url(url, data=data, headers=headers)
-
-
-class GoalState(object):
-
- def __init__(self, xml, http_client):
- self.http_client = http_client
- self.root = ElementTree.fromstring(xml)
- self._certificates_xml = None
-
- def _text_from_xpath(self, xpath):
- element = self.root.find(xpath)
- if element is not None:
- return element.text
- return None
-
- @property
- def container_id(self):
- return self._text_from_xpath('./Container/ContainerId')
-
- @property
- def incarnation(self):
- return self._text_from_xpath('./Incarnation')
-
- @property
- def instance_id(self):
- return self._text_from_xpath(
- './Container/RoleInstanceList/RoleInstance/InstanceId')
-
- @property
- def certificates_xml(self):
- if self._certificates_xml is None:
- url = self._text_from_xpath(
- './Container/RoleInstanceList/RoleInstance'
- '/Configuration/Certificates')
- if url is not None:
- self._certificates_xml = self.http_client.get(
- url, secure=True).contents
- return self._certificates_xml
-
-
-class OpenSSLManager(object):
-
- certificate_names = {
- 'private_key': 'TransportPrivate.pem',
- 'certificate': 'TransportCert.pem',
- }
-
- def __init__(self):
- self.tmpdir = tempfile.mkdtemp()
- self.certificate = None
- self.generate_certificate()
-
- def clean_up(self):
- util.del_dir(self.tmpdir)
-
- def generate_certificate(self):
- LOG.debug('Generating certificate for communication with fabric...')
- if self.certificate is not None:
- LOG.debug('Certificate already generated.')
- return
- with cd(self.tmpdir):
- util.subp([
- 'openssl', 'req', '-x509', '-nodes', '-subj',
- '/CN=LinuxTransport', '-days', '32768', '-newkey', 'rsa:2048',
- '-keyout', self.certificate_names['private_key'],
- '-out', self.certificate_names['certificate'],
- ])
- certificate = ''
- for line in open(self.certificate_names['certificate']):
- if "CERTIFICATE" not in line:
- certificate += line.rstrip()
- self.certificate = certificate
- LOG.debug('New certificate generated.')
-
- def parse_certificates(self, certificates_xml):
- tag = ElementTree.fromstring(certificates_xml).find(
- './/Data')
- certificates_content = tag.text
- lines = [
- b'MIME-Version: 1.0',
- b'Content-Disposition: attachment; filename="Certificates.p7m"',
- b'Content-Type: application/x-pkcs7-mime; name="Certificates.p7m"',
- b'Content-Transfer-Encoding: base64',
- b'',
- certificates_content.encode('utf-8'),
- ]
- with cd(self.tmpdir):
- with open('Certificates.p7m', 'wb') as f:
- f.write(b'\n'.join(lines))
- out, _ = util.subp(
- 'openssl cms -decrypt -in Certificates.p7m -inkey'
- ' {private_key} -recip {certificate} | openssl pkcs12 -nodes'
- ' -password pass:'.format(**self.certificate_names),
- shell=True)
- private_keys, certificates = [], []
- current = []
- for line in out.splitlines():
- current.append(line)
- if re.match(r'[-]+END .*?KEY[-]+$', line):
- private_keys.append('\n'.join(current))
- current = []
- elif re.match(r'[-]+END .*?CERTIFICATE[-]+$', line):
- certificates.append('\n'.join(current))
- current = []
- keys = []
- for certificate in certificates:
- with cd(self.tmpdir):
- public_key, _ = util.subp(
- 'openssl x509 -noout -pubkey |'
- 'ssh-keygen -i -m PKCS8 -f /dev/stdin',
- data=certificate,
- shell=True)
- keys.append(public_key)
- return keys
-
-
-class WALinuxAgentShim(object):
-
- REPORT_READY_XML_TEMPLATE = '\n'.join([
- '<?xml version="1.0" encoding="utf-8"?>',
- '<Health xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
- ' xmlns:xsd="http://www.w3.org/2001/XMLSchema">',
- ' <GoalStateIncarnation>{incarnation}</GoalStateIncarnation>',
- ' <Container>',
- ' <ContainerId>{container_id}</ContainerId>',
- ' <RoleInstanceList>',
- ' <Role>',
- ' <InstanceId>{instance_id}</InstanceId>',
- ' <Health>',
- ' <State>Ready</State>',
- ' </Health>',
- ' </Role>',
- ' </RoleInstanceList>',
- ' </Container>',
- '</Health>'])
-
- def __init__(self):
- LOG.debug('WALinuxAgentShim instantiated...')
- self.endpoint = self.find_endpoint()
- self.openssl_manager = None
- self.values = {}
-
- def clean_up(self):
- if self.openssl_manager is not None:
- self.openssl_manager.clean_up()
-
- @staticmethod
- def get_ip_from_lease_value(lease_value):
- unescaped_value = lease_value.replace('\\', '')
- if len(unescaped_value) > 4:
- hex_string = ''
- for hex_pair in unescaped_value.split(':'):
- if len(hex_pair) == 1:
- hex_pair = '0' + hex_pair
- hex_string += hex_pair
- packed_bytes = struct.pack(
- '>L', int(hex_string.replace(':', ''), 16))
- else:
- packed_bytes = unescaped_value.encode('utf-8')
- return socket.inet_ntoa(packed_bytes)
-
- @staticmethod
- def find_endpoint():
- LOG.debug('Finding Azure endpoint...')
- content = util.load_file('/var/lib/dhcp/dhclient.eth0.leases')
- value = None
- for line in content.splitlines():
- if 'unknown-245' in line:
- value = line.strip(' ').split(' ', 2)[-1].strip(';\n"')
- if value is None:
- raise ValueError('No endpoint found in DHCP config.')
- endpoint_ip_address = WALinuxAgentShim.get_ip_from_lease_value(value)
- LOG.debug('Azure endpoint found at %s', endpoint_ip_address)
- return endpoint_ip_address
-
- def register_with_azure_and_fetch_data(self):
- self.openssl_manager = OpenSSLManager()
- http_client = AzureEndpointHttpClient(self.openssl_manager.certificate)
- LOG.info('Registering with Azure...')
- attempts = 0
- while True:
- try:
- response = http_client.get(
- 'http://{0}/machine/?comp=goalstate'.format(self.endpoint))
- except Exception:
- if attempts < 10:
- time.sleep(attempts + 1)
- else:
- raise
- else:
- break
- attempts += 1
- LOG.debug('Successfully fetched GoalState XML.')
- goal_state = GoalState(response.contents, http_client)
- public_keys = []
- if goal_state.certificates_xml is not None:
- LOG.debug('Certificate XML found; parsing out public keys.')
- public_keys = self.openssl_manager.parse_certificates(
- goal_state.certificates_xml)
- data = {
- 'public-keys': public_keys,
- }
- self._report_ready(goal_state, http_client)
- return data
-
- def _report_ready(self, goal_state, http_client):
- LOG.debug('Reporting ready to Azure fabric.')
- document = self.REPORT_READY_XML_TEMPLATE.format(
- incarnation=goal_state.incarnation,
- container_id=goal_state.container_id,
- instance_id=goal_state.instance_id,
- )
- http_client.post(
- "http://{0}/machine?comp=health".format(self.endpoint),
- data=document,
- extra_headers={'Content-Type': 'text/xml; charset=utf-8'},
- )
- LOG.info('Reported ready to Azure fabric.')
-
-
-def get_metadata_from_fabric():
- shim = WALinuxAgentShim()
- try:
- return shim.register_with_azure_and_fetch_data()
- finally:
- shim.clean_up()
diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py
deleted file mode 100644
index 2e7a1d47..00000000
--- a/cloudinit/sources/helpers/openstack.py
+++ /dev/null
@@ -1,648 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2012 Canonical Ltd.
-# Copyright (C) 2012 Yahoo! Inc.
-#
-# Author: Scott Moser <scott.moser@canonical.com>
-# Author: Joshua Harlow <harlowja@yahoo-inc.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import abc
-import base64
-import copy
-import functools
-import os
-
-import six
-
-from cloudinit import ec2_utils
-from cloudinit import log as logging
-from cloudinit import net
-from cloudinit import sources
-from cloudinit import url_helper
-from cloudinit import util
-
-# For reference: http://tinyurl.com/laora4c
-
-LOG = logging.getLogger(__name__)
-
-FILES_V1 = {
- # Path <-> (metadata key name, translator function, default value)
- 'etc/network/interfaces': ('network_config', lambda x: x, ''),
- 'meta.js': ('meta_js', util.load_json, {}),
- "root/.ssh/authorized_keys": ('authorized_keys', lambda x: x, ''),
-}
-KEY_COPIES = (
- # Cloud-init metadata names <-> (metadata key, is required)
- ('local-hostname', 'hostname', False),
- ('instance-id', 'uuid', True),
-)
-OS_LATEST = 'latest'
-OS_FOLSOM = '2012-08-10'
-OS_GRIZZLY = '2013-04-04'
-OS_HAVANA = '2013-10-17'
-OS_LIBERTY = '2015-10-15'
-# keep this in chronological order. new supported versions go at the end.
-OS_VERSIONS = (
- OS_FOLSOM,
- OS_GRIZZLY,
- OS_HAVANA,
- OS_LIBERTY,
-)
-
-
-class NonReadable(IOError):
- pass
-
-
-class BrokenMetadata(IOError):
- pass
-
-
-class SourceMixin(object):
- def _ec2_name_to_device(self, name):
- if not self.ec2_metadata:
- return None
- bdm = self.ec2_metadata.get('block-device-mapping', {})
- for (ent_name, device) in bdm.items():
- if name == ent_name:
- return device
- return None
-
- def get_public_ssh_keys(self):
- name = "public_keys"
- if self.version == 1:
- name = "public-keys"
- return sources.normalize_pubkey_data(self.metadata.get(name))
-
- def _os_name_to_device(self, name):
- device = None
- try:
- criteria = 'LABEL=%s' % (name)
- if name == 'swap':
- criteria = 'TYPE=%s' % (name)
- dev_entries = util.find_devs_with(criteria)
- if dev_entries:
- device = dev_entries[0]
- except util.ProcessExecutionError:
- pass
- return device
-
- def _validate_device_name(self, device):
- if not device:
- return None
- if not device.startswith("/"):
- device = "/dev/%s" % device
- if os.path.exists(device):
- return device
- # Durn, try adjusting the mapping
- remapped = self._remap_device(os.path.basename(device))
- if remapped:
- LOG.debug("Remapped device name %s => %s", device, remapped)
- return remapped
- return None
-
- def device_name_to_device(self, name):
- # Translate a 'name' to a 'physical' device
- if not name:
- return None
- # Try the ec2 mapping first
- names = [name]
- if name == 'root':
- names.insert(0, 'ami')
- if name == 'ami':
- names.append('root')
- device = None
- LOG.debug("Using ec2 style lookup to find device %s", names)
- for n in names:
- device = self._ec2_name_to_device(n)
- device = self._validate_device_name(device)
- if device:
- break
- # Try the openstack way second
- if not device:
- LOG.debug("Using openstack style lookup to find device %s", names)
- for n in names:
- device = self._os_name_to_device(n)
- device = self._validate_device_name(device)
- if device:
- break
- # Ok give up...
- if not device:
- return None
- else:
- LOG.debug("Mapped %s to device %s", name, device)
- return device
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseReader(object):
-
- def __init__(self, base_path):
- self.base_path = base_path
-
- @abc.abstractmethod
- def _path_join(self, base, *add_ons):
- pass
-
- @abc.abstractmethod
- def _path_read(self, path, decode=False):
- pass
-
- @abc.abstractmethod
- def _fetch_available_versions(self):
- pass
-
- @abc.abstractmethod
- def _read_ec2_metadata(self):
- pass
-
- def _find_working_version(self):
- try:
- versions_available = self._fetch_available_versions()
- except Exception as e:
- LOG.debug("Unable to read openstack versions from %s due to: %s",
- self.base_path, e)
- versions_available = []
-
- # openstack.OS_VERSIONS is stored in chronological order, so
- # reverse it to check newest first.
- supported = [v for v in reversed(list(OS_VERSIONS))]
- selected_version = OS_LATEST
-
- for potential_version in supported:
- if potential_version not in versions_available:
- continue
- selected_version = potential_version
- break
-
- LOG.debug("Selected version '%s' from %s", selected_version,
- versions_available)
- return selected_version
-
- def _read_content_path(self, item, decode=False):
- path = item.get('content_path', '').lstrip("/")
- path_pieces = path.split("/")
- valid_pieces = [p for p in path_pieces if len(p)]
- if not valid_pieces:
- raise BrokenMetadata("Item %s has no valid content path" % (item))
- path = self._path_join(self.base_path, "openstack", *path_pieces)
- return self._path_read(path, decode=decode)
-
- def read_v2(self):
- """Reads a version 2 formatted location.
-
- Return a dict with metadata, userdata, ec2-metadata, dsmode,
- network_config, files and version (2).
-
- If not a valid location, raise a NonReadable exception.
- """
-
- load_json_anytype = functools.partial(
- util.load_json, root_types=(dict, list) + six.string_types)
-
- def datafiles(version):
- files = {}
- files['metadata'] = (
- # File path to read
- self._path_join("openstack", version, 'meta_data.json'),
- # Is it required?
- True,
- # Translator function (applied after loading)
- util.load_json,
- )
- files['userdata'] = (
- self._path_join("openstack", version, 'user_data'),
- False,
- lambda x: x,
- )
- files['vendordata'] = (
- self._path_join("openstack", version, 'vendor_data.json'),
- False,
- load_json_anytype,
- )
- files['networkdata'] = (
- self._path_join("openstack", version, 'network_data.json'),
- False,
- load_json_anytype,
- )
- return files
-
- results = {
- 'userdata': '',
- 'version': 2,
- }
- data = datafiles(self._find_working_version())
- for (name, (path, required, translator)) in data.items():
- path = self._path_join(self.base_path, path)
- data = None
- found = False
- try:
- data = self._path_read(path)
- except IOError as e:
- if not required:
- LOG.debug("Failed reading optional path %s due"
- " to: %s", path, e)
- else:
- LOG.debug("Failed reading mandatory path %s due"
- " to: %s", path, e)
- else:
- found = True
- if required and not found:
- raise NonReadable("Missing mandatory path: %s" % path)
- if found and translator:
- try:
- data = translator(data)
- except Exception as e:
- raise BrokenMetadata("Failed to process "
- "path %s: %s" % (path, e))
- if found:
- results[name] = data
-
- metadata = results['metadata']
- if 'random_seed' in metadata:
- random_seed = metadata['random_seed']
- try:
- metadata['random_seed'] = base64.b64decode(random_seed)
- except (ValueError, TypeError) as e:
- raise BrokenMetadata("Badly formatted metadata"
- " random_seed entry: %s" % e)
-
- # load any files that were provided
- files = {}
- metadata_files = metadata.get('files', [])
- for item in metadata_files:
- if 'path' not in item:
- continue
- path = item['path']
- try:
- files[path] = self._read_content_path(item)
- except Exception as e:
- raise BrokenMetadata("Failed to read provided "
- "file %s: %s" % (path, e))
- results['files'] = files
-
- # The 'network_config' item in metadata is a content pointer
- # to the network config that should be applied. It is just a
- # ubuntu/debian '/etc/network/interfaces' file.
- net_item = metadata.get("network_config", None)
- if net_item:
- try:
- content = self._read_content_path(net_item, decode=True)
- results['network_config'] = content
- except IOError as e:
- raise BrokenMetadata("Failed to read network"
- " configuration: %s" % (e))
-
- # To openstack, user can specify meta ('nova boot --meta=key=value')
- # and those will appear under metadata['meta'].
- # if they specify 'dsmode' they're indicating the mode that they intend
- # for this datasource to operate in.
- try:
- results['dsmode'] = metadata['meta']['dsmode']
- except KeyError:
- pass
-
- # Read any ec2-metadata (if applicable)
- results['ec2-metadata'] = self._read_ec2_metadata()
-
- # Perform some misc. metadata key renames...
- for (target_key, source_key, is_required) in KEY_COPIES:
- if is_required and source_key not in metadata:
- raise BrokenMetadata("No '%s' entry in metadata" % source_key)
- if source_key in metadata:
- metadata[target_key] = metadata.get(source_key)
- return results
-
-
-class ConfigDriveReader(BaseReader):
- def __init__(self, base_path):
- super(ConfigDriveReader, self).__init__(base_path)
- self._versions = None
-
- def _path_join(self, base, *add_ons):
- components = [base] + list(add_ons)
- return os.path.join(*components)
-
- def _path_read(self, path, decode=False):
- return util.load_file(path, decode=decode)
-
- def _fetch_available_versions(self):
- if self._versions is None:
- path = self._path_join(self.base_path, 'openstack')
- found = [d for d in os.listdir(path)
- if os.path.isdir(os.path.join(path))]
- self._versions = sorted(found)
- return self._versions
-
- def _read_ec2_metadata(self):
- path = self._path_join(self.base_path,
- 'ec2', 'latest', 'meta-data.json')
- if not os.path.exists(path):
- return {}
- else:
- try:
- return util.load_json(self._path_read(path))
- except Exception as e:
- raise BrokenMetadata("Failed to process "
- "path %s: %s" % (path, e))
-
- def read_v1(self):
- """Reads a version 1 formatted location.
-
- Return a dict with metadata, userdata, dsmode, files and version (1).
-
- If not a valid path, raise a NonReadable exception.
- """
-
- found = {}
- for name in FILES_V1.keys():
- path = self._path_join(self.base_path, name)
- if os.path.exists(path):
- found[name] = path
- if len(found) == 0:
- raise NonReadable("%s: no files found" % (self.base_path))
-
- md = {}
- for (name, (key, translator, default)) in FILES_V1.items():
- if name in found:
- path = found[name]
- try:
- contents = self._path_read(path)
- except IOError:
- raise BrokenMetadata("Failed to read: %s" % path)
- try:
- md[key] = translator(contents)
- except Exception as e:
- raise BrokenMetadata("Failed to process "
- "path %s: %s" % (path, e))
- else:
- md[key] = copy.deepcopy(default)
-
- keydata = md['authorized_keys']
- meta_js = md['meta_js']
-
- # keydata in meta_js is preferred over "injected"
- keydata = meta_js.get('public-keys', keydata)
- if keydata:
- lines = keydata.splitlines()
- md['public-keys'] = [l for l in lines
- if len(l) and not l.startswith("#")]
-
- # config-drive-v1 has no way for openstack to provide the instance-id
- # so we copy that into metadata from the user input
- if 'instance-id' in meta_js:
- md['instance-id'] = meta_js['instance-id']
-
- results = {
- 'version': 1,
- 'metadata': md,
- }
-
- # allow the user to specify 'dsmode' in a meta tag
- if 'dsmode' in meta_js:
- results['dsmode'] = meta_js['dsmode']
-
- # config-drive-v1 has no way of specifying user-data, so the user has
- # to cheat and stuff it in a meta tag also.
- results['userdata'] = meta_js.get('user-data', '')
-
- # this implementation does not support files other than
- # network/interfaces and authorized_keys...
- results['files'] = {}
-
- return results
-
-
-class MetadataReader(BaseReader):
- def __init__(self, base_url, ssl_details=None, timeout=5, retries=5):
- super(MetadataReader, self).__init__(base_url)
- self.ssl_details = ssl_details
- self.timeout = float(timeout)
- self.retries = int(retries)
- self._versions = None
-
- def _fetch_available_versions(self):
- # <baseurl>/openstack/ returns a newline separated list of versions
- if self._versions is not None:
- return self._versions
- found = []
- version_path = self._path_join(self.base_path, "openstack")
- content = self._path_read(version_path)
- for line in content.splitlines():
- line = line.strip()
- if not line:
- continue
- found.append(line)
- self._versions = found
- return self._versions
-
- def _path_read(self, path, decode=False):
-
- def should_retry_cb(_request_args, cause):
- try:
- code = int(cause.code)
- if code >= 400:
- return False
- except (TypeError, ValueError):
- # Older versions of requests didn't have a code.
- pass
- return True
-
- response = url_helper.readurl(path,
- retries=self.retries,
- ssl_details=self.ssl_details,
- timeout=self.timeout,
- exception_cb=should_retry_cb)
- if decode:
- return response.contents.decode()
- else:
- return response.contents
-
- def _path_join(self, base, *add_ons):
- return url_helper.combine_url(base, *add_ons)
-
- def _read_ec2_metadata(self):
- return ec2_utils.get_instance_metadata(ssl_details=self.ssl_details,
- timeout=self.timeout,
- retries=self.retries)
-
-
-# Convert OpenStack ConfigDrive NetworkData json to network_config yaml
-def convert_net_json(network_json=None, known_macs=None):
- """Return a dictionary of network_config by parsing provided
- OpenStack ConfigDrive NetworkData json format
-
- OpenStack network_data.json provides a 3 element dictionary
- - "links" (links are network devices, physical or virtual)
- - "networks" (networks are ip network configurations for one or more
- links)
- - services (non-ip services, like dns)
-
- networks and links are combined via network items referencing specific
- links via a 'link_id' which maps to a links 'id' field.
-
- To convert this format to network_config yaml, we first iterate over the
- links and then walk the network list to determine if any of the networks
- utilize the current link; if so we generate a subnet entry for the device
-
- We also need to map network_data.json fields to network_config fields. For
- example, the network_data links 'id' field is equivalent to network_config
- 'name' field for devices. We apply more of this mapping to the various
- link types that we encounter.
-
- There are additional fields that are populated in the network_data.json
- from OpenStack that are not relevant to network_config yaml, so we
- enumerate a dictionary of valid keys for network_yaml and apply filtering
- to drop these superflous keys from the network_config yaml.
- """
- if network_json is None:
- return None
-
- # dict of network_config key for filtering network_json
- valid_keys = {
- 'physical': [
- 'name',
- 'type',
- 'mac_address',
- 'subnets',
- 'params',
- 'mtu',
- ],
- 'subnet': [
- 'type',
- 'address',
- 'netmask',
- 'broadcast',
- 'metric',
- 'gateway',
- 'pointopoint',
- 'scope',
- 'dns_nameservers',
- 'dns_search',
- 'routes',
- ],
- }
-
- links = network_json.get('links', [])
- networks = network_json.get('networks', [])
- services = network_json.get('services', [])
-
- config = []
- for link in links:
- subnets = []
- cfg = dict((k, v) for k, v in link.items()
- if k in valid_keys['physical'])
- # 'name' is not in openstack spec yet, but we will support it if it is
- # present. The 'id' in the spec is currently implemented as the host
- # nic's name, meaning something like 'tap-adfasdffd'. We do not want
- # to name guest devices with such ugly names.
- if 'name' in link:
- cfg['name'] = link['name']
-
- for network in [n for n in networks
- if n['link'] == link['id']]:
- subnet = dict((k, v) for k, v in network.items()
- if k in valid_keys['subnet'])
- if 'dhcp' in network['type']:
- t = 'dhcp6' if network['type'].startswith('ipv6') else 'dhcp4'
- subnet.update({
- 'type': t,
- })
- else:
- subnet.update({
- 'type': 'static',
- 'address': network.get('ip_address'),
- })
- if network['type'] == 'ipv4':
- subnet['ipv4'] = True
- if network['type'] == 'ipv6':
- subnet['ipv6'] = True
- subnets.append(subnet)
- cfg.update({'subnets': subnets})
- if link['type'] in ['ethernet', 'vif', 'ovs', 'phy', 'bridge']:
- cfg.update({
- 'type': 'physical',
- 'mac_address': link['ethernet_mac_address']})
- elif link['type'] in ['bond']:
- params = {}
- for k, v in link.items():
- if k == 'bond_links':
- continue
- elif k.startswith('bond'):
- params.update({k: v})
- cfg.update({
- 'bond_interfaces': copy.deepcopy(link['bond_links']),
- 'params': params,
- })
- elif link['type'] in ['vlan']:
- cfg.update({
- 'name': "%s.%s" % (link['vlan_link'],
- link['vlan_id']),
- 'vlan_link': link['vlan_link'],
- 'vlan_id': link['vlan_id'],
- 'mac_address': link['vlan_mac_address'],
- })
- else:
- raise ValueError(
- 'Unknown network_data link type: %s' % link['type'])
-
- config.append(cfg)
-
- need_names = [d for d in config
- if d.get('type') == 'physical' and 'name' not in d]
-
- if need_names:
- if known_macs is None:
- known_macs = net.get_interfaces_by_mac()
-
- for d in need_names:
- mac = d.get('mac_address')
- if not mac:
- raise ValueError("No mac_address or name entry for %s" % d)
- if mac not in known_macs:
- raise ValueError("Unable to find a system nic for %s" % d)
- d['name'] = known_macs[mac]
-
- for service in services:
- cfg = service
- cfg.update({'type': 'nameserver'})
- config.append(cfg)
-
- return {'version': 1, 'config': config}
-
-
-def convert_vendordata_json(data, recurse=True):
- """data: a loaded json *object* (strings, arrays, dicts).
- return something suitable for cloudinit vendordata_raw.
-
- if data is:
- None: return None
- string: return string
- list: return data
- the list is then processed in UserDataProcessor
- dict: return convert_vendordata_json(data.get('cloud-init'))
- """
- if not data:
- return None
- if isinstance(data, six.string_types):
- return data
- if isinstance(data, list):
- return copy.deepcopy(data)
- if isinstance(data, dict):
- if recurse is True:
- return convert_vendordata_json(data.get('cloud-init'),
- recurse=False)
- raise ValueError("vendordata['cloud-init'] cannot be dict")
- raise ValueError("Unknown data type for vendordata: %s" % type(data))
diff --git a/cloudinit/sources/helpers/vmware/__init__.py b/cloudinit/sources/helpers/vmware/__init__.py
deleted file mode 100644
index 386225d5..00000000
--- a/cloudinit/sources/helpers/vmware/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# vi: ts=4 expandtab
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/cloudinit/sources/helpers/vmware/imc/__init__.py b/cloudinit/sources/helpers/vmware/imc/__init__.py
deleted file mode 100644
index 386225d5..00000000
--- a/cloudinit/sources/helpers/vmware/imc/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# vi: ts=4 expandtab
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/cloudinit/sources/helpers/vmware/imc/boot_proto.py b/cloudinit/sources/helpers/vmware/imc/boot_proto.py
deleted file mode 100644
index fb53ec1d..00000000
--- a/cloudinit/sources/helpers/vmware/imc/boot_proto.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class BootProtoEnum(object):
- """Specifies the NIC Boot Settings."""
-
- DHCP = 'dhcp'
- STATIC = 'static'
diff --git a/cloudinit/sources/helpers/vmware/imc/config.py b/cloudinit/sources/helpers/vmware/imc/config.py
deleted file mode 100644
index d645c497..00000000
--- a/cloudinit/sources/helpers/vmware/imc/config.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from .nic import Nic
-
-
-class Config(object):
- """
- Stores the Contents specified in the Customization
- Specification file.
- """
-
- DNS = 'DNS|NAMESERVER|'
- SUFFIX = 'DNS|SUFFIX|'
- PASS = 'PASSWORD|-PASS'
- TIMEZONE = 'DATETIME|TIMEZONE'
- UTC = 'DATETIME|UTC'
- HOSTNAME = 'NETWORK|HOSTNAME'
- DOMAINNAME = 'NETWORK|DOMAINNAME'
-
- def __init__(self, configFile):
- self._configFile = configFile
-
- @property
- def host_name(self):
- """Return the hostname."""
- return self._configFile.get(Config.HOSTNAME, None)
-
- @property
- def domain_name(self):
- """Return the domain name."""
- return self._configFile.get(Config.DOMAINNAME, None)
-
- @property
- def timezone(self):
- """Return the timezone."""
- return self._configFile.get(Config.TIMEZONE, None)
-
- @property
- def utc(self):
- """Retrieves whether to set time to UTC or Local."""
- return self._configFile.get(Config.UTC, None)
-
- @property
- def admin_password(self):
- """Return the root password to be set."""
- return self._configFile.get(Config.PASS, None)
-
- @property
- def name_servers(self):
- """Return the list of DNS servers."""
- res = []
- cnt = self._configFile.get_count_with_prefix(Config.DNS)
- for i in range(1, cnt + 1):
- key = Config.DNS + str(i)
- res.append(self._configFile[key])
-
- return res
-
- @property
- def dns_suffixes(self):
- """Return the list of DNS Suffixes."""
- res = []
- cnt = self._configFile.get_count_with_prefix(Config.SUFFIX)
- for i in range(1, cnt + 1):
- key = Config.SUFFIX + str(i)
- res.append(self._configFile[key])
-
- return res
-
- @property
- def nics(self):
- """Return the list of associated NICs."""
- res = []
- nics = self._configFile['NIC-CONFIG|NICS']
- for nic in nics.split(','):
- res.append(Nic(nic, self._configFile))
-
- return res
diff --git a/cloudinit/sources/helpers/vmware/imc/config_file.py b/cloudinit/sources/helpers/vmware/imc/config_file.py
deleted file mode 100644
index bb9fb7dc..00000000
--- a/cloudinit/sources/helpers/vmware/imc/config_file.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-
-try:
- import configparser
-except ImportError:
- import ConfigParser as configparser
-
-from .config_source import ConfigSource
-
-logger = logging.getLogger(__name__)
-
-
-class ConfigFile(ConfigSource, dict):
- """ConfigFile module to load the content from a specified source."""
-
- def __init__(self, filename):
- self._loadConfigFile(filename)
- pass
-
- def _insertKey(self, key, val):
- """
- Inserts a Key Value pair.
-
- Keyword arguments:
- key -- The key to insert
- val -- The value to insert for the key
-
- """
- key = key.strip()
- val = val.strip()
-
- if key.startswith('-') or '|-' in key:
- canLog = False
- else:
- canLog = True
-
- # "sensitive" settings shall not be logged
- if canLog:
- logger.debug("ADDED KEY-VAL :: '%s' = '%s'" % (key, val))
- else:
- logger.debug("ADDED KEY-VAL :: '%s' = '*****************'" % key)
-
- self[key] = val
-
- def _loadConfigFile(self, filename):
- """
- Parses properties from the specified config file.
-
- Any previously available properties will be removed.
- Sensitive data will not be logged in case the key starts
- from '-'.
-
- Keyword arguments:
- filename - The full path to the config file.
- """
- logger.info('Parsing the config file %s.' % filename)
-
- config = configparser.ConfigParser()
- config.optionxform = str
- config.read(filename)
-
- self.clear()
-
- for category in config.sections():
- logger.debug("FOUND CATEGORY = '%s'" % category)
-
- for (key, value) in config.items(category):
- self._insertKey(category + '|' + key, value)
-
- def should_keep_current_value(self, key):
- """
- Determines whether a value for a property must be kept.
-
- If the propery is missing, it is treated as it should be not
- changed by the engine.
-
- Keyword arguments:
- key -- The key to search for.
- """
- # helps to distinguish from "empty" value which is used to indicate
- # "removal"
- return key not in self
-
- def should_remove_current_value(self, key):
- """
- Determines whether a value for the property must be removed.
-
- If the specified key is empty, it is treated as it should be
- removed by the engine.
-
- Return true if the value can be removed, false otherwise.
-
- Keyword arguments:
- key -- The key to search for.
- """
- # helps to distinguish from "missing" value which is used to indicate
- # "keeping unchanged"
- if key in self:
- return not bool(self[key])
- else:
- return False
-
- def get_count_with_prefix(self, prefix):
- """
- Return the total count of keys that start with the specified prefix.
-
- Keyword arguments:
- prefix -- prefix of the key
- """
- return len([key for key in self if key.startswith(prefix)])
diff --git a/cloudinit/sources/helpers/vmware/imc/config_namespace.py b/cloudinit/sources/helpers/vmware/imc/config_namespace.py
deleted file mode 100644
index b28830f5..00000000
--- a/cloudinit/sources/helpers/vmware/imc/config_namespace.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from .config_source import ConfigSource
-
-
-class ConfigNamespace(ConfigSource):
- """Specifies the Config Namespace."""
- pass
diff --git a/cloudinit/sources/helpers/vmware/imc/config_nic.py b/cloudinit/sources/helpers/vmware/imc/config_nic.py
deleted file mode 100644
index 511cc918..00000000
--- a/cloudinit/sources/helpers/vmware/imc/config_nic.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2016 VMware INC.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-import os
-import re
-
-from cloudinit import util
-
-logger = logging.getLogger(__name__)
-
-
-class NicConfigurator(object):
- def __init__(self, nics):
- """
- Initialize the Nic Configurator
- @param nics (list) an array of nics to configure
- """
- self.nics = nics
- self.mac2Name = {}
- self.ipv4PrimaryGateway = None
- self.ipv6PrimaryGateway = None
- self.find_devices()
- self._primaryNic = self.get_primary_nic()
-
- def get_primary_nic(self):
- """
- Retrieve the primary nic if it exists
- @return (NicBase): the primary nic if exists, None otherwise
- """
- primary_nics = [nic for nic in self.nics if nic.primary]
- if not primary_nics:
- return None
- elif len(primary_nics) > 1:
- raise Exception('There can only be one primary nic',
- [nic.mac for nic in primary_nics])
- else:
- return primary_nics[0]
-
- def find_devices(self):
- """
- Create the mac2Name dictionary
- The mac address(es) are in the lower case
- """
- cmd = ['ip', 'addr', 'show']
- (output, err) = util.subp(cmd)
- sections = re.split(r'\n\d+: ', '\n' + output)[1:]
-
- macPat = r'link/ether (([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2}))'
- for section in sections:
- match = re.search(macPat, section)
- if not match: # Only keep info about nics
- continue
- mac = match.group(1).lower()
- name = section.split(':', 1)[0]
- self.mac2Name[mac] = name
-
- def gen_one_nic(self, nic):
- """
- Return the lines needed to configure a nic
- @return (str list): the string list to configure the nic
- @param nic (NicBase): the nic to configure
- """
- lines = []
- name = self.mac2Name.get(nic.mac.lower())
- if not name:
- raise ValueError('No known device has MACADDR: %s' % nic.mac)
-
- if nic.onboot:
- lines.append('auto %s' % name)
-
- # Customize IPv4
- lines.extend(self.gen_ipv4(name, nic))
-
- # Customize IPv6
- lines.extend(self.gen_ipv6(name, nic))
-
- lines.append('')
-
- return lines
-
- def gen_ipv4(self, name, nic):
- """
- Return the lines needed to configure the IPv4 setting of a nic
- @return (str list): the string list to configure the gateways
- @param name (str): name of the nic
- @param nic (NicBase): the nic to configure
- """
- lines = []
-
- bootproto = nic.bootProto.lower()
- if nic.ipv4_mode.lower() == 'disabled':
- bootproto = 'manual'
- lines.append('iface %s inet %s' % (name, bootproto))
-
- if bootproto != 'static':
- return lines
-
- # Static Ipv4
- v4 = nic.staticIpv4
- if v4.ip:
- lines.append(' address %s' % v4.ip)
- if v4.netmask:
- lines.append(' netmask %s' % v4.netmask)
-
- # Add the primary gateway
- if nic.primary and v4.gateways:
- self.ipv4PrimaryGateway = v4.gateways[0]
- lines.append(' gateway %s metric 0' % self.ipv4PrimaryGateway)
- return lines
-
- # Add routes if there is no primary nic
- if not self._primaryNic:
- lines.extend(self.gen_ipv4_route(nic, v4.gateways))
-
- return lines
-
- def gen_ipv4_route(self, nic, gateways):
- """
- Return the lines needed to configure additional Ipv4 route
- @return (str list): the string list to configure the gateways
- @param nic (NicBase): the nic to configure
- @param gateways (str list): the list of gateways
- """
- lines = []
-
- for gateway in gateways:
- lines.append(' up route add default gw %s metric 10000' %
- gateway)
-
- return lines
-
- def gen_ipv6(self, name, nic):
- """
- Return the lines needed to configure the gateways for a nic
- @return (str list): the string list to configure the gateways
- @param name (str): name of the nic
- @param nic (NicBase): the nic to configure
- """
- lines = []
-
- if not nic.staticIpv6:
- return lines
-
- # Static Ipv6
- addrs = nic.staticIpv6
- lines.append('iface %s inet6 static' % name)
- lines.append(' address %s' % addrs[0].ip)
- lines.append(' netmask %s' % addrs[0].netmask)
-
- for addr in addrs[1:]:
- lines.append(' up ifconfig %s inet6 add %s/%s' % (name, addr.ip,
- addr.netmask))
- # Add the primary gateway
- if nic.primary:
- for addr in addrs:
- if addr.gateway:
- self.ipv6PrimaryGateway = addr.gateway
- lines.append(' gateway %s' % self.ipv6PrimaryGateway)
- return lines
-
- # Add routes if there is no primary nic
- if not self._primaryNic:
- lines.extend(self._genIpv6Route(name, nic, addrs))
-
- return lines
-
- def _genIpv6Route(self, name, nic, addrs):
- lines = []
-
- for addr in addrs:
- lines.append(' up route -A inet6 add default gw '
- '%s metric 10000' % addr.gateway)
-
- return lines
-
- def generate(self):
- """Return the lines that is needed to configure the nics"""
- lines = []
- lines.append('iface lo inet loopback')
- lines.append('auto lo')
- lines.append('')
-
- for nic in self.nics:
- lines.extend(self.gen_one_nic(nic))
-
- return lines
-
- def clear_dhcp(self):
- logger.info('Clearing DHCP leases')
-
- # Ignore the return code 1.
- util.subp(["pkill", "dhclient"], rcs=[0, 1])
- util.subp(["rm", "-f", "/var/lib/dhcp/*"])
-
- def if_down_up(self):
- names = []
- for nic in self.nics:
- name = self.mac2Name.get(nic.mac.lower())
- names.append(name)
-
- for name in names:
- logger.info('Bring down interface %s' % name)
- util.subp(["ifdown", "%s" % name])
-
- self.clear_dhcp()
-
- for name in names:
- logger.info('Bring up interface %s' % name)
- util.subp(["ifup", "%s" % name])
-
- def configure(self):
- """
- Configure the /etc/network/intefaces
- Make a back up of the original
- """
- containingDir = '/etc/network'
-
- interfaceFile = os.path.join(containingDir, 'interfaces')
- originalFile = os.path.join(containingDir,
- 'interfaces.before_vmware_customization')
-
- if not os.path.exists(originalFile) and os.path.exists(interfaceFile):
- os.rename(interfaceFile, originalFile)
-
- lines = self.generate()
- with open(interfaceFile, 'w') as fp:
- for line in lines:
- fp.write('%s\n' % line)
-
- self.if_down_up()
diff --git a/cloudinit/sources/helpers/vmware/imc/config_source.py b/cloudinit/sources/helpers/vmware/imc/config_source.py
deleted file mode 100644
index 28ef306a..00000000
--- a/cloudinit/sources/helpers/vmware/imc/config_source.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class ConfigSource(object):
- """Specifies a source for the Config Content."""
- pass
diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_error.py b/cloudinit/sources/helpers/vmware/imc/guestcust_error.py
deleted file mode 100644
index d1546852..00000000
--- a/cloudinit/sources/helpers/vmware/imc/guestcust_error.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2016 Canonical Ltd.
-# Copyright (C) 2016 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class GuestCustErrorEnum(object):
- """Specifies different errors of Guest Customization engine"""
-
- GUESTCUST_ERROR_SUCCESS = 0
diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_event.py b/cloudinit/sources/helpers/vmware/imc/guestcust_event.py
deleted file mode 100644
index ce90c898..00000000
--- a/cloudinit/sources/helpers/vmware/imc/guestcust_event.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2016 Canonical Ltd.
-# Copyright (C) 2016 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class GuestCustEventEnum(object):
- """Specifies different types of Guest Customization Events"""
-
- GUESTCUST_EVENT_CUSTOMIZE_FAILED = 100
- GUESTCUST_EVENT_NETWORK_SETUP_FAILED = 101
- GUESTCUST_EVENT_ENABLE_NICS = 103
- GUESTCUST_EVENT_QUERY_NICS = 104
diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_state.py b/cloudinit/sources/helpers/vmware/imc/guestcust_state.py
deleted file mode 100644
index 422a096d..00000000
--- a/cloudinit/sources/helpers/vmware/imc/guestcust_state.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2016 Canonical Ltd.
-# Copyright (C) 2016 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class GuestCustStateEnum(object):
- """Specifies different states of Guest Customization engine"""
-
- GUESTCUST_STATE_RUNNING = 4
- GUESTCUST_STATE_DONE = 5
diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_util.py b/cloudinit/sources/helpers/vmware/imc/guestcust_util.py
deleted file mode 100644
index c07c5949..00000000
--- a/cloudinit/sources/helpers/vmware/imc/guestcust_util.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2016 Canonical Ltd.
-# Copyright (C) 2016 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-import os
-import time
-
-from cloudinit import util
-
-from .guestcust_event import GuestCustEventEnum
-from .guestcust_state import GuestCustStateEnum
-
-logger = logging.getLogger(__name__)
-
-
-CLOUDINIT_LOG_FILE = "/var/log/cloud-init.log"
-QUERY_NICS_SUPPORTED = "queryNicsSupported"
-NICS_STATUS_CONNECTED = "connected"
-
-
-# This will send a RPC command to the underlying
-# VMware Virtualization Platform.
-def send_rpc(rpc):
- if not rpc:
- return None
-
- out = ""
- err = "Error sending the RPC command"
-
- try:
- logger.debug("Sending RPC command: %s", rpc)
- (out, err) = util.subp(["vmware-rpctool", rpc], rcs=[0])
- # Remove the trailing newline in the output.
- if out:
- out = out.rstrip()
- except Exception as e:
- logger.debug("Failed to send RPC command")
- logger.exception(e)
-
- return (out, err)
-
-
-# This will send the customization status to the
-# underlying VMware Virtualization Platform.
-def set_customization_status(custstate, custerror, errormessage=None):
- message = ""
-
- if errormessage:
- message = CLOUDINIT_LOG_FILE + "@" + errormessage
- else:
- message = CLOUDINIT_LOG_FILE
-
- rpc = "deployPkg.update.state %d %d %s" % (custstate, custerror, message)
- (out, err) = send_rpc(rpc)
- return (out, err)
-
-
-# This will read the file nics.txt in the specified directory
-# and return the content
-def get_nics_to_enable(dirpath):
- if not dirpath:
- return None
-
- NICS_SIZE = 1024
- nicsfilepath = os.path.join(dirpath, "nics.txt")
- if not os.path.exists(nicsfilepath):
- return None
-
- with open(nicsfilepath, 'r') as fp:
- nics = fp.read(NICS_SIZE)
-
- return nics
-
-
-# This will send a RPC command to the underlying VMware Virtualization platform
-# and enable nics.
-def enable_nics(nics):
- if not nics:
- logger.warning("No Nics found")
- return
-
- enableNicsWaitRetries = 5
- enableNicsWaitCount = 5
- enableNicsWaitSeconds = 1
-
- for attempt in range(0, enableNicsWaitRetries):
- logger.debug("Trying to connect interfaces, attempt %d", attempt)
- (out, err) = set_customization_status(
- GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
- GuestCustEventEnum.GUESTCUST_EVENT_ENABLE_NICS,
- nics)
- if not out:
- time.sleep(enableNicsWaitCount * enableNicsWaitSeconds)
- continue
-
- if out != QUERY_NICS_SUPPORTED:
- logger.warning("NICS connection status query is not supported")
- return
-
- for count in range(0, enableNicsWaitCount):
- (out, err) = set_customization_status(
- GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
- GuestCustEventEnum.GUESTCUST_EVENT_QUERY_NICS,
- nics)
- if out and out == NICS_STATUS_CONNECTED:
- logger.info("NICS are connected on %d second", count)
- return
-
- time.sleep(enableNicsWaitSeconds)
-
- logger.warning("Can't connect network interfaces after %d attempts",
- enableNicsWaitRetries)
diff --git a/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py b/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py
deleted file mode 100644
index 873ddc3b..00000000
--- a/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class Ipv4ModeEnum(object):
- """
- The IPv4 configuration mode which directly represents the user's goal.
-
- This mode effectively acts as a contract of the in-guest customization
- engine. It must be set based on what the user has requested and should
- not be changed by those layers. It's up to the in-guest engine to
- interpret and materialize the user's request.
- """
-
- # The legacy mode which only allows dhcp/static based on whether IPv4
- # addresses list is empty or not
- IPV4_MODE_BACKWARDS_COMPATIBLE = 'BACKWARDS_COMPATIBLE'
-
- # IPv4 must use static address. Reserved for future use
- IPV4_MODE_STATIC = 'STATIC'
-
- # IPv4 must use DHCPv4. Reserved for future use
- IPV4_MODE_DHCP = 'DHCP'
-
- # IPv4 must be disabled
- IPV4_MODE_DISABLED = 'DISABLED'
-
- # IPv4 settings should be left untouched. Reserved for future use
- IPV4_MODE_AS_IS = 'AS_IS'
diff --git a/cloudinit/sources/helpers/vmware/imc/nic.py b/cloudinit/sources/helpers/vmware/imc/nic.py
deleted file mode 100644
index b5d704ea..00000000
--- a/cloudinit/sources/helpers/vmware/imc/nic.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from .boot_proto import BootProtoEnum
-from .nic_base import NicBase, StaticIpv4Base, StaticIpv6Base
-
-
-class Nic(NicBase):
- """
- Holds the information about each NIC specified
- in the customization specification file
- """
-
- def __init__(self, name, configFile):
- self._name = name
- self._configFile = configFile
-
- def _get(self, what):
- return self._configFile.get(self.name + '|' + what, None)
-
- def _get_count_with_prefix(self, prefix):
- return self._configFile.get_count_with_prefix(self.name + prefix)
-
- @property
- def name(self):
- return self._name
-
- @property
- def mac(self):
- return self._get('MACADDR').lower()
-
- @property
- def primary(self):
- value = self._get('PRIMARY')
- if value:
- value = value.lower()
- return value == 'yes' or value == 'true'
- else:
- return False
-
- @property
- def onboot(self):
- value = self._get('ONBOOT')
- if value:
- value = value.lower()
- return value == 'yes' or value == 'true'
- else:
- return False
-
- @property
- def bootProto(self):
- value = self._get('BOOTPROTO')
- if value:
- return value.lower()
- else:
- return ""
-
- @property
- def ipv4_mode(self):
- value = self._get('IPv4_MODE')
- if value:
- return value.lower()
- else:
- return ""
-
- @property
- def staticIpv4(self):
- """
- Checks the BOOTPROTO property and returns StaticIPv4Addr
- configuration object if STATIC configuration is set.
- """
- if self.bootProto == BootProtoEnum.STATIC:
- return [StaticIpv4Addr(self)]
- else:
- return None
-
- @property
- def staticIpv6(self):
- cnt = self._get_count_with_prefix('|IPv6ADDR|')
-
- if not cnt:
- return None
-
- result = []
- for index in range(1, cnt + 1):
- result.append(StaticIpv6Addr(self, index))
-
- return result
-
-
-class StaticIpv4Addr(StaticIpv4Base):
- """Static IPV4 Setting."""
-
- def __init__(self, nic):
- self._nic = nic
-
- @property
- def ip(self):
- return self._nic._get('IPADDR')
-
- @property
- def netmask(self):
- return self._nic._get('NETMASK')
-
- @property
- def gateways(self):
- value = self._nic._get('GATEWAY')
- if value:
- return [x.strip() for x in value.split(',')]
- else:
- return None
-
-
-class StaticIpv6Addr(StaticIpv6Base):
- """Static IPV6 Address."""
-
- def __init__(self, nic, index):
- self._nic = nic
- self._index = index
-
- @property
- def ip(self):
- return self._nic._get('IPv6ADDR|' + str(self._index))
-
- @property
- def netmask(self):
- return self._nic._get('IPv6NETMASK|' + str(self._index))
-
- @property
- def gateway(self):
- return self._nic._get('IPv6GATEWAY|' + str(self._index))
diff --git a/cloudinit/sources/helpers/vmware/imc/nic_base.py b/cloudinit/sources/helpers/vmware/imc/nic_base.py
deleted file mode 100644
index 3c892db0..00000000
--- a/cloudinit/sources/helpers/vmware/imc/nic_base.py
+++ /dev/null
@@ -1,154 +0,0 @@
-# vi: ts=4 expandtab
-#
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright (C) 2015 VMware Inc.
-#
-# Author: Sankar Tanguturi <stanguturi@vmware.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3, as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class NicBase(object):
- """
- Define what are expected of each nic.
- The following properties should be provided in an implementation class.
- """
-
- @property
- def mac(self):
- """
- Retrieves the mac address of the nic
- @return (str) : the MACADDR setting
- """
- raise NotImplementedError('MACADDR')
-
- @property
- def primary(self):
- """
- Retrieves whether the nic is the primary nic
- Indicates whether NIC will be used to define the default gateway.
- If none of the NICs is configured to be primary, default gateway won't
- be set.
- @return (bool): the PRIMARY setting
- """
- raise NotImplementedError('PRIMARY')
-
- @property
- def onboot(self):
- """
- Retrieves whether the nic should be up at the boot time
- @return (bool) : the ONBOOT setting
- """
- raise NotImplementedError('ONBOOT')
-
- @property
- def bootProto(self):
- """
- Retrieves the boot protocol of the nic
- @return (str): the BOOTPROTO setting, valid values: dhcp and static.
- """
- raise NotImplementedError('BOOTPROTO')
-
- @property
- def ipv4_mode(self):
- """
- Retrieves the IPv4_MODE
- @return (str): the IPv4_MODE setting, valid values:
- backwards_compatible, static, dhcp, disabled, as_is
- """
- raise NotImplementedError('IPv4_MODE')
-
- @property
- def staticIpv4(self):
- """
- Retrieves the static IPv4 configuration of the nic
- @return (StaticIpv4Base list): the static ipv4 setting
- """
- raise NotImplementedError('Static IPv4')
-
- @property
- def staticIpv6(self):
- """
- Retrieves the IPv6 configuration of the nic
- @return (StaticIpv6Base list): the static ipv6 setting
- """
- raise NotImplementedError('Static Ipv6')
-
- def validate(self):
- """
- Validate the object
- For example, the staticIpv4 property is required and should not be
- empty when ipv4Mode is STATIC
- """
- raise NotImplementedError('Check constraints on properties')
-
-
-class StaticIpv4Base(object):
- """
- Define what are expected of a static IPv4 setting
- The following properties should be provided in an implementation class.
- """
-
- @property
- def ip(self):
- """
- Retrieves the Ipv4 address
- @return (str): the IPADDR setting
- """
- raise NotImplementedError('Ipv4 Address')
-
- @property
- def netmask(self):
- """
- Retrieves the Ipv4 NETMASK setting
- @return (str): the NETMASK setting
- """
- raise NotImplementedError('Ipv4 NETMASK')
-
- @property
- def gateways(self):
- """
- Retrieves the gateways on this Ipv4 subnet
- @return (str list): the GATEWAY setting
- """
- raise NotImplementedError('Ipv4 GATEWAY')
-
-
-class StaticIpv6Base(object):
- """Define what are expected of a static IPv6 setting
- The following properties should be provided in an implementation class.
- """
-
- @property
- def ip(self):
- """
- Retrieves the Ipv6 address
- @return (str): the IPv6ADDR setting
- """
- raise NotImplementedError('Ipv6 Address')
-
- @property
- def netmask(self):
- """
- Retrieves the Ipv6 NETMASK setting
- @return (str): the IPv6NETMASK setting
- """
- raise NotImplementedError('Ipv6 NETMASK')
-
- @property
- def gateway(self):
- """
- Retrieves the Ipv6 GATEWAY setting
- @return (str): the IPv6GATEWAY setting
- """
- raise NotImplementedError('Ipv6 GATEWAY')