diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | cloudinit/config/cc_vyos.py | 143 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceAzure.py | 6 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceEc2.py | 8 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceGCE.py | 8 | ||||
-rw-r--r-- | config/cloud.cfg.tmpl | 190 | ||||
-rw-r--r-- | integration-requirements.txt | 3 | ||||
-rw-r--r-- | systemd/cloud-config.service.tmpl | 1 | ||||
-rw-r--r-- | systemd/cloud-final.service.tmpl | 1 | ||||
-rw-r--r-- | systemd/cloud-init.service.tmpl | 4 | ||||
-rwxr-xr-x | tools/read-version | 39 |
11 files changed, 181 insertions, 230 deletions
@@ -47,12 +47,6 @@ pyflakes: pyflakes3: @$(CWD)/tools/run-pyflakes3 -unittest: clean_pyc - nosetests $(noseopts) tests/unittests cloudinit - -unittest3: clean_pyc - nosetests3 $(noseopts) tests/unittests cloudinit - ci-deps-ubuntu: @$(PYVER) $(CWD)/tools/read-dependencies --distro ubuntu --test-distro @@ -67,8 +61,6 @@ pip-test-requirements: @echo "Installing cloud-init test dependencies..." $(PIP_INSTALL) -r "$@.txt" -q -test: $(unittests) - check_version: @if [ "$(READ_VERSION)" != "$(CODE_VERSION)" ]; then \ echo "Error: read-version version '$(READ_VERSION)'" \ diff --git a/cloudinit/config/cc_vyos.py b/cloudinit/config/cc_vyos.py new file mode 100644 index 00000000..290d3665 --- /dev/null +++ b/cloudinit/config/cc_vyos.py @@ -0,0 +1,143 @@ +# vi: ts=4 expandtab +# +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.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 os +import sys +import ast + +from cloudinit import util + +from cloudinit.distros import ug_util +from cloudinit.settings import PER_INSTANCE + +from vyos.configtree import ConfigTree + +frequency = PER_INSTANCE + +class VyosError(Exception): + """Raised when the distro runs into an exception when setting vyos config. + This may happen when the ssh pub key format is wrong. + """ + pass + +def set_pass_login(config, user, password, encrypted_pass): + if encrypted_pass: + config.set(['system', 'login', 'user', user, 'authentication', 'encrypted-password'], value=password, replace=True) + else: + config.set(['system', 'login', 'user', user, 'authentication', 'plaintext-password'], value=password, replace=True) + + config.set_tag(['system', 'login', 'user']) + config.set(['system', 'login', 'user', user, 'level'], value='admin', replace=True) + + +def set_ssh_login(config, user, key_string, key_x): + key_type = None + key_data = None + key_name = None + + key_parts = key_string.split(None) + + for key in key_parts: + if 'ssh-dss' in key or 'ssh-rsa' in key: + key_type = key + + if key.startswith('AAAAB3NzaC1yc2E') or key.startswith('AAAAB3NzaC1kc3M'): + key_data = key + + if not key_type: + util.logexc(log, 'Key type not defined, wrong ssh key format.') + raise VyosError('Key type not defined, wrong ssh key format.') + + if not key_data: + util.logexc(log, 'Key base64 not defined, wrong ssh key format.') + raise VyosError('Key base64 not defined, wrong ssh key format.') + + if len(key_parts) > 2: + if key_parts[2] != key_type or key_parts[2] != key_data: + key_name = key_parts[2] + else: + key_name = "cloud-init-%s" % key_x + else: + key_name = "cloud-init-%s" % key_x + + config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name , 'key'], value=key_data, replace=True) + config.set(['system', 'login', 'user', user, 'authentication', 'public-keys', key_name , 'type'], value=key_type, replace=True) + config.set_tag(['system', 'login', 'user']) + config.set_tag(['system', 'login', 'user', user, 'authentication', 'public-keys']) + config.set(['system', 'login', 'user', user, 'level'], value='admin', replace=True) + + +def handle(name, cfg, cloud, log, _args): + cfg_file_name = '/opt/vyatta/etc/config/config.boot' + bak_file_name = '/opt/vyatta/etc/config.boot.default' + metadata = cloud.datasource.metadata + (users, groups) = ug_util.normalize_users_groups(cfg, cloud.distro) + (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) + encrypted_pass = False + key_x = 1 + + if not os.path.exists(cfg_file_name): + file_name = bak_file_name + else: + file_name = cfg_file_name + + with open(file_name, 'r') as f: + config_file = f.read() + config = ConfigTree(config_file) + + if 'DataSourceAzure' in str(cloud.datasource): + encrypted_pass = True + for key, val in users.items(): + user = key + if 'passwd' in val: + password = val.get('passwd') + set_pass_login(config, user, password, encrypted_pass) + + vyos_keys = metadata['public-keys'] + for ssh_key in vyos_keys: + set_ssh_login(config, user, ssh_key, key_x) + key_x = key_x + 1 + else: + for user in users: + password = util.get_cfg_option_str(cfg, "passwd", None) + if password: + set_pass_login(config, user, password, encrypted_pass) + + vyos_keys = cloud.get_public_ssh_keys() or [] + if "ssh_authorized_keys" in cfg: + cfgkeys = cfg["ssh_authorized_keys"] + vyos_keys.extend(cfgkeys) + + for ssh_key in vyos_keys: + set_ssh_login(config, user, ssh_key, key_x) + key_x = key_x + 1 + + config.set(['service', 'ssh'], replace=True) + config.set(['service', 'ssh', 'port'], value='22', replace=True) + config.set(['service', 'ssh', 'client-keepalive-interval'], value='180', replace=True) + config.set(['interfaces', 'ethernet', 'eth0', 'address'], value='dhcp', replace=True) + config.set_tag(['interfaces', 'ethernet']) + config.set(['system', 'host-name'], value=hostname, replace=True) + + try: + with open(cfg_file_name, 'w') as f: + f.write(config.to_string()) + except: + util.logexc(log, "Failed to write configs into file %s", file_name) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index 783445e1..629f006f 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -13,6 +13,7 @@ import os import os.path import re from time import time +from subprocess import call from xml.dom import minidom import xml.etree.ElementTree as ET @@ -265,6 +266,11 @@ class DataSourceAzure(sources.DataSource): dsname = 'Azure' _negotiated = False _metadata_imds = sources.UNSET + process_name = 'dhclient' + + tmpps = os.popen("ps -Af").read() + if process_name not in tmpps[:]: + call(['/sbin/dhclient', DEFAULT_PRIMARY_NIC]) def __init__(self, sys_cfg, distro, paths): sources.DataSource.__init__(self, sys_cfg, distro, paths) diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py index 968ab3f7..98ea7bbc 100644 --- a/cloudinit/sources/DataSourceEc2.py +++ b/cloudinit/sources/DataSourceEc2.py @@ -10,6 +10,7 @@ import os import time +from subprocess import call from cloudinit import ec2_utils as ec2 from cloudinit import log as logging @@ -26,6 +27,7 @@ SKIP_METADATA_URL_CODES = frozenset([uhelp.NOT_FOUND]) STRICT_ID_PATH = ("datasource", "Ec2", "strict_id") STRICT_ID_DEFAULT = "warn" +DEFAULT_PRIMARY_NIC = 'eth0' class Platforms(object): @@ -45,6 +47,12 @@ class Platforms(object): class DataSourceEc2(sources.DataSource): dsname = 'Ec2' + process_name = 'dhclient' + + tmpps = os.popen("ps -Af").read() + if process_name not in tmpps[:]: + call(['/sbin/dhclient', DEFAULT_PRIMARY_NIC]) + # Default metadata urls that will be used if none are provided # They will be checked for 'resolveability' and some of the # following may be discarded if they do not resolve diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py index d8162623..f72d9836 100644 --- a/cloudinit/sources/DataSourceGCE.py +++ b/cloudinit/sources/DataSourceGCE.py @@ -2,8 +2,10 @@ # # This file is part of cloud-init. See LICENSE file for license information. +import os import datetime import json +from subprocess import call from base64 import b64decode @@ -18,6 +20,7 @@ LOG = logging.getLogger(__name__) MD_V1_URL = 'http://metadata.google.internal/computeMetadata/v1/' BUILTIN_DS_CONFIG = {'metadata_url': MD_V1_URL} REQUIRED_FIELDS = ('instance-id', 'availability-zone', 'local-hostname') +DEFAULT_PRIMARY_NIC = 'eth0' class GoogleMetadataFetcher(object): @@ -50,6 +53,11 @@ class GoogleMetadataFetcher(object): class DataSourceGCE(sources.DataSource): dsname = 'GCE' + process_name = 'dhclient' + + tmpps = os.popen("ps -Af").read() + if process_name not in tmpps[:]: + call(['/sbin/dhclient', DEFAULT_PRIMARY_NIC]) def __init__(self, sys_cfg, distro, paths): sources.DataSource.__init__(self, sys_cfg, distro, paths) diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl index 1fef133a..0847ab3d 100644 --- a/config/cloud.cfg.tmpl +++ b/config/cloud.cfg.tmpl @@ -2,201 +2,35 @@ # The top level settings are used as module # and system configuration. -{% if variant in ["freebsd"] %} -syslog_fix_perms: root:wheel -{% elif variant in ["suse"] %} -syslog_fix_perms: root:root -{% endif %} -# A set of users which may be applied and/or used by various modules -# when a 'default' entry is found it will reference the 'default_user' -# from the distro configuration specified below -users: - - default - -# If this is set, 'root' will not be able to ssh in and they -# will get a message to login instead as the default $user -{% if variant in ["freebsd"] %} -disable_root: false -{% else %} -disable_root: true -{% endif %} +datasource: + Azure: + agent_command: [/usr/bin/python3, -u, /usr/sbin/waagent, -start] -{% if variant in ["centos", "fedora", "rhel"] %} -mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2'] -resize_rootfs_tmp: /dev -ssh_pwauth: 0 - -{% endif %} # This will cause the set+update hostname module to not operate (if true) -preserve_hostname: false - -{% if variant in ["freebsd"] %} -# This should not be required, but leave it in place until the real cause of -# not beeing able to find -any- datasources is resolved. -datasource_list: ['ConfigDrive', 'Azure', 'OpenStack', 'Ec2'] -{% endif %} -# Example datasource config -# datasource: -# Ec2: -# metadata_urls: [ 'blah.com' ] -# timeout: 5 # (defaults to 50 seconds) -# max_wait: 10 # (defaults to 120 seconds) +preserve_hostname: true -# The modules that run in the 'init' stage -cloud_init_modules: - - migrator - - seed_random - - bootcmd - - write-files - - growpart - - resizefs -{% if variant not in ["freebsd"] %} - - disk_setup - - mounts -{% endif %} - - set_hostname - - update_hostname -{% if variant not in ["freebsd"] %} - - update_etc_hosts - - ca-certs - - rsyslog -{% endif %} - - users-groups - - ssh +users: + - default # The modules that run in the 'config' stage cloud_config_modules: -{% if variant in ["ubuntu", "unknown", "debian"] %} -# Emit the cloud config ready event -# this can be used by upstart jobs for 'start on cloud-config'. - - emit_upstart - - snap - - snap_config # DEPRECATED- Drop in version 18.2 -{% endif %} - - ssh-import-id - - locale - - set-passwords -{% if variant in ["rhel", "fedora"] %} - - spacewalk - - yum-add-repo -{% endif %} -{% if variant in ["ubuntu", "unknown", "debian"] %} - - grub-dpkg - - apt-pipelining - - apt-configure -{% endif %} -{% if variant in ["ubuntu"] %} - - ubuntu-advantage -{% endif %} -{% if variant in ["suse"] %} - - zypper-add-repo -{% endif %} -{% if variant not in ["freebsd"] %} - - ntp -{% endif %} - - timezone - - disable-ec2-metadata - - runcmd -{% if variant in ["ubuntu", "unknown", "debian"] %} - - byobu -{% endif %} + - vyos # The modules that run in the 'final' stage cloud_final_modules: -{% if variant in ["ubuntu", "unknown", "debian"] %} - - snappy # DEPRECATED- Drop in version 18.2 -{% endif %} - - package-update-upgrade-install -{% if variant in ["ubuntu", "unknown", "debian"] %} - - fan - - landscape - - lxd -{% endif %} -{% if variant not in ["freebsd"] %} - - puppet - - chef - - mcollective -{% endif %} - - salt-minion - - rightscale_userdata - - scripts-vendor - - scripts-per-once - - scripts-per-boot - - scripts-per-instance - - scripts-user - - ssh-authkey-fingerprints - - keys-to-console - - phone-home - - final-message - - power-state-change + - runcmd + # System and/or distro specific settings # (not accessible to handlers/transforms) system_info: # This will affect which distro class gets used -{% if variant in ["centos", "debian", "fedora", "rhel", "suse", "ubuntu", "freebsd"] %} - distro: {{ variant }} -{% else %} - # Unknown/fallback distro. - distro: ubuntu -{% endif %} -{% if variant in ["ubuntu", "unknown", "debian"] %} + distro: debian # Default user name + that default users groups (if added/used) default_user: - name: ubuntu - lock_passwd: True - gecos: Ubuntu - groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video] - sudo: ["ALL=(ALL) NOPASSWD:ALL"] - shell: /bin/bash - # Automatically discover the best ntp_client - ntp_client: auto + name: vyos # Other config here will be given to the distro class and/or path classes paths: - cloud_dir: /var/lib/cloud/ + cloud_dir: /opt/vyatta/etc/config/cloud/ templates_dir: /etc/cloud/templates/ upstart_dir: /etc/init/ - package_mirrors: - - arches: [i386, amd64] - failsafe: - primary: http://archive.ubuntu.com/ubuntu - security: http://security.ubuntu.com/ubuntu - search: - primary: - - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/ - - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/ - - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/ - security: [] - - arches: [armhf, armel, default] - failsafe: - primary: http://ports.ubuntu.com/ubuntu-ports - security: http://ports.ubuntu.com/ubuntu-ports - ssh_svcname: ssh -{% elif variant in ["centos", "rhel", "fedora", "suse"] %} - # Default user name + that default users groups (if added/used) - default_user: - name: {{ variant }} - lock_passwd: True - gecos: {{ variant }} Cloud User -{% if variant == "suse" %} - groups: [cdrom, users] -{% else %} - groups: [wheel, adm, systemd-journal] -{% endif %} - sudo: ["ALL=(ALL) NOPASSWD:ALL"] - shell: /bin/bash - # Other config here will be given to the distro class and/or path classes - paths: - cloud_dir: /var/lib/cloud/ - templates_dir: /etc/cloud/templates/ - ssh_svcname: sshd -{% elif variant in ["freebsd"] %} - # Default user name + that default users groups (if added/used) - default_user: - name: freebsd - lock_passwd: True - gecos: FreeBSD - groups: [wheel] - sudo: ["ALL=(ALL) NOPASSWD:ALL"] - shell: /bin/tcsh -{% endif %} diff --git a/integration-requirements.txt b/integration-requirements.txt index 880d9886..b10ff964 100644 --- a/integration-requirements.txt +++ b/integration-requirements.txt @@ -10,8 +10,7 @@ unittest2 boto3==1.5.9 # ssh communication -paramiko==2.4.1 - +paramiko==2.4.2 # lxd backend # 04/03/2018: enables use of lxd 3.0 diff --git a/systemd/cloud-config.service.tmpl b/systemd/cloud-config.service.tmpl index 9d928ca2..508d777e 100644 --- a/systemd/cloud-config.service.tmpl +++ b/systemd/cloud-config.service.tmpl @@ -1,6 +1,7 @@ ## template:jinja [Unit] Description=Apply the settings specified in cloud-config +Before=vyos-router.service After=network-online.target cloud-config.target After=snapd.seeded.service Wants=network-online.target cloud-config.target diff --git a/systemd/cloud-final.service.tmpl b/systemd/cloud-final.service.tmpl index 8207b18c..e2b91255 100644 --- a/systemd/cloud-final.service.tmpl +++ b/systemd/cloud-final.service.tmpl @@ -15,7 +15,6 @@ ExecStart=/usr/bin/cloud-init modules --mode=final RemainAfterExit=yes TimeoutSec=0 KillMode=process -TasksMax=infinity # Output needs to appear in instance console output StandardOutput=journal+console diff --git a/systemd/cloud-init.service.tmpl b/systemd/cloud-init.service.tmpl index b92e8abc..0f152967 100644 --- a/systemd/cloud-init.service.tmpl +++ b/systemd/cloud-init.service.tmpl @@ -3,8 +3,6 @@ Description=Initial cloud-init job (metadata service crawler) DefaultDependencies=no Wants=cloud-init-local.service -Wants=sshd-keygen.service -Wants=sshd.service After=cloud-init-local.service After=systemd-networkd-wait-online.service {% if variant in ["ubuntu", "unknown", "debian"] %} @@ -21,8 +19,6 @@ After=wicked.service After=dbus.service {% endif %} Before=network-online.target -Before=sshd-keygen.service -Before=sshd.service {% if variant in ["ubuntu", "unknown", "debian"] %} Before=sysinit.target Conflicts=shutdown.target diff --git a/tools/read-version b/tools/read-version index e69c2ce0..06fd61a8 100755 --- a/tools/read-version +++ b/tools/read-version @@ -45,49 +45,14 @@ def which(program): return None -def is_gitdir(path): - # Return boolean indicating if path is a git tree. - git_meta = os.path.join(path, '.git') - if os.path.isdir(git_meta): - return True - if os.path.exists(git_meta): - # in a git worktree, .git is a file with 'gitdir: x' - with open(git_meta, "rb") as fp: - if b'gitdir:' in fp.read(): - return True - return False - - use_long = '--long' in sys.argv or os.environ.get('CI_RV_LONG') use_tags = '--tags' in sys.argv or os.environ.get('CI_RV_TAGS') output_json = '--json' in sys.argv src_version = ci_version.version_string() version_long = None - -if is_gitdir(_tdir) and which("git"): - flags = [] - if use_tags: - flags = ['--tags'] - cmd = ['git', 'describe', '--abbrev=8', '--match=[0-9]*'] + flags - - version = tiny_p(cmd).strip() - - if not version.startswith(src_version): - sys.stderr.write("git describe version (%s) differs from " - "cloudinit.version (%s)\n" % (version, src_version)) - sys.stderr.write( - "Please get the latest upstream tags.\n" - "As an example, this can be done with the following:\n" - "$ git remote add upstream https://git.launchpad.net/cloud-init\n" - "$ git fetch upstream --tags\n" - ) - sys.exit(1) - - version_long = tiny_p(cmd + ["--long"]).strip() -else: - version = src_version - version_long = None +version = src_version +version_long = None # version is X.Y.Z[+xxx.gHASH] # version_long is None or X.Y.Z-xxx-gHASH |