vkhitrin.com

Technology And Ramblings

How Guest Instances Configure Themselves In OpenStack



Tags: #OpenStack #cloud-init

Tested on Red Hat OpenStack Platform 14, which is based on the Upstream RDO Rocky release. Using RHEL7 cloud image for guest instance with network access to Nova Metadata Server

User Requesting An Instance In A Cloud Environment

One of the basic expectations regarding clouds is that once an end-user requests an instance, it should be supplied with the least effort involved and timely.

While the process is transparent to the end user and might seem like magic, behind the scenes, several components attempt to ensure that a properly configured instance is supplied.

This blog post will discuss how this is achieved in the OpenStack cloud.

Before getting into the technical details, it’s important to understand the flow that occurs in cloud platforms.

Public clouds provide a prebuilt image catalog from which the end-user must choose when spawning an instance. They have to ensure that the instance is spawned without the involvement and support additional customization provided to alter the instance.

Successful boot in a cloud environment is achieved by the cloud images(special images designed for the cloud) having a component that can communicate with the cloud infrastructure and apply necessary configuration(network, storage, user-supplied actions, etc.).

In OpenStack, the component which is part of the cloud images is cloud-init, and the infrastructure component is Nova Metadata Service.

cloud-init-nova-metadata-server

When OpenStack spawns an instance, if the instance is using a cloud image with cloud-init, the instance can leverage the Nova Metadata Service to retrieve necessary metadata needed for configuration and additional user data that allow user-defined customization to occur during the spawn.

Configuration Components In OpenStack

OpenStack can inject data into images if they contain a cloud-init package.
Most popular distributions offer prebuilt images containing cloud-init.
Refer to OpenStack documentation on retrieving cloud images.

Cloud-init

Note: cloud-init is a robust tool with many capabilities, and this blog post describes some basic capabilities.

cloud-init is a Python utility that is distributed in the form of a package that aims to be the defacto multi-distribution package that handles the early initialization of a cloud instance(as described in the documentation).

It operates during various boot stages to make sure that the necessary configuration is applied.

cloud-init is a multi-cloud solution due to its ability to retrieve necessary metadata and configuration from various datasources.
OpenStack is one of the default datasrouces available.

Nova Metadata Service

Nova Metadata Service is the infrastructure component that provides the metadata to instances.

This service holds two sets of APIs that the instance could consume, an OpenStack metadata API and an EC2-compatible API.

cloud-init can access the OpenStack datasource and local Config Drive datasource to retrieve metadata:

Metadata Server

Metadata is exposed to the instance via a URL, which by default is hosted on http://169.254.169.254.

Instances with network connectivity and routing to the metadata server can perform an HTTP GET request for the relevant API.

http://169.254.169.254/openstack will provide OpenStack API.
http://169.254.169.254/ec2 will provide EC2 compatible API.

Config Drive

Instances that do not have network connectivity could still consume metadata via a CD-ROM-like device (Config Drive).

When booting up an instance in OpenStack, there is an option to attach a Config Drive which contains all the metadata information provided by Nova Metadata Service.

Config Drive is useful when your instance lacks external connectivity, which can be configured later while providing all the necessary metadata.

For example: I use Config Drive in an environment where an instance is connected to a set of switches, with only one allowing external connectivity to Nova Metadata Service.
During boot, an instance might be launched with the first NIC attached to a network that can’t access Nova Metadata Service, which will prevent cloud-init from accessing metadata.
By using Config Drive, I’m able to supply the metadata and configure the external network using a script that locates the NIC connected to an external network.

How metadata is applied to an instance

cloud-init in systemd based distributions is a collection of daemons that are enabled by default:

systemctl list-units | grep cloud-init
# Output
  cloud-init-local.service                                          loaded active exited    Initial cloud-init job (pre-networking)
  cloud-init.service                                                loaded active exited    Initial cloud-init job (metadata service crawler)

While the daemons are running, they invoke the cloud-init CLI, which logs the output by default into /var/log/cloud-init.log (example).

How cloud-init discovers distribution

cloud-init must discover the distribution of the instance to apply the configuration:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:03,399 - handlers.py[DEBUG]: finish: init-local/check-cache: SUCCESS: no cache found
2019-01-11 14:14:03,399 - util.py[DEBUG]: Attempting to remove /var/lib/cloud/instance
2019-01-11 14:14:03,415 - stages.py[DEBUG]: Using distro class <class 'cloudinit.distros.rhel.Distro'>
(text is omitted)

Once a distribution is discovered, a Python class containing methods that apply the configuration on said distribution is loaded. In this scenario, rhel distribution was detected.

How cloud-init Discovers Datasources

After distribution discovery, the next step is discovering a data source:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:03,416 - __init__.py[DEBUG]: Looking for for data source in: ['NoCloud', 'ConfigDrive', 'OpenNebula', 'DigitalOcean', 'Azure', 'AltCloud', 'OVF', 'MAAS', 'GCE', 'OpenStack', 'AliYun', 'Ec2', 'CloudSigma', 'CloudStack', 'SmartOS', 'Bigstep', 'None'], via packages ['', u'cloudinit.sources'] that matches dependencies ['FILESYSTEM']
2019-01-11 14:14:03,509 - __init__.py[DEBUG]: Searching for local data source in: [u'DataSourceNoCloud', u'DataSourceConfigDrive', u'DataSourceOpenNebula', u'DataSourceDigitalOcean', u'DataSourceOVF', u'DataSourceCloudSigma', u'DataSourceSmartOS']
(text is omitted)

All supported datasources are loaded and then cloud-init iterates and attempts to discover a datasource:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:03,576 - __init__.py[DEBUG]: Seeing if we can get any data from <class 'cloudinit.sources.DataSourceDigitalOcean.DataSourceDigitalOcean'>
2019-01-11 14:14:03,576 - util.py[DEBUG]: querying dmi data /sys/class/dmi/id/sys_vendor
2019-01-11 14:14:03,577 - util.py[DEBUG]: Reading from /sys/class/dmi/id/sys_vendor (quiet=False)
2019-01-11 14:14:03,577 - util.py[DEBUG]: Read 8 bytes from /sys/class/dmi/id/sys_vendor
2019-01-11 14:14:03,577 - util.py[DEBUG]: dmi data /sys/class/dmi/id/sys_vendor returned Red Hat
2019-01-11 14:14:03,577 - handlers.py[DEBUG]: finish: init-local/search-DigitalOcean: SUCCESS: no local data found from DataSourceDigitalOcean
(text is omitted)

As the first line describes, cloud-init attempts to discover information if it’s hosted on DigitalOcean, but it fails and proceeds to the next datasource.
At some point, it will attempt to access the OpenStack datasource:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:16,345 - handlers.py[DEBUG]: start: init-network/search-OpenStack: searching for network data from DataSourceOpenStack
2019-01-11 14:14:16,345 - __init__.py[DEBUG]: Seeing if we can get any data from <class 'cloudinit.sources.DataSourceOpenStack.DataSourceOpenStack'>
2019-01-11 14:14:16,346 - url_helper.py[DEBUG]: [0/1] open 'http://169.254.169.254/openstack' with {'url': 'http://169.254.169.254/openstack', 'headers': {'User-Agent': 'Cloud-Init/0.7.9'}, 'allow_redirects': True, 'method': 'GET', 'timeout': 10.0} configuration
2019-01-11 14:14:18,459 - url_helper.py[DEBUG]: Read from http://169.254.169.254/openstack (200, 94b) after 1 attempts
2019-01-11 14:14:18,459 - DataSourceOpenStack.py[DEBUG]: Using metadata source: 'http://169.254.169.254'
2019-01-11 14:14:18,460 - url_helper.py[DEBUG]: [0/6] open 'http://169.254.169.254/openstack' with {'url': 'http://169.254.169.254/openstack', 'headers': {'User-Agent': 'Cloud-Init/0.7.9'}, 'allow_redirects': True, 'method': 'GET', 'timeout': 10.0} configuration
(text is omitted)
2019-01-11 14:14:25,005 - util.py[DEBUG]: Crawl of openstack metadata service took 6.546 seconds
2019-01-11 14:14:25,005 - handlers.py[DEBUG]: finish: init-network/search-OpenStack: SUCCESS: found network data from DataSourceOpenStack
(text is omitted)

In this scenario, cloud-init accessed Nova Metadata Service via a metadata server.

Once a datastore is accessed, the type and errors accessing the datastore are logged into /run/cloud-init/result.json (which later will be symlinked to /var/lib/cloud/data/result.json):

cat /var/lib/cloud/data/result.json | jq .
# Output
{
 "v1": {
  "datasource": "DataSourceOpenStack [net,ver=2]",
  "errors": []
 }
}

How cloud-init applies configuration

After a datasource is detected, all the needed information is retrieved, and cloud-init starts applying the configuration.

Default configuration

cloud-init, which is supplied as a part of a cloud image, contains distribution-specific configuration files in /etc/cloud.

Users may override the default values by providing a user_data file.

Example of a default configuration file /etc/cloud/cloud.cfg, which comes prepackaged in Red Hat Enterprise Linux cloud image:

cat /etc/cloud/cloud.cfg
users:
 - default

disable_root: 1
ssh_pwauth:   0

mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']
resize_rootfs_tmp: /dev
ssh_deletekeys:   0
ssh_genkeytypes:  ~
syslog_fix_perms: ~

cloud_init_modules:
 - migrator
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - rsyslog
 - users-groups
 - ssh

cloud_config_modules:
 - mounts
 - locale
 - set-passwords
 - rh_subscription
 - yum-add-repo
 - package-update-upgrade-install
 - timezone
 - puppet
 - chef
 - salt-minion
 - mcollective
 - disable-ec2-metadata
 - runcmd

cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change

system_info:
  default_user:
    name: cloud-user
    lock_passwd: true
    gecos: Cloud User
    groups: [wheel, adm, systemd-journal]
    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
    shell: /bin/bash
  distro: rhel
  paths:
    cloud_dir: /var/lib/cloud
    templates_dir: /etc/cloud/templates
  ssh_svcname: sshd

The default configuration is used by cloud-init to configure the minimal necessary configuration that will result in a successful boot.

Network

Nova Metadata Service hosts a network_data.json file, which describes all the network interfaces attached to the instance and their configuration:

curl http://169.254.169.254/openstack/latest/network_data.json | jq .
# Output
{
    "services": [],
    "networks": [{
        "network_id": "a2332620-8027-4591-a0a6-dae312bc0944",
        "link": "tap7dbc4527-31",
        "type": "ipv4_dhcp",
        "id": "network0"
    }],
    "links": [{
        "ethernet_mac_address": "fa:16:3e:d8:bb:81",
        "mtu": 8950,
        "type": "vhostuser",
        "id": "tap7dbc4527-31",
        "vif_id": "7dbc4527-319a-45c6-8a0e-a27f92d062d3"
    }]
}

During datasource discovery, network_data.json is read and parsed:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:19,136 - url_helper.py[DEBUG]: [0/6] open 'http://169.254.169.254/openstack/2015-10-15/network_data.json' with {'url': 'http://169.254.169.254/openstack/2015-10-15/network_data.json', 'headers': {'User-Agent': 'Cloud-Init/0.7.9'}, 'allow_redirects': True, 'method': 'GET', 'timeout': 10.0} configuration
2019-01-11 14:14:19,325 - url_helper.py[DEBUG]: Read from http://169.254.169.254/openstack/2015-10-15/network_data.json (200, 317b) after 1 attempts
(text is omitted)

Then cloud-init parses the network interfaces detected by the operating system and attempts to configure them based on the distribution’s requirements:

cat /var/log/cloud-init.log
# Output
(text is omitted)
019-01-11 14:14:25,049 - util.py[DEBUG]: Read 18 bytes from /sys/class/net/eth0/address
2019-01-11 14:14:25,049 - stages.py[DEBUG]: applying net config names for {'version': 1, 'config': [{'subnets': [{'type': 'dhcp'}], 'type': 'physical', 'name': 'eth0', 'mac_address': 'fa:16:3e:d8:bb:81'}]}
2019-01-11 14:14:25,049 - stages.py[DEBUG]: Using distro class <class 'cloudinit.distros.rhel.Distro'>
2019-01-11 14:14:25,049 - util.py[DEBUG]: Reading from /sys/class/net/eth0/addr_assign_type (quiet=False)
2019-01-11 14:14:25,049 - util.py[DEBUG]: Read 2 bytes from /sys/class/net/eth0/addr_assign_type
2019-01-11 14:14:25,050 - util.py[DEBUG]: Reading from /sys/class/net/eth0/address (quiet=False)
2019-01-11 14:14:25,050 - util.py[DEBUG]: Read 18 bytes from /sys/class/net/eth0/address
2019-01-11 14:14:25,050 - util.py[DEBUG]: Reading from /sys/class/net/lo/addr_assign_type (quiet=False)
2019-01-11 14:14:25,050 - util.py[DEBUG]: Read 2 bytes from /sys/class/net/lo/addr_assign_type
2019-01-11 14:14:25,050 - util.py[DEBUG]: Reading from /sys/class/net/lo/address (quiet=False)
2019-01-11 14:14:25,050 - util.py[DEBUG]: Read 18 bytes from /sys/class/net/lo/address
2019-01-11 14:14:25,050 - util.py[DEBUG]: Reading from /sys/class/net/eth0/operstate (quiet=False)
2019-01-11 14:14:25,050 - util.py[DEBUG]: Read 3 bytes from /sys/class/net/eth0/operstate
2019-01-11 14:14:25,050 - util.py[DEBUG]: Reading from /sys/class/net/lo/operstate (quiet=False)
2019-01-11 14:14:25,050 - util.py[DEBUG]: Read 8 bytes from /sys/class/net/lo/operstate
2019-01-11 14:14:25,051 - util.py[DEBUG]: Running command ['ip', '-6', 'addr', 'show', 'permanent', 'scope', 'global'] with allowed return codes [0] (shell=False, capture=True)
2019-01-11 14:14:25,056 - util.py[DEBUG]: Running command ['ip', '-4', 'addr', 'show'] with allowed return codes [0] (shell=False, capture=True)
2019-01-11 14:14:25,059 - __init__.py[DEBUG]: no work necessary for renaming of [['fa:16:3e:d8:bb:81', 'eth0']]
2019-01-11 14:14:25,060 - stages.py[INFO]: Applying network configuration from fallback bringup=True: {'version': 1, 'config': [{'subnets': [{'type': 'dhcp'}], 'type': 'physical', 'name': 'eth0', 'mac_address': 'fa:16:3e:d8:bb:81'}]}
2019-01-11 14:14:25,062 - util.py[DEBUG]: Writing to /etc/sysconfig/network-scripts/ifcfg-eth0 - wb: [420] 159 bytes
2019-01-11 14:14:25,063 - util.py[DEBUG]: Restoring selinux mode for /etc/sysconfig/network-scripts/ifcfg-eth0 (recursive=False)
2019-01-11 14:14:25,063 - util.py[DEBUG]: Restoring selinux mode for /etc/sysconfig/network-scripts/ifcfg-eth0 (recursive=False)
2019-01-11 14:14:25,064 - util.py[DEBUG]: Reading from /etc/resolv.conf (quiet=False)
2019-01-11 14:14:25,064 - util.py[DEBUG]: Read 115 bytes from /etc/resolv.conf
2019-01-11 14:14:25,064 - util.py[DEBUG]: Writing to /etc/resolv.conf - wb: [420] 186 bytes
(text is omitted)

Metadata, SSH keys, Hostname, Storage(Partitions/filesystems), Devices

Nova Metadata Service hosts a meta_data.json file, which describes all the metadata, SSH keys, hostname, storage, and devices attached to the instance:

curl http://169.254.169.254/openstack/latest/meta_data.json | jq .
# Output
{
    "random_seed": "aenkmMbb5FmAWiwUgbz8QvSCx+pF9Ny/5d35J1yIEZZzJiZTlZJ+0vkUCN5ytJKkeDLdn+5NfBYWUCU7njYYc/Yt/dCCkBKhWT38vUzqcRQuGlEWWwErAmKtmUUj69E2D1iw818WyPLdVLA7KTnBD5Gp6F+lseG9EgLtahiceK1OTayg5c0Q/DkjnA0MBPCDGfhS4Ef0ekTg7WCoQgL877D42+mI1l+nVgD28SwVh/+zmZ2+S3v2CnNckjFnOgQHtTxxx32MxreK2Hd4qM3CUPnB0qrpJr6298X6K6WQRipV4a7x7Cm9ZjzOMy4p67T5rZly5ggYuCmuW3KvAkOnwBIbGVM7Z8vgoenj+astHJ+HJNuqhyONfNXt0gZZIkAwLmDF9cVIlABZmsM8C0uxDh9yTaOjE6m4XGUmxgq943ZQKFaBJzkWl0dgtryq8y5rl94PVRD2HZHSk48SJBJjIVuQmSfARfqqNbqh0wk1AR/h0Xu8GKw/lIrejE8bMO/mL+0OTIS1I46lcSVZVAYqRo5NNgmetT2jF04eB1TdJU1ygp3/Z1c9cw5ode8ehhSjbTxaVElMdbMv65hhDa2Vjq/7UaVPmFIyJB/Hhz1YEnwkRcVYmolrVONwoOBxcxGxFjE0ToGlCFUSqABUFxzUMwAmWjR0kSsjw820Cj9nOXM=",
    "uuid": "380cc09f-25ce-4a4e-aa88-bba53234d92e",
    "availability_zone": "nova",
    "keys": [{
        "data": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDC/aZPawAn3K6K2OMzsENlcluwztaKYFeT3uASXGKlXeGBniZeidns3DnU4pCb4t+1weq5d+B4Tgyt18IDVWUJ5Ehd1xNdAP4Q6nB26WfVMH7PuHgzRLnMZiwhZz4BoxVAtTPfRv/FQGv7f+AQcpblZLz4LefBdrnYnc90ObDPQFfQNMttrars9CfW/RXanYvnUm+VQwzqftqoD3pI5tGaXjEQxrN1+LCteLHB5rABbVDMczilNz+Bg3KlX/pmUhqtrQvXMVHXBs2WuxklL9ibBGzQGTs9nyHNDI/wNs16cSz/QD2KUnEZajzDRChM+Riu6okeJA0JcyRI1Dae2FUf Generated-by-Nova",
        "type": "ssh",
        "name": "lab-keys"
    }],
    "hostname": "rhel",
    "launch_index": 0,
    "devices": [],
    "public_keys": {
        "lab-keys": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDC/aZPawAn3K6K2OMzsENlcluwztaKYFeT3uASXGKlXeGBniZeidns3DnU4pCb4t+1weq5d+B4Tgyt18IDVWUJ5Ehd1xNdAP4Q6nB26WfVMH7PuHgzRLnMZiwhZz4BoxVAtTPfRv/FQGv7f+AQcpblZLz4LefBdrnYnc90ObDPQFfQNMttrars9CfW/RXanYvnUm+VQwzqftqoD3pI5tGaXjEQxrN1+LCteLHB5rABbVDMczilNz+Bg3KlX/pmUhqtrQvXMVHXBs2WuxklL9ibBGzQGTs9nyHNDI/wNs16cSz/QD2KUnEZajzDRChM+Riu6okeJA0JcyRI1Dae2FUf Generated-by-Nova"
    },
    "project_id": "678e269fc36d498586223d3d72fe694a",
    "name": "RHEL"
}

Afterward, cloud-init performs the required configuration:

cat /var/log/cloud-init.log
# Output
(text is omitted)
2019-01-11 14:14:25,835 - cc_set_hostname.py[DEBUG]: Setting the hostname to rhel (rhel)
2019-01-11 14:14:25,835 - util.py[DEBUG]: Running command ['hostnamectl', 'set-hostname', 'rhel'] with allowed return codes [0] (shell=False, capture=True)
(text is omitted)
2019-01-11 14:14:27,727 - stages.py[DEBUG]: Running module ssh-authkey-fingerprints (<module 'cloudinit.config.cc_ssh_authkey_fingerprints' from '/usr/lib/python2.7/site-packages/cloudinit/config/cc_ssh_authkey_fingerprints.pyc'>) with frequency once-per-instance
2019-01-11 14:14:27,728 - handlers.py[DEBUG]: start: modules-final/config-ssh-authkey-fingerprints: running config-ssh-authkey-fingerprints with frequency once-per-instance
2019-01-11 14:14:27,728 - util.py[DEBUG]: Writing to /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh_authkey_fingerprints - wb: [420] 20 bytes
2019-01-11 14:14:27,729 - util.py[DEBUG]: Restoring selinux mode for /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh_authkey_fingerprints (recursive=False)
2019-01-11 14:14:27,730 - util.py[DEBUG]: Restoring selinux mode for /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh_authkey_fingerprints (recursive=False)
2019-01-11 14:14:27,730 - helpers.py[DEBUG]: Running config-ssh-authkey-fingerprints using lock (<FileLock using file '/var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh_authkey_fingerprints'>)
2019-01-11 14:14:27,731 - util.py[DEBUG]: Reading from /etc/ssh/sshd_config (quiet=False)
2019-01-11 14:14:27,731 - util.py[DEBUG]: Read 3906 bytes from /etc/ssh/sshd_config
2019-01-11 14:14:27,733 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh (recursive=True)
2019-01-11 14:14:27,733 - util.py[DEBUG]: Reading from /home/cloud-user/.ssh/authorized_keys (quiet=False)
2019-01-11 14:14:27,733 - util.py[DEBUG]: Read 399 bytes from /home/cloud-user/.ssh/authorized_keys
2019-01-11 14:14:27,760 - handlers.py[DEBUG]: finish: modules-final/config-ssh-authkey-fingerprints: SUCCESS: config-ssh-authkey-fingerprints ran successfully
(text is omitted)

Userdata

cloud-init is extended via modules, each module exposes different capabilities.
Besides the basic actions that cloud-init does (mentioned above), users can pass additional configuration requests using modules.

Nova Metadata Service hosts a user_data file that contains additional configuration provided by the user.
user_data file may contain a bash script, python script, or cloud-init modules:

curl http://169.254.169.254/openstack/latest/user_data
#cloud-config
user: cloud-user
password: cloud-password
chpasswd: {expire: False}
ssh_pwauth: True
disable_root: 0

This user_data will perform the following configuration:

In the background, cloud-init will apply this configuration:

cat /var/log/cloud-init.log
(text is omitted)
2019-01-11 14:14:25,885 - __init__.py[DEBUG]: Adding user cloud-user
2019-01-11 14:14:25,885 - util.py[DEBUG]: Running hidden command to protect sensitive input/output logstring: ['useradd', 'cloud-user', '--comment', 'Cloud User', '--groups', 'adm,systemd-journal,wheel', '--shell', '/bin/bash', '-m']
2019-01-11 14:14:26,079 - util.py[DEBUG]: Running command ['passwd', '-l', 'cloud-user'] with allowed return codes [0] (shell=False, capture=True)
2019-01-11 14:14:26,151 - util.py[DEBUG]: Reading from /etc/sudoers (quiet=False)
2019-01-11 14:14:26,169 - util.py[DEBUG]: Read 3973 bytes from /etc/sudoers
2019-01-11 14:14:26,170 - util.py[DEBUG]: Restoring selinux mode for /etc/sudoers.d (recursive=False)
2019-01-11 14:14:26,170 - util.py[DEBUG]: Writing to /etc/sudoers.d/90-cloud-init-users - wb: [288] 131 bytes
2019-01-11 14:14:26,171 - util.py[DEBUG]: Restoring selinux mode for /etc/sudoers.d/90-cloud-init-users (recursive=False)
2019-01-11 14:14:26,171 - util.py[DEBUG]: Restoring selinux mode for /etc/sudoers.d/90-cloud-init-users (recursive=False)
2019-01-11 14:14:26,171 - handlers.py[DEBUG]: finish: init-network/config-users-groups: SUCCESS: config-users-groups ran successfully
2019-01-11 14:14:26,172 - stages.py[DEBUG]: Running module ssh (<module 'cloudinit.config.cc_ssh' from '/usr/lib/python2.7/site-packages/cloudinit/config/cc_ssh.pyc'>) with frequency once-per-instance
2019-01-11 14:14:26,172 - handlers.py[DEBUG]: start: init-network/config-ssh: running config-ssh with frequency once-per-instance
2019-01-11 14:14:26,172 - util.py[DEBUG]: Writing to /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh - wb: [420] 19 bytes
2019-01-11 14:14:26,173 - util.py[DEBUG]: Restoring selinux mode for /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh (recursive=False)
2019-01-11 14:14:26,173 - util.py[DEBUG]: Restoring selinux mode for /var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh (recursive=False)
2019-01-11 14:14:26,173 - helpers.py[DEBUG]: Running config-ssh using lock (<FileLock using file '/var/lib/cloud/instances/380cc09f-25ce-4a4e-aa88-bba53234d92e/sem/config_ssh'>)
2019-01-11 14:14:26,174 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user (recursive=True)
2019-01-11 14:14:26,175 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh (recursive=False)
2019-01-11 14:14:26,175 - util.py[DEBUG]: Changing the ownership of /home/cloud-user/.ssh to 1000:1000
2019-01-11 14:14:26,192 - util.py[DEBUG]: Reading from /etc/ssh/sshd_config (quiet=False)
2019-01-11 14:14:26,199 - util.py[DEBUG]: Read 3907 bytes from /etc/ssh/sshd_config
2019-01-11 14:14:26,199 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh (recursive=True)
2019-01-11 14:14:26,199 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh (recursive=False)
2019-01-11 14:14:26,200 - util.py[DEBUG]: Writing to /home/cloud-user/.ssh/authorized_keys - wb: [384] 399 bytes
2019-01-11 14:14:26,200 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh/authorized_keys (recursive=False)
2019-01-11 14:14:26,200 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh/authorized_keys (recursive=False)
2019-01-11 14:14:26,200 - util.py[DEBUG]: Changing the ownership of /home/cloud-user/.ssh/authorized_keys to 1000:1000
2019-01-11 14:14:26,201 - util.py[DEBUG]: Restoring selinux mode for /home/cloud-user/.ssh (recursive=True)
2019-01-11 14:14:26,223 - util.py[DEBUG]: Restoring selinux mode for /root (recursive=True)
2019-01-11 14:14:26,244 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh (recursive=False)
2019-01-11 14:14:26,245 - util.py[DEBUG]: Changing the ownership of /root/.ssh to 0:0
2019-01-11 14:14:26,245 - util.py[DEBUG]: Reading from /etc/ssh/sshd_config (quiet=False)
2019-01-11 14:14:26,245 - util.py[DEBUG]: Read 3907 bytes from /etc/ssh/sshd_config
2019-01-11 14:14:26,245 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh (recursive=True)
2019-01-11 14:14:26,246 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh (recursive=False)
2019-01-11 14:14:26,246 - util.py[DEBUG]: Writing to /root/.ssh/authorized_keys - wb: [384] 399 bytes
2019-01-11 14:14:26,246 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh/authorized_keys (recursive=False)
2019-01-11 14:14:26,246 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh/authorized_keys (recursive=False)
2019-01-11 14:14:26,246 - util.py[DEBUG]: Changing the ownership of /root/.ssh/authorized_keys to 0:0
2019-01-11 14:14:26,247 - util.py[DEBUG]: Restoring selinux mode for /root/.ssh (recursive=True)
2019-01-11 14:14:26,247 - handlers.py[DEBUG]: finish: init-network/config-ssh: SUCCESS: config-ssh ran successfully
(text is omitted)
2019-01-11 14:14:27,035 - cc_set_passwords.py[DEBUG]: Changing password for ['cloud-user']:
2019-01-11 14:14:27,035 - util.py[DEBUG]: Running command ['chpasswd'] with allowed return codes [0] (shell=False, capture=True)
2019-01-11 14:14:27,086 - util.py[DEBUG]: Reading from /etc/ssh/sshd_config (quiet=False)
2019-01-11 14:14:27,086 - util.py[DEBUG]: Read 3907 bytes from /etc/ssh/sshd_config
2019-01-11 14:14:27,087 - cc_set_passwords.py[DEBUG]: Replacing auth line 65 with yes
2019-01-11 14:14:27,088 - util.py[DEBUG]: Writing to /etc/ssh/sshd_config - wb: [384] 3906 bytes
2019-01-11 14:14:27,088 - util.py[DEBUG]: Restoring selinux mode for /etc/ssh/sshd_config (recursive=False)
2019-01-11 14:14:27,089 - util.py[DEBUG]: Restoring selinux mode for /etc/ssh/sshd_config (recursive=False)
2019-01-11 14:14:27,090 - util.py[DEBUG]: Running command ['service', 'sshd', 'restart'] with allowed return codes [0] (shell=False, capture=True)
2019-01-11 14:14:27,243 - cc_set_passwords.py[DEBUG]: Restarted the ssh daemon
2019-01-11 14:14:27,244 - handlers.py[DEBUG]: finish: modules-config/config-set-passwords: SUCCESS: config-set-passwords ran successfully
(text is omitted)

Summary

cloud-init and Nova Metadata Service work together to ensure an instance’s successful spawn.

Instance customization is allowed due to the modularity and robustness of cloud-init.

Every action is logged to disk and can be viewed later when required.

Back To Top