├── tests ├── __init__.py ├── unittests │ ├── test_runs │ │ └── __init__.py │ ├── test_datasource │ │ └── __init__.py │ ├── test_filters │ │ └── __init__.py │ ├── test_handler │ │ └── __init__.py │ ├── test_vmware │ │ └── __init__.py │ ├── test_distros │ │ ├── test_sles.py │ │ ├── test_opensuse.py │ │ ├── test_netbsd.py │ │ ├── __init__.py │ │ ├── test_dragonflybsd.py │ │ └── test_gentoo.py │ └── __init__.py ├── cloud_tests │ ├── platforms │ │ ├── ec2 │ │ │ └── __init__.py │ │ ├── lxd │ │ │ └── __init__.py │ │ ├── azurecloud │ │ │ └── __init__.py │ │ └── nocloudkvm │ │ │ └── __init__.py │ └── testcases │ │ ├── modules │ │ ├── debug_enable.yaml │ │ ├── debug_disable.yaml │ │ ├── __init__.py │ │ ├── bootcmd.yaml │ │ ├── runcmd.yaml │ │ ├── final_message.yaml │ │ ├── ssh_auth_key_fingerprints_disable.yaml │ │ ├── apt_pipelining_disable.yaml │ │ ├── seed_random_data.yaml │ │ ├── lxd_dir.yaml │ │ ├── apt_pipelining_os.yaml │ │ ├── ssh_import_id.yaml │ │ ├── apt_configure_security.yaml │ │ ├── README.md │ │ ├── ntp_timesyncd.yaml │ │ ├── set_password_list.py │ │ ├── byobu.yaml │ │ ├── set_hostname.yaml │ │ ├── set_password_list_string.py │ │ ├── keys_to_console.yaml │ │ ├── set_password.yaml │ │ ├── ntp_chrony.yaml │ │ ├── seed_random_command.yaml │ │ ├── timezone.yaml │ │ ├── apt_configure_primary.yaml │ │ ├── apt_configure_conf.yaml │ │ ├── apt_configure_disable_suites.yaml │ │ ├── apt_configure_proxy.yaml │ │ ├── runcmd.py │ │ ├── snap.yaml │ │ ├── timezone.py │ │ ├── bootcmd.py │ │ ├── debug_enable.py │ │ ├── locale.yaml │ │ ├── ntp.yaml │ │ ├── apt_configure_disable_suites.py │ │ ├── ntp_timesyncd.py │ │ ├── seed_random_data.py │ │ ├── set_hostname_fqdn.yaml │ │ ├── snap.py │ │ ├── apt_configure_security.py │ │ ├── set_hostname.py │ │ ├── apt_pipelining_os.py │ │ ├── apt_pipelining_disable.py │ │ ├── debug_disable.py │ │ ├── ssh_import_id.py │ │ ├── ssh_auth_key_fingerprints_disable.py │ │ ├── ntp_servers.yaml │ │ ├── apt_configure_sources_keyserver.yaml │ │ ├── ssh_auth_key_fingerprints_enable.py │ │ ├── apt_configure_conf.py │ │ ├── lxd_bridge.yaml │ │ ├── set_password.py │ │ ├── keys_to_console.py │ │ ├── apt_configure_sources_ppa.yaml │ │ ├── ntp.py │ │ ├── landscape.yaml │ │ ├── set_password_expire.py │ │ ├── apt_configure_sources_list.yaml │ │ ├── set_password_expire.yaml │ │ ├── byobu.py │ │ ├── apt_configure_sources_ppa.py │ │ ├── apt_configure_proxy.py │ │ ├── apt_configure_sources_key.py │ │ ├── ntp_pools.yaml │ │ ├── apt_configure_sources_keyserver.py │ │ ├── ssh_keys_generate.yaml │ │ ├── ntp_chrony.py │ │ ├── apt_configure_primary.py │ │ ├── package_update_upgrade_install.yaml │ │ ├── locale.py │ │ ├── lxd_dir.py │ │ └── set_hostname_fqdn.py │ │ ├── bugs │ │ ├── lp1611074.yaml │ │ ├── __init__.py │ │ ├── lp1511485.yaml │ │ ├── lp1511485.py │ │ ├── lp1628337.yaml │ │ ├── README.md │ │ └── lp1628337.py │ │ ├── main │ │ ├── __init__.py │ │ ├── README.md │ │ ├── command_output_simple.yaml │ │ └── command_output_simple.py │ │ └── examples │ │ ├── __init__.py │ │ ├── run_apt_upgrade.yaml │ │ ├── alter_completion_message.yaml │ │ ├── run_commands.yaml │ │ ├── run_commands_first_boot.yaml │ │ ├── README.md │ │ ├── install_arbitrary_packages.yaml │ │ ├── run_commands.py │ │ ├── run_commands_first_boot.py │ │ ├── install_run_chef_recipes.py │ │ ├── TODO.md │ │ ├── install_arbitrary_packages.py │ │ ├── add_apt_repositories.yaml │ │ ├── add_apt_repositories.py │ │ ├── run_apt_upgrade.py │ │ └── configure_instance_trusted_ca_certificates.py ├── data │ ├── merge_sources │ │ ├── expected1.yaml │ │ ├── expected3.yaml │ │ ├── expected4.yaml │ │ ├── source11-2.yaml │ │ ├── source11-3.yaml │ │ ├── source4-1.yaml │ │ ├── expected2.yaml │ │ ├── source1-1.yaml │ │ ├── source3-1.yaml │ │ ├── expected11.yaml │ │ ├── expected12.yaml │ │ ├── source11-1.yaml │ │ ├── source12-2.yaml │ │ ├── source2-2.yaml │ │ ├── source6-1.yaml │ │ ├── source2-1.yaml │ │ ├── source5-1.yaml │ │ ├── expected5.yaml │ │ ├── source12-1.yaml │ │ ├── source10-1.yaml │ │ ├── source1-2.yaml │ │ ├── source3-2.yaml │ │ ├── source4-2.yaml │ │ ├── source9-2.yaml │ │ ├── expected6.yaml │ │ ├── source5-2.yaml │ │ ├── expected10.yaml │ │ ├── source10-2.yaml │ │ ├── source6-2.yaml │ │ ├── source9-1.yaml │ │ ├── expected9.yaml │ │ ├── source8-2.yaml │ │ ├── expected8.yaml │ │ ├── source8-1.yaml │ │ ├── source7-2.yaml │ │ ├── source7-1.yaml │ │ └── expected7.yaml │ ├── roots │ │ └── simple_ubuntu │ │ │ └── etc │ │ │ └── networks │ │ │ └── interfaces │ ├── old_pickles │ │ ├── focal-20.1-10-g71af48df-0ubuntu5.pkl │ │ └── focal-20.3-2-g371b392c-0ubuntu1~20.04.1.pkl │ ├── azure │ │ ├── parse_certificates_fingerprints │ │ ├── non_unicode_random_string │ │ ├── pubkey_extract_ssh_key │ │ └── pubkey_extract_cert │ ├── netinfo │ │ ├── sample-iproute-output-v4 │ │ ├── sample-route-output-v4 │ │ ├── sample-ipaddrshow-output-down │ │ ├── netdev-formatted-output-down │ │ ├── new-ifconfig-output-down │ │ ├── sample-ipaddrshow-output │ │ ├── sample-iproute-output-v6 │ │ ├── netdev-formatted-output │ │ ├── new-ifconfig-output │ │ ├── old-ifconfig-output │ │ └── sample-route-output-v6 │ ├── filter_cloud_multipart_1.email │ ├── filter_cloud_multipart_header.email │ ├── zpool_status_simple.txt │ ├── user_data.1.txt │ ├── vmware │ │ ├── cust-dhcp-2nic.cfg │ │ └── cust-static-2nic.cfg │ ├── filter_cloud_multipart_2.email │ ├── filter_cloud_multipart.yaml │ ├── mountinfo_raring_btrfs.txt │ └── mount_parse_ext.txt └── integration_tests │ ├── assets │ ├── test_version_change.pkl │ └── keys │ │ ├── id_rsa.test1.pub │ │ ├── id_rsa.test2.pub │ │ └── id_rsa.test3.pub │ ├── __init__.py │ ├── bugs │ ├── test_gh868.py │ ├── test_lp1886531.py │ ├── test_lp1897099.py │ └── test_lp1900837.py │ ├── modules │ ├── test_runcmd.py │ ├── test_timezone.py │ ├── test_snap.py │ ├── test_command_output.py │ └── test_seed_random_data.py │ └── test_logging.py ├── cloudinit ├── __init__.py ├── cmd │ ├── __init__.py │ ├── tests │ │ └── __init__.py │ └── devel │ │ ├── tests │ │ └── __init__.py │ │ └── __init__.py ├── tests │ ├── __init__.py │ └── test_event.py ├── analyze │ └── __init__.py ├── filters │ └── __init__.py ├── net │ └── tests │ │ └── __init__.py ├── distros │ ├── tests │ │ └── __init__.py │ ├── centos.py │ ├── rocky.py │ ├── almalinux.py │ ├── eurolinux.py │ ├── virtuozzo.py │ ├── dragonflybsd.py │ ├── sles.py │ ├── fedora.py │ ├── parsers │ │ ├── __init__.py │ │ └── networkmanager_conf.py │ └── amazon.py ├── sources │ ├── helpers │ │ ├── __init__.py │ │ └── vmware │ │ │ ├── __init__.py │ │ │ └── imc │ │ │ ├── __init__.py │ │ │ ├── config_source.py │ │ │ ├── boot_proto.py │ │ │ ├── config_namespace.py │ │ │ ├── guestcust_state.py │ │ │ ├── guestcust_error.py │ │ │ └── guestcust_event.py │ └── tests │ │ └── __init__.py ├── version.py ├── type_utils.py └── mergers │ └── m_str.py ├── packages └── debian │ ├── compat │ ├── source │ └── format │ ├── manpages │ ├── dirs │ ├── watch │ ├── changelog.in │ ├── cloud-init.postinst │ ├── cloud-init.preinst │ ├── control.in │ └── rules ├── doc-requirements.txt ├── doc ├── rtd │ ├── topics │ │ ├── hacking.rst │ │ ├── security.rst │ │ ├── datasources │ │ │ ├── maas.rst │ │ │ ├── e24cloud.rst │ │ │ ├── gce.rst │ │ │ ├── fallback.rst │ │ │ ├── rbxcloud.rst │ │ │ ├── zstack.rst │ │ │ ├── upcloud.rst │ │ │ ├── vultr.rst │ │ │ └── digitalocean.rst │ │ └── network-config-format-eni.rst │ └── static │ │ └── logo.png ├── examples │ ├── plain-ignored.txt │ ├── seed │ │ ├── user-data │ │ └── README │ ├── user-script.txt │ ├── cloud-config-update-packages.txt │ ├── include.txt │ ├── upstart-cloud-config.txt │ ├── upstart-rclocal.txt │ ├── cloud-config-final-message.txt │ ├── cloud-config-update-apt.txt │ ├── cloud-config-archive.txt │ ├── include-once.txt │ ├── cloud-config-phone-home.txt │ ├── cloud-config-install-packages.txt │ ├── cloud-config-reporting.txt │ ├── cloud-config-gluster.txt │ ├── cloud-config-resolv-conf.txt │ ├── cloud-config-vendor-data.txt │ ├── cloud-config-boot-cmds.txt │ ├── cloud-config-launch-index.txt │ ├── cloud-config-yum-repo.txt │ ├── cloud-config-landscape.txt │ ├── part-handler.txt │ ├── cloud-config-archive-launch-index.txt │ ├── cloud-config-ntp.txt │ ├── cloud-config-run-cmds.txt │ ├── kernel-cmdline.txt │ └── cloud-config-growpart.txt ├── sources │ └── ovf │ │ └── user-data └── man │ └── cloud-id.1 ├── .readthedocs.yaml ├── test-requirements.txt ├── config └── cloud.cfg.d │ └── README ├── sysvinit ├── gentoo │ ├── cloud-final │ ├── cloud-init-local │ ├── cloud-config │ └── cloud-init ├── netbsd │ ├── cloudinit │ ├── cloudfinal │ ├── cloudconfig │ └── cloudinitlocal └── freebsd │ ├── cloudconfig │ ├── cloudinit │ ├── cloudfinal │ └── cloudinitlocal ├── templates ├── timesyncd.conf.tmpl ├── ntp.conf.alpine.tmpl ├── systemd.resolved.conf.tmpl ├── hosts.photon.tmpl ├── hosts.freebsd.tmpl ├── hosts.debian.tmpl ├── hosts.redhat.tmpl ├── resolv.conf.tmpl ├── hosts.alpine.tmpl ├── chrony.conf.sles.tmpl └── chrony.conf.opensuse.tmpl ├── upstart ├── cloud-init.conf ├── cloud-config.conf ├── cloud-final.conf ├── cloud-init-local.conf └── cloud-log-shutdown.conf ├── integration-requirements.txt ├── tools ├── 21-cloudinit.conf ├── run-pyflakes ├── run-pep8 ├── pipremove ├── build-on-openbsd ├── hook-hotplug ├── validate-yaml.py ├── motd-hook ├── hook-network-manager ├── hook-dhclient ├── hook-rhel.sh ├── .github-cla-signers ├── Z99-cloudinit-warnings.sh ├── .lp-to-git-user └── cloudconfig-schema ├── systemd ├── cloud-init.target ├── cloud-init-hotplugd.socket ├── cloud-config.service.tmpl ├── cloud-config.target ├── cloud-final.service.tmpl ├── cloud-init-local.service.tmpl └── cloud-init-hotplugd.service ├── udev └── 10-cloud-init-hook-hotplug.rules ├── MANIFEST.in ├── snapcraft.yaml ├── .gitignore ├── cloud-tests-requirements.txt ├── .github └── workflows │ └── stale.yml └── requirements.txt /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/cmd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /cloudinit/analyze/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/cmd/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/filters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/net/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/cmd/devel/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/distros/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/sources/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unittests/test_runs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/cloud_tests/platforms/ec2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/cloud_tests/platforms/lxd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unittests/test_datasource/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unittests/test_filters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unittests/test_handler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unittests/test_vmware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /tests/cloud_tests/platforms/azurecloud/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/cloud_tests/platforms/nocloudkvm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected1.yaml: -------------------------------------------------------------------------------- 1 | Blah: ['blah2', 'b'] 2 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected3.yaml: -------------------------------------------------------------------------------- 1 | Blah: [blah2, 'blah1'] 2 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected4.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: {} 3 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source11-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | b: 4 4 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source11-3.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 22 4 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source4-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: 3 | b: 1 4 | -------------------------------------------------------------------------------- /doc-requirements.txt: -------------------------------------------------------------------------------- 1 | doc8 2 | m2r 3 | sphinx<2 4 | sphinx_rtd_theme 5 | pyyaml 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected2.yaml: -------------------------------------------------------------------------------- 1 | Blah: 3 2 | Blah2: 2 3 | Blah3: [1] 4 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source1-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: ['blah2'] 3 | 4 | -------------------------------------------------------------------------------- /doc/rtd/topics/hacking.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../../HACKING.rst 2 | .. vi: textwidth=78 3 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source3-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: ['blah1'] 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected11.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 22 4 | b: 4 5 | c: 3 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected12.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 4 | e: 5 | y: 2 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source11-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 1 4 | b: 2 5 | c: 3 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source12-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 4 | e: 5 | y: 2 6 | -------------------------------------------------------------------------------- /tests/data/roots/simple_ubuntu/etc/networks/interfaces: -------------------------------------------------------------------------------- 1 | auto lo 2 | iface lo inet loopback 3 | 4 | -------------------------------------------------------------------------------- /doc/rtd/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puppetlabs/cloud-init/main/doc/rtd/static/logo.png -------------------------------------------------------------------------------- /packages/debian/manpages: -------------------------------------------------------------------------------- 1 | doc/man/cloud-id.1 2 | doc/man/cloud-init-per.1 3 | doc/man/cloud-init.1 4 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source2-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | Blah: 3 4 | Blah2: 2 5 | Blah3: [1] 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source6-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | run_cmds: 4 | - bash 5 | - top 6 | -------------------------------------------------------------------------------- /doc/examples/plain-ignored.txt: -------------------------------------------------------------------------------- 1 | #ignored 2 | Nothing will be done with this part by the UserDataHandler 3 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source2-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | 4 | Blah: 1 5 | Blah2: 2 6 | Blah3: 3 7 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source5-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | 4 | Blah: 1 5 | Blah2: 2 6 | Blah3: 3 7 | -------------------------------------------------------------------------------- /packages/debian/dirs: -------------------------------------------------------------------------------- 1 | var/lib/cloud 2 | usr/bin 3 | usr/share/doc/cloud 4 | etc/cloud 5 | lib/udev/rules.d 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected5.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | Blah: 3 4 | Blah2: 2 5 | Blah3: [1] 6 | 7 | 8 | -------------------------------------------------------------------------------- /doc/rtd/topics/security.rst: -------------------------------------------------------------------------------- 1 | .. _security: 2 | 3 | .. mdinclude:: ../../../SECURITY.md 4 | 5 | .. vi: textwidth=78 6 | -------------------------------------------------------------------------------- /packages/debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | https://launchpad.net/cloud-init/+download .*/\+download/cloud-init-(.+)\.tar.gz 3 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source12-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | a: 4 | c: 1 5 | d: 2 6 | e: 7 | z: a 8 | y: b 9 | -------------------------------------------------------------------------------- /doc/examples/seed/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | runcmd: 3 | - [ sh, -c, 'echo ==== $(date) ====; echo HI WORLD; echo =======' ] 4 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source10-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | power_state: 4 | delay: '+30' 5 | mode: poweroff 6 | message: [Bye, Bye] 7 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source1-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | Blah: ['b'] 4 | 5 | merge_how: 'dict(recurse_array,no_replace)+list(append)' 6 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source3-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: ['blah2'] 3 | 4 | merge_how: 'dict(recurse_array,no_replace)+list(prepend)' 5 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source4-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | Blah: 3 | b: null 4 | 5 | 6 | merge_how: 'dict(allow_delete,no_replace)+list()' 7 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source9-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | phone_home: 4 | url: $BLAH_BLAH 5 | 6 | merge_how: 'dict(recurse_str)+str(append)' 7 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected6.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | run_cmds: 4 | - bash 5 | - top 6 | - ps 7 | - vi 8 | - emacs 9 | 10 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source5-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | Blah: 3 4 | Blah2: 2 5 | Blah3: [1] 6 | 7 | 8 | merge_how: 'dict(replace)+list(append)' 9 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | formats: all 4 | 5 | python: 6 | install: 7 | - requirements: doc-requirements.txt 8 | - path: . 9 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/maas.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_maas: 2 | 3 | MAAS 4 | ==== 5 | 6 | *TODO* 7 | 8 | For now see: https://maas.io/docs 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected10.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | power_state: 4 | delay: '+30' 5 | mode: poweroff 6 | message: [Bye, Bye, Pew, Pew] 7 | 8 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source10-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | power_state: 4 | message: [Pew, Pew] 5 | 6 | merge_how: 'dict(recurse_list)+list(append)' 7 | -------------------------------------------------------------------------------- /tests/integration_tests/assets/test_version_change.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puppetlabs/cloud-init/main/tests/integration_tests/assets/test_version_change.pkl -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | # Needed generally in tests 2 | httpretty>=0.7.1 3 | pytest 4 | pytest-cov 5 | 6 | # Only really needed on older versions of python 7 | setuptools 8 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source6-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | run_cmds: 4 | - ps 5 | - vi 6 | - emacs 7 | 8 | merge_type: 'list(append)+dict(recurse_array)+str()' 9 | -------------------------------------------------------------------------------- /tests/data/old_pickles/focal-20.1-10-g71af48df-0ubuntu5.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puppetlabs/cloud-init/main/tests/data/old_pickles/focal-20.1-10-g71af48df-0ubuntu5.pkl -------------------------------------------------------------------------------- /doc/examples/user-script.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat < Fri, 16 Dec 2011 11:50:25 -0500 7 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/lp1611074.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # LP Bug 1611074: Reformatting of ephemeral drive fails on resize of Azure VM 3 | # 4 | # 2016-11-18: Disabled until test written 5 | # 6 | enabled: False 7 | 8 | # vi: ts=4 expandtab 9 | -------------------------------------------------------------------------------- /tests/data/merge_sources/expected8.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | mounts: 4 | - [ ephemeral22, /mnt, auto, "defaults,noexec" ] 5 | - [ sdc, /opt/data ] 6 | - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] 7 | - [ dd, /dev/zero ] 8 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source8-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | mounts: 4 | - [ ephemeral0, /mnt, auto, "defaults,noexec" ] 5 | - [ sdc, /opt/data ] 6 | - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] 7 | - [ dd, /dev/zero ] 8 | -------------------------------------------------------------------------------- /cloudinit/distros/centos.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.distros import rhel 4 | 5 | 6 | class Distro(rhel.Distro): 7 | pass 8 | 9 | # vi: ts=4 expandtab 10 | -------------------------------------------------------------------------------- /cloudinit/distros/rocky.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.distros import rhel 4 | 5 | 6 | class Distro(rhel.Distro): 7 | pass 8 | 9 | # vi: ts=4 expandtab 10 | -------------------------------------------------------------------------------- /cloudinit/distros/almalinux.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.distros import rhel 4 | 5 | 6 | class Distro(rhel.Distro): 7 | pass 8 | 9 | # vi: ts=4 expandtab 10 | -------------------------------------------------------------------------------- /cloudinit/distros/eurolinux.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.distros import rhel 4 | 5 | 6 | class Distro(rhel.Distro): 7 | pass 8 | 9 | # vi: ts=4 expandtab 10 | -------------------------------------------------------------------------------- /cloudinit/distros/virtuozzo.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.distros import rhel 4 | 5 | 6 | class Distro(rhel.Distro): 7 | pass 8 | 9 | # vi: ts=4 expandtab 10 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-iproute-output-v4: -------------------------------------------------------------------------------- 1 | default via 192.168.2.1 dev enp0s25 proto static metric 100 2 | default via 192.168.2.1 dev wlp3s0 proto static metric 150 3 | 192.168.2.0/24 dev enp0s25 proto kernel scope link src 192.168.2.18 metric 100 4 | -------------------------------------------------------------------------------- /sysvinit/gentoo/cloud-init-local: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | depend() { 4 | after localmount 5 | before net 6 | before cloud-init 7 | provide cloud-init-local 8 | } 9 | 10 | start() { 11 | cloud-init init --local 12 | eend 0 13 | } 14 | -------------------------------------------------------------------------------- /templates/timesyncd.conf.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # cloud-init generated file 3 | # See timesyncd.conf(5) for details. 4 | 5 | [Time] 6 | {% if servers or pools -%} 7 | NTP={% for host in servers|list + pools|list %}{{ host }} {% endfor -%} 8 | {% endif -%} 9 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """Test verifiers for cloud-init bugs. 4 | 5 | See configs/bugs/README.md for more information 6 | """ 7 | 8 | # vi: ts=4 expandtab 9 | -------------------------------------------------------------------------------- /tests/data/filter_cloud_multipart_1.email: -------------------------------------------------------------------------------- 1 | From nobody Fri Aug 31 17:17:00 2012 2 | Content-Type: text/plain; charset="us-ascii" 3 | MIME-Version: 1.0 4 | Content-Transfer-Encoding: 7bit 5 | 6 | 7 | #cloud-config 8 | b: c 9 | launch-index: 2 10 | 11 | 12 | -------------------------------------------------------------------------------- /sysvinit/gentoo/cloud-config: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | depend() { 4 | after cloud-init-local 5 | after cloud-init 6 | before cloud-final 7 | provide cloud-config 8 | } 9 | 10 | start() { 11 | cloud-init modules --mode config 12 | eend 0 13 | } 14 | -------------------------------------------------------------------------------- /tests/data/filter_cloud_multipart_header.email: -------------------------------------------------------------------------------- 1 | From nobody Fri Aug 31 17:17:00 2012 2 | Content-Type: text/plain; charset="us-ascii" 3 | MIME-Version: 1.0 4 | Launch-Index: 5 5 | Content-Transfer-Encoding: 7bit 6 | 7 | 8 | #cloud-config 9 | b: c 10 | 11 | 12 | -------------------------------------------------------------------------------- /upstart/cloud-init.conf: -------------------------------------------------------------------------------- 1 | # cloud-init - the initial cloud-init job 2 | # crawls metadata service, emits cloud-config 3 | start on mounted MOUNTPOINT=/ and stopped cloud-init-nonet 4 | 5 | task 6 | 7 | console output 8 | 9 | exec /usr/bin/cloud-init init 10 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/main/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """Test verifiers for cloud-init main features. 4 | 5 | See configs/main/README.md for more information 6 | """ 7 | 8 | # vi: ts=4 expandtab 9 | -------------------------------------------------------------------------------- /doc/examples/include.txt: -------------------------------------------------------------------------------- 1 | #include 2 | # entries are one url per line. comment lines beginning with '#' are allowed 3 | # urls are passed to urllib.urlopen, so the format must be supported there 4 | http://www.ubuntu.com/robots.txt 5 | http://www.w3schools.com/html/lastpage.htm 6 | -------------------------------------------------------------------------------- /doc/examples/upstart-cloud-config.txt: -------------------------------------------------------------------------------- 1 | #upstart-job 2 | description "My test job" 3 | 4 | start on cloud-config 5 | console output 6 | task 7 | 8 | script 9 | echo "====BEGIN=======" 10 | echo "HELLO WORLD: $UPSTART_JOB" 11 | echo "=====END========" 12 | end script 13 | -------------------------------------------------------------------------------- /sysvinit/gentoo/cloud-init: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # add depends for network, dns, fs etc 3 | depend() { 4 | after cloud-init-local 5 | after net 6 | before cloud-config 7 | provide cloud-init 8 | } 9 | 10 | start() { 11 | cloud-init init 12 | eend 0 13 | } 14 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """Test verifiers for cloud-init examples. 4 | 5 | See configs/examples/README.md for more information 6 | """ 7 | 8 | # vi: ts=4 expandtab 9 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """Test verifiers for cloud-init cc modules. 4 | 5 | See configs/modules/README.md for more information 6 | """ 7 | 8 | # vi: ts=4 expandtab 9 | -------------------------------------------------------------------------------- /templates/ntp.conf.alpine.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # /etc/ntp.conf 3 | # 4 | # Configuration for Busybox ntpd - it only supports "server" lines. 5 | 6 | {% if servers %}# Servers 7 | {% endif %} 8 | {% for server in servers -%} 9 | server {{server}} 10 | {% endfor %} 11 | -------------------------------------------------------------------------------- /integration-requirements.txt: -------------------------------------------------------------------------------- 1 | # PyPI requirements for cloud-init integration testing 2 | # https://cloudinit.readthedocs.io/en/latest/topics/integration_tests.html 3 | # 4 | pycloudlib @ git+https://github.com/canonical/pycloudlib.git@245ca0b97e71926fdb651147e42d6256b17f6778 5 | pytest 6 | -------------------------------------------------------------------------------- /tests/data/zpool_status_simple.txt: -------------------------------------------------------------------------------- 1 | pool: vmzroot 2 | state: ONLINE 3 | scan: none requested 4 | config: 5 | 6 | NAME STATE READ WRITE CKSUM 7 | vmzroot ONLINE 0 0 0 8 | gpt/system ONLINE 0 0 0 9 | 10 | errors: No known data errors -------------------------------------------------------------------------------- /tools/21-cloudinit.conf: -------------------------------------------------------------------------------- 1 | # Log cloudinit generated log messages to file 2 | :syslogtag, isequal, "[CLOUDINIT]" /var/log/cloud-init.log 3 | 4 | # comment out the following line to allow CLOUDINIT messages through. 5 | # Doing so means you'll also get CLOUDINIT messages in /var/log/syslog 6 | & stop 7 | -------------------------------------------------------------------------------- /tests/data/azure/non_unicode_random_string: -------------------------------------------------------------------------------- 1 | OEM0d\x00\x00\x00\x01\x80VRTUALMICROSFT\x02\x17\x00\x06MSFT\x97\x00\x00\x00C\xb4{V\xf4X%\x061x\x90\x1c\xfen\x86\xbf~\xf5\x8c\x94&\x88\xed\x84\xf9B\xbd\xd3\xf1\xdb\xee:\xd9\x0fc\x0e\x83(\xbd\xe3'\xfc\x85,\xdf\xf4\x13\x99N\xc5\xf3Y\x1e\xe3\x0b\xa4H\x08J\xb9\xdcdb$ -------------------------------------------------------------------------------- /upstart/cloud-config.conf: -------------------------------------------------------------------------------- 1 | # cloud-config - Handle applying the settings specified in cloud-config 2 | description "Handle applying cloud-config" 3 | emits cloud-config 4 | 5 | start on (filesystem and started rsyslog) 6 | console output 7 | task 8 | 9 | exec cloud-init modules --mode=config 10 | -------------------------------------------------------------------------------- /doc/examples/upstart-rclocal.txt: -------------------------------------------------------------------------------- 1 | #upstart-job 2 | description "a test upstart job" 3 | 4 | start on stopped rc RUNLEVEL=[2345] 5 | console output 6 | task 7 | 8 | script 9 | echo "====BEGIN=======" 10 | echo "HELLO RC.LOCAL LIKE WORLD: $UPSTART_JOB" 11 | echo "=====END========" 12 | end script 13 | -------------------------------------------------------------------------------- /systemd/cloud-init.target: -------------------------------------------------------------------------------- 1 | # cloud-init target is enabled by cloud-init-generator 2 | # To disable it you can either: 3 | # a.) boot with kernel cmdline of 'cloud-init=disabled' 4 | # b.) touch a file /etc/cloud/cloud-init.disabled 5 | [Unit] 6 | Description=Cloud-init target 7 | After=multi-user.target 8 | -------------------------------------------------------------------------------- /udev/10-cloud-init-hook-hotplug.rules: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | # Handle device adds only 3 | ACTION!="add|remove", GOTO="cloudinit_end" 4 | LABEL="cloudinit_hook" 5 | SUBSYSTEM=="net|block", RUN+="/usr/lib/cloud-init/hook-hotplug" 6 | LABEL="cloudinit_end" 7 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-final-message.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # final_message 4 | # default: cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds 5 | # this message is written by cloud-final when the system is finished 6 | # its first boot 7 | final_message: "The system is finally up, after $UPTIME seconds" 8 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-update-apt.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # Update apt database on first boot (run 'apt-get update'). 3 | # Note, if packages are given, or package_upgrade is true, then 4 | # update will be done independent of this setting. 5 | # 6 | # Default: false 7 | # Aliases: apt_update 8 | package_update: true 9 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/run_apt_upgrade.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | package_upgrade: true 10 | 11 | # vi: ts=4 expandtab 12 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/bootcmd.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Early boot command 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | bootcmd: 7 | - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts 8 | collect_scripts: 9 | hosts: | 10 | #!/bin/bash 11 | cat /etc/hosts 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/runcmd.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Run a simple command 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | runcmd: 7 | - echo cloud-init run cmd test > /var/tmp/run_cmd 8 | collect_scripts: 9 | run_cmd: | 10 | #!/bin/bash 11 | cat /var/tmp/run_cmd 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/e24cloud.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_e24cloud: 2 | 3 | E24Cloud 4 | ======== 5 | `E24Cloud ` platform provides an AWS Ec2 metadata 6 | service clone. It identifies itself to guests using the dmi 7 | system-manufacturer (/sys/class/dmi/id/sys_vendor). 8 | 9 | .. vi: textwidth=78 10 | -------------------------------------------------------------------------------- /sysvinit/netbsd/cloudinit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudinit 4 | # REQUIRE: cloudinitlocal 5 | 6 | $_rc_subr_loaded . /etc/rc.subr 7 | 8 | name="cloudinit" 9 | start_cmd="start_cloud_init" 10 | start_cloud_init() 11 | { 12 | /usr/pkg/bin/cloud-init init 13 | } 14 | 15 | load_rc_config $name 16 | run_rc_command "$1" 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/final_message.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Print a final message with various predefined variables 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | final_message: | 7 | This is my final message! 8 | $version 9 | $timestamp 10 | $datasource 11 | $uptime 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /cloudinit/distros/dragonflybsd.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020-2021 Gonéri Le Bouder 2 | # 3 | # This file is part of cloud-init. See LICENSE file for license information. 4 | 5 | import cloudinit.distros.freebsd 6 | 7 | 8 | class Distro(cloudinit.distros.freebsd.Distro): 9 | home_dir = '/home' 10 | 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /cloudinit/distros/sles.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 SUSE LLC 2 | # 3 | # Author: Robert Schweikert 4 | # 5 | # This file is part of cloud-init. See LICENSE file for license information. 6 | 7 | from cloudinit.distros import opensuse 8 | 9 | 10 | class Distro(opensuse.Distro): 11 | pass 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-archive.txt: -------------------------------------------------------------------------------- 1 | #cloud-config-archive 2 | - type: foo/wark 3 | filename: bar 4 | content: | 5 | This is my payload 6 | hello 7 | - this is also payload 8 | - | 9 | multi line payload 10 | here 11 | - 12 | type: text/upstart-job 13 | filename: my-upstart.conf 14 | content: | 15 | whats this, yo? 16 | 17 | -------------------------------------------------------------------------------- /sysvinit/netbsd/cloudfinal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudfinal 4 | # REQUIRE: LOGIN cloudconfig 5 | 6 | $_rc_subr_loaded . /etc/rc.subr 7 | 8 | name="cloudinit" 9 | start_cmd="start_cloud_init" 10 | start_cloud_init() 11 | { 12 | /usr/pkg/bin/cloud-init modules --mode final 13 | } 14 | 15 | load_rc_config $name 16 | run_rc_command "$1" 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Disable fingerprint printing 3 | # 4 | required_features: 5 | - syslog 6 | cloud_config: | 7 | #cloud-config 8 | no_ssh_fingerprints: true 9 | collect_scripts: 10 | syslog: | 11 | #!/bin/bash 12 | cat /var/log/syslog 13 | 14 | # vi: ts=4 expandtab 15 | -------------------------------------------------------------------------------- /tools/run-pyflakes: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CR=" 4 | " 5 | pycheck_dirs=( "cloudinit/" "tests/" "tools/" ) 6 | 7 | set -f 8 | if [ $# -eq 0 ]; then 9 | files=( "${pycheck_dirs[@]}" ) 10 | else 11 | files=( "$@" ) 12 | fi 13 | 14 | cmd=( "python3" -m "pyflakes" "${files[@]}" ) 15 | 16 | echo "Running: " "${cmd[@]}" 1>&2 17 | exec "${cmd[@]}" 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/lp1511485.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # LP Bug 1511485: final_message is silent on ubuntu-12.04.5 / cloud-init 0.6.3 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | final_message: "Final message from cloud-config" 10 | 11 | # vi: ts=4 expandtab 12 | -------------------------------------------------------------------------------- /upstart/cloud-final.conf: -------------------------------------------------------------------------------- 1 | # cloud-final.conf - run "final" jobs 2 | # this runs around traditional "rc.local" time. 3 | # and after all cloud-config jobs are run 4 | description "execute cloud user/final scripts" 5 | 6 | start on (stopped rc RUNLEVEL=[2345] and stopped cloud-config) 7 | console output 8 | task 9 | 10 | exec cloud-init modules --mode=final 11 | -------------------------------------------------------------------------------- /sysvinit/netbsd/cloudconfig: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudconfig 4 | # REQUIRE: cloudinit 5 | # BEFORE: sshd 6 | 7 | $_rc_subr_loaded . /etc/rc.subr 8 | 9 | name="cloudinit" 10 | start_cmd="start_cloud_init" 11 | start_cloud_init() 12 | { 13 | /usr/pkg/bin/cloud-init modules --mode config 14 | } 15 | 16 | load_rc_config $name 17 | run_rc_command "$1" 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_pipelining_disable.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Disable apt pipelining value 3 | # 4 | required_features: 5 | - apt 6 | cloud_config: | 7 | #cloud-config 8 | apt_pipelining: false 9 | collect_scripts: 10 | 90cloud-init-pipelining: | 11 | #!/bin/bash 12 | cat /etc/apt/apt.conf.d/90cloud-init-pipelining 13 | 14 | # vi: ts=4 expandtab 15 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/seed_random_data.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Push in random raw string to set as seed 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | random_seed: 7 | data: 'MYUb34023nD:LFDK10913jk;dfnk:Df' 8 | encoding: raw 9 | file: /root/seed 10 | collect_scripts: 11 | seed_data: | 12 | #!/bin/bash 13 | cat /root/seed 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/test_sles.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.tests.helpers import CiTestCase 4 | 5 | from . import _get_distro 6 | 7 | 8 | class TestSLES(CiTestCase): 9 | 10 | def test_get_distro(self): 11 | distro = _get_distro("sles") 12 | self.assertEqual(distro.osfamily, 'suse') 13 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/lxd_dir.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # LXD configured with directory backend 3 | # 4 | required_features: 5 | - lxd 6 | cloud_config: | 7 | #cloud-config 8 | lxd: 9 | init: 10 | storage_backend: dir 11 | collect_scripts: 12 | lxc: | 13 | #!/bin/bash 14 | which lxc 15 | lxd: | 16 | #!/bin/bash 17 | which lxd 18 | 19 | # vi: ts=4 expandtab 20 | -------------------------------------------------------------------------------- /doc/examples/include-once.txt: -------------------------------------------------------------------------------- 1 | #include-once 2 | # entries are one url per line. comment lines beginning with '#' are allowed 3 | # urls are passed to urllib.urlopen, so the format must be supported there 4 | # This entries will just be processed ONE TIME by cloud-init, any further 5 | # iterations won't process this file 6 | http://www.ubuntu.com/robots.txt 7 | http://www.w3schools.com/html/lastpage.htm 8 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-route-output-v4: -------------------------------------------------------------------------------- 1 | Kernel IP routing table 2 | Destination Gateway Genmask Flags Metric Ref Use Iface 3 | 0.0.0.0 192.168.2.1 0.0.0.0 UG 100 0 0 enp0s25 4 | 0.0.0.0 192.168.2.1 0.0.0.0 UG 150 0 0 wlp3s0 5 | 192.168.2.0 0.0.0.0 255.255.255.0 U 100 0 0 enp0s25 6 | -------------------------------------------------------------------------------- /tests/unittests/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | try: 4 | # For test cases, avoid the following UserWarning to stderr: 5 | # You don't have the C version of NameMapper installed ... 6 | from Cheetah import NameMapper as _nm 7 | _nm.C_VERSION = True 8 | except ImportError: 9 | pass 10 | 11 | # vi: ts=4 expandtab 12 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_pipelining_os.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set apt pipelining value to OS, no conf written 3 | # 4 | required_features: 5 | - apt 6 | cloud_config: | 7 | #cloud-config 8 | apt_pipelining: os 9 | collect_scripts: 10 | 90cloud-init-pipelining_not_written: | 11 | #!/bin/bash 12 | ls /etc/apt/apt.conf.d/90cloud-init-pipelining | wc -l 13 | 14 | # vi: ts=4 expandtab 15 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/test_opensuse.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit.tests.helpers import CiTestCase 4 | 5 | from . import _get_distro 6 | 7 | 8 | class TestopenSUSE(CiTestCase): 9 | 10 | def test_get_distro(self): 11 | distro = _get_distro("opensuse") 12 | self.assertEqual(distro.osfamily, 'suse') 13 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/config_source.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Canonical Ltd. 2 | # Copyright (C) 2015 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | 9 | class ConfigSource(object): 10 | """Specifies a source for the Config Content.""" 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_import_id.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Import a user's ssh key via gh or lp 3 | # 4 | required_features: 5 | - ubuntu_user 6 | - sudo 7 | cloud_config: | 8 | #cloud-config 9 | ssh_import_id: 10 | - gh:powersj 11 | - lp:smoser 12 | collect_scripts: 13 | auth_keys_ubuntu: | 14 | #!/bin/bash 15 | cat /home/ubuntu/.ssh/authorized_keys 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /tests/data/azure/pubkey_extract_ssh_key: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHU9IDclbKVYVbYuv0+zViX+wTwlKspslmy/uf3hkWLh7pyzyrq70S7qtSW2EGixUPxZS/R8pOLHoinlKF9ILgj0gVTCJsSwnWpXRg3rhZwIVoYMHN50BHS1SqVD0lsWNMXmo76LoJcjmWvwIznvj5C/gnhU+K7+c3m7AlCyU2wjwpBAEYj7PQs6l/wTqpEiaqC5NytNBd7qp+lYYysVrpa1PFL0Nj4MMZARIfjkiJtL9qDhy9YZeJRQ6q/Fhz0kjvkZnfxixfKF4yWzOfhBrAtpF6oOnuYKk3hxjh9KjTTX4/U8zdLojalX09iyHyEjwJKGlGEpzh1aY7t5btUyvp 2 | -------------------------------------------------------------------------------- /tests/data/user_data.1.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | write_files: 3 | - content: blah 4 | path: /etc/blah.ini 5 | permissions: 493 6 | 7 | system_info: 8 | package_mirrors: 9 | - arches: [i386, amd64, blah] 10 | failsafe: 11 | primary: http://my.archive.mydomain.com/ubuntu 12 | security: http://my.security.mydomain.com/ubuntu 13 | search: 14 | primary: [] 15 | security: [] 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/main/README.md: -------------------------------------------------------------------------------- 1 | # Main Functionality Test Configs 2 | 3 | ## purpose 4 | Test main features and config options of cloud-init such as logging, output 5 | redirection, early init and integration with init system 6 | 7 | ## structure 8 | Should have one or more test configs for all main cloud-init output and logging 9 | options, and basic functionality test cases 10 | 11 | # vi: ts=4 expandtab 12 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/alter_completion_message.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | final_message: | 10 | This is my final message! 11 | $version 12 | $timestamp 13 | $datasource 14 | $uptime 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_security.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Add security to sources.list 3 | # 4 | required_features: 5 | - apt 6 | - ubuntu_repos 7 | cloud_config: | 8 | #cloud-config 9 | apt: 10 | security: 11 | - arches: 12 | - default 13 | collect_scripts: 14 | sources.list: | 15 | #!/bin/bash 16 | grep -c security.ubuntu.com /etc/apt/sources.list 17 | 18 | # vi: ts=4 expandtab 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/run_commands.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | runcmd: 10 | - echo cloud-init run cmd test > /var/tmp/run_cmd 11 | collect_scripts: 12 | run_cmd: | 13 | #!/bin/bash 14 | cat /var/tmp/run_cmd 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.py MANIFEST.in LICENSE* ChangeLog 2 | global-include *.txt *.rst *.ini *.in *.conf *.cfg *.sh 3 | graft bash_completion 4 | graft config 5 | graft doc 6 | graft packages 7 | graft systemd 8 | graft sysvinit 9 | graft templates 10 | graft tests 11 | graft tools 12 | graft udev 13 | graft upstart 14 | prune build 15 | prune dist 16 | prune .tox 17 | prune .git 18 | prune .bzr 19 | exclude .gitignore 20 | exclude .bzrignore 21 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/README.md: -------------------------------------------------------------------------------- 1 | # Module Test Configs 2 | 3 | ## Purpose 4 | Test functionality of cloud config modules. See 5 | [here](https://cloudinit.readthedocs.io/en/latest/topics/modules.html) for 6 | a full list. 7 | 8 | ## Structure 9 | Should have one or more test configs for each module in cloudinit/config/. The 10 | name of the test should indicate which module the config is verifying. 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_timesyncd.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # ntp enabled, systemd-timesyncd selected, check conf file 3 | # as systemd-timesyncd won't start in a container 4 | # 5 | cloud_config: | 6 | #cloud-config 7 | ntp: 8 | enabled: true 9 | ntp_client: systemd-timesyncd 10 | collect_scripts: 11 | timesyncd_conf: | 12 | #!/bin/sh 13 | cat /etc/systemd/timesyncd.conf.d/cloud-init.conf 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password_list.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestPasswordList(base.PasswordListTest, base.CloudTestCase): 8 | """Test password setting via list in chpasswd/list.""" 9 | 10 | __test__ = True 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/boot_proto.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Canonical Ltd. 2 | # Copyright (C) 2015 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | 9 | class BootProtoEnum(object): 10 | """Specifies the NIC Boot Settings.""" 11 | 12 | DHCP = 'dhcp' 13 | STATIC = 'static' 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/run_commands_first_boot.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | bootcmd: 10 | - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts 11 | collect_scripts: 12 | hosts: | 13 | #!/bin/bash 14 | cat /etc/hosts 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/config_namespace.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Canonical Ltd. 2 | # Copyright (C) 2015 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | from .config_source import ConfigSource 9 | 10 | 11 | class ConfigNamespace(ConfigSource): 12 | """Specifies the Config Namespace.""" 13 | 14 | # vi: ts=4 expandtab 15 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/byobu.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Install and enable byobu system wide and default user 3 | # 4 | required_features: 5 | - byobu 6 | cloud_config: | 7 | #cloud-config 8 | byobu_by_default: enable 9 | collect_scripts: 10 | byobu_profile_enabled: | 11 | #!/bin/bash 12 | ls /etc/profile.d/Z97-byobu.sh 13 | byobu_launch_exists: | 14 | #!/bin/bash 15 | which /usr/bin/byobu-launch 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_hostname.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set the hostname and update /etc/hosts 3 | # 4 | required_features: 5 | - hostname 6 | cloud_config: | 7 | #cloud-config 8 | hostname: cloudinit2 9 | 10 | collect_scripts: 11 | hosts: | 12 | #!/bin/bash 13 | grep ^127 /etc/hosts 14 | hostname: | 15 | #!/bin/bash 16 | hostname 17 | fqdn: | 18 | #!/bin/bash 19 | hostname --fqdn 20 | 21 | # vi: ts=4 expandtab 22 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password_list_string.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestPasswordListString(base.PasswordListTest, base.CloudTestCase): 8 | """Test password setting via string in chpasswd/list.""" 9 | 10 | __test__ = True 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-phone-home.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # phone_home: if this dictionary is present, then the phone_home 4 | # cloud-config module will post specified data back to the given 5 | # url 6 | # default: none 7 | # phone_home: 8 | # url: http://my.foo.bar/$INSTANCE/ 9 | # post: all 10 | # tries: 10 11 | # 12 | phone_home: 13 | url: http://my.example.com/$INSTANCE_ID/ 14 | post: [ pub_key_dsa, pub_key_rsa, pub_key_ecdsa, instance_id ] 15 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/main/command_output_simple.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Test functionality of simple output redirection 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | output: { all: "| tee -a /var/log/cloud-init-test-output" } 7 | final_message: "should be last line in cloud-init-test-output file" 8 | collect_scripts: 9 | cloud-init-test-output: | 10 | #!/bin/bash 11 | cat /var/log/cloud-init-test-output 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/keys_to_console.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Hide printing of ssh key and fingerprints for specific keys 3 | # 4 | required_features: 5 | - syslog 6 | cloud_config: | 7 | #cloud-config 8 | ssh_fp_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] 9 | ssh_key_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] 10 | collect_scripts: 11 | syslog: | 12 | #!/bin/bash 13 | cat /var/log/syslog 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set password of default user 3 | # 4 | required_features: 5 | - ubuntu_user 6 | cloud_config: | 7 | #cloud-config 8 | password: password 9 | chpasswd: { expire: False } 10 | ssh_pwauth: True 11 | collect_scripts: 12 | shadow: | 13 | #!/bin/bash 14 | cat /etc/shadow 15 | sshd_config: | 16 | #!/bin/bash 17 | grep '^PasswordAuth' /etc/ssh/sshd_config 18 | 19 | # vi: ts=4 expandtab 20 | -------------------------------------------------------------------------------- /upstart/cloud-init-local.conf: -------------------------------------------------------------------------------- 1 | # cloud-init - the initial cloud-init job 2 | # crawls metadata service, emits cloud-config 3 | start on mounted MOUNTPOINT=/ and mounted MOUNTPOINT=/run 4 | 5 | task 6 | 7 | console output 8 | 9 | script 10 | lfin=/run/cloud-init/local-finished 11 | ret=0 12 | cloud-init init --local || ret=$? 13 | [ -r /proc/uptime ] && read up idle < /proc/uptime || up="N/A" 14 | echo "$ret up $up" > "$lfin" 15 | exit $ret 16 | end script 17 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-install-packages.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # Install additional packages on first boot 4 | # 5 | # Default: none 6 | # 7 | # if packages are specified, this apt_update will be set to true 8 | # 9 | # packages may be supplied as a single package name or as a list 10 | # with the format [, ] wherein the specifc 11 | # package version will be installed. 12 | packages: 13 | - pwgen 14 | - pastebinit 15 | - [libpython2.7, 2.7.3-0ubuntu3.1] 16 | -------------------------------------------------------------------------------- /systemd/cloud-init-hotplugd.socket: -------------------------------------------------------------------------------- 1 | # cloud-init-hotplugd.socket listens on the FIFO file 2 | # /run/cloud-init/hook-hotplug-cmd which is created during a udev network 3 | # add or remove event as processed by 10-cloud-init-hook-hotplug.rules. 4 | 5 | # Known bug with an enforcing SELinux policy: LP: #1936229 6 | [Unit] 7 | Description=cloud-init hotplug hook socket 8 | 9 | [Socket] 10 | ListenFIFO=/run/cloud-init/hook-hotplug-cmd 11 | 12 | [Install] 13 | WantedBy=cloud-init.target 14 | -------------------------------------------------------------------------------- /sysvinit/netbsd/cloudinitlocal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudinitlocal 4 | # REQUIRE: NETWORKING 5 | 6 | # After NETWORKING because we don't want staticroute to wipe 7 | # the route set by the DHCP client toward the meta-data server. 8 | $_rc_subr_loaded . /etc/rc.subr 9 | 10 | name="cloudinitlocal" 11 | start_cmd="start_cloud_init_local" 12 | start_cloud_init_local() 13 | { 14 | /usr/pkg/bin/cloud-init init -l 15 | } 16 | 17 | load_rc_config $name 18 | run_rc_command "$1" 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_chrony.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # ntp enabled, chrony selected, check conf file 3 | # as chrony won't start in a container 4 | # 5 | cloud_config: | 6 | #cloud-config 7 | ntp: 8 | enabled: true 9 | ntp_client: chrony 10 | collect_scripts: 11 | chrony_conf: | 12 | #!/bin/sh 13 | set -- /etc/chrony.conf /etc/chrony/chrony.conf 14 | for p in "$@"; do 15 | [ -e "$p" ] && { cat "$p"; exit; } 16 | done 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/seed_random_command.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Use uuid to create a random string 3 | # 4 | # 2016-11-15 Disabled as this is not working currently 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | random_seed: 10 | command: ["cat", "/proc/sys/kernel/random/uuid"] 11 | command_required: true 12 | file: /root/seed 13 | collect_scripts: 14 | seed_data: | 15 | #!/bin/bash 16 | cat /root/seed 17 | 18 | # vi: ts=4 expandtab 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/timezone.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set system timezone 3 | # 4 | required_features: 5 | - daylight_time 6 | cloud_config: | 7 | #cloud-config 8 | timezone: US/Aleutian 9 | collect_scripts: 10 | timezone: | 11 | #!/bin/bash 12 | # date will convert this to system's configured time zone. 13 | # use a static date to avoid dealing with daylight savings. 14 | date "+%Z" --date="Thu, 03 Nov 2016 00:47:00 -0400" 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/README.md: -------------------------------------------------------------------------------- 1 | # Example Test Configs 2 | 3 | ## Purpose 4 | This folder contains example cloud configs found on 5 | [cloudinit.readthedocs.io](https://cloudinit.readthedocs.io/en/latest/topics/examples.html). 6 | Examples covered by other tests, like modules, are excluded from tests here 7 | to prevent duplication and reduce test time. 8 | 9 | ## Structure 10 | One test per example test config on cloudinit.readthedocs.io 11 | 12 | # vi: ts=4 expandtab 13 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_primary.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Setup a custome primary sources.list 3 | # 4 | required_features: 5 | - apt 6 | - apt_src_cont 7 | cloud_config: | 8 | #cloud-config 9 | apt: 10 | primary: 11 | - arches: 12 | - default 13 | uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/" 14 | collect_scripts: 15 | sources.list: | 16 | #!/bin/bash 17 | cat /etc/apt/sources.list 18 | 19 | # vi: ts=4 expandtab 20 | -------------------------------------------------------------------------------- /tests/integration_tests/__init__.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def random_mac_address() -> str: 5 | """Generate a random MAC address. 6 | 7 | The MAC address will have a 1 in its least significant bit, indicating it 8 | to be a locally administered address. 9 | """ 10 | return "02:00:00:%02x:%02x:%02x" % (random.randint(0, 255), 11 | random.randint(0, 255), 12 | random.randint(0, 255)) 13 | -------------------------------------------------------------------------------- /tools/run-pep8: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pycheck_dirs=( "cloudinit/" "tests/" "tools/" ) 4 | 5 | CR=" 6 | " 7 | [ "$1" = "-v" ] && { verbose="$1"; shift; } || verbose="" 8 | 9 | set -f 10 | if [ $# -eq 0 ]; then unset IFS 11 | IFS="$CR" 12 | files=( "${bin_files[@]}" "${pycheck_dirs[@]}" ) 13 | unset IFS 14 | else 15 | files=( "$@" ) 16 | fi 17 | 18 | myname=${0##*/} 19 | cmd=( "${myname#run-}" $verbose "${files[@]}" ) 20 | echo "Running: " "${cmd[@]}" 1>&2 21 | exec "${cmd[@]}" 22 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/guestcust_state.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Canonical Ltd. 2 | # Copyright (C) 2016 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | 9 | class GuestCustStateEnum(object): 10 | """Specifies different states of Guest Customization engine""" 11 | 12 | GUESTCUST_STATE_RUNNING = 4 13 | GUESTCUST_STATE_DONE = 5 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-reporting.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | ## 3 | ## The following sets up 2 reporting end points. 4 | ## A 'webhook' and a 'log' type. 5 | ## It also disables the built in default 'log' 6 | reporting: 7 | smtest: 8 | type: webhook 9 | endpoint: "http://myhost:8000/" 10 | consumer_key: "ckey_foo" 11 | consumer_secret: "csecret_foo" 12 | token_key: "tkey_foo" 13 | token_secret: "tkey_foo" 14 | smlogger: 15 | type: log 16 | level: WARN 17 | log: null 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/install_arbitrary_packages.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | cloud_config: | 8 | #cloud-config 9 | packages: 10 | - htop 11 | - tree 12 | collect_scripts: 13 | htop: | 14 | #!/bin/bash 15 | dpkg -l | grep htop | wc -l 16 | tree: | 17 | #!/bin/bash 18 | dpkg -l | grep tree | wc -l 19 | 20 | # vi: ts=4 expandtab 21 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_conf.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Provide a configuration for APT 3 | # 4 | required_features: 5 | - apt 6 | cloud_config: | 7 | #cloud-config 8 | apt: 9 | conf: | 10 | APT { 11 | Get { 12 | Assume-Yes "true"; 13 | Fix-Broken "true"; 14 | } 15 | } 16 | collect_scripts: 17 | 94cloud-init-config: | 18 | #!/bin/bash 19 | cat /etc/apt/apt.conf.d/94cloud-init-config 20 | 21 | # vi: ts=4 expandtab 22 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source7-2.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | users: 4 | - bob 5 | - joe 6 | - sue 7 | - name: foobar_jr 8 | gecos: Foo B. Bar Jr 9 | primary_group: foobar 10 | groups: users 11 | selinux_user: staff_u 12 | expiredate: '2012-09-01' 13 | ssh_import_id: foobar 14 | lock-passwd: false 15 | passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ 16 | 17 | merge_how: "dict(recurse_array)+list(append)" 18 | -------------------------------------------------------------------------------- /tools/pipremove: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | import sys 4 | 5 | for pkg in sys.argv[1:]: 6 | try: 7 | exec('import %s' % pkg) # pylint: disable=W0122 8 | except ImportError: 9 | continue 10 | sys.stderr.write("%s removing package %s\n" % (sys.argv[0], pkg)) 11 | ret = subprocess.Popen(['pip', 'uninstall', '--yes', pkg]).wait() 12 | if ret != 0: 13 | sys.stderr.write("Failed to uninstall %s (%d)\n" % (pkg, ret)) 14 | sys.exit(ret) 15 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_disable_suites.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Disables everything in sources.list 3 | # 4 | required_features: 5 | - apt 6 | - lsb_release 7 | cloud_config: | 8 | #cloud-config 9 | apt: 10 | disable_suites: 11 | - $RELEASE 12 | - $RELEASE-updates 13 | - $RELEASE-backports 14 | - $RELEASE-security 15 | collect_scripts: 16 | sources.list: | 17 | #!/bin/bash 18 | grep -v '^#' /etc/apt/sources.list | sed '/^\s*$/d' 19 | 20 | # vi: ts=4 expandtab 21 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_proxy.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set apt proxy 3 | # 4 | required_features: 5 | - apt 6 | cloud_config: | 7 | #cloud-config 8 | apt: 9 | proxy: "http://squid.internal:3128" 10 | http_proxy: "http://squid.internal:3128" 11 | ftp_proxy: "ftp://squid.internal:3128" 12 | https_proxy: "https://squid.internal:3128" 13 | collect_scripts: 14 | 90cloud-init-aptproxy: | 15 | #!/bin/bash 16 | cat /etc/apt/apt.conf.d/90cloud-init-aptproxy 17 | 18 | # vi: ts=4 expandtab 19 | -------------------------------------------------------------------------------- /doc/sources/ovf/user-data: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | password: passw0rd 3 | chpasswd: { expire: False } 4 | ssh_pwauth: True 5 | 6 | ssh_authorized_keys: 7 | - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVmr/XVGTL+4d1sol7CYS0MAEahKMgXKOhjThPl0VhQ3CLQHoqbtvzliWqaL/UqZHhm+L752PXRee6yhav9mu6/zmEeKUxn0ajMvZEPqNT8Joj6sFCQpJpH8J2YQcFtGKarpPYT1yEyEljSM3N57ElIpVHdB4t1tFnrgftAZMentSWh269L1XABZylhsaBwznjV9ugUCIk4sgIzVQ8fjHlYOROr/rJ4SVKZ6ITaUe0RIeHIwk5IMHdhnmHDX7htjexH7S9ndVBbOmfUvCDVfcBkDzJ/5myYxkeFMV4KCWx3yOUseRa52HmYkGQK7A+9FCTWATmBKdMa2LRNSosis1H ubuntu@ovfdemo 8 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/runcmd.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestRunCmd(base.CloudTestCase): 8 | """Test runcmd module.""" 9 | 10 | def test_run_cmd(self): 11 | """Test run command worked.""" 12 | out = self.get_data_file('run_cmd') 13 | self.assertIn('cloud-init run cmd test', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-ipaddrshow-output-down: -------------------------------------------------------------------------------- 1 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 2 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 3 | inet 127.0.0.1/8 scope host lo 4 | valid_lft forever preferred_lft forever 5 | inet6 ::1/128 scope host 6 | valid_lft forever preferred_lft forever 7 | 44: eth0@if45: mtu 1500 qdisc noqueue state DOWN group default qlen 1000 8 | link/ether 00:16:3e:de:51:a6 brd ff:ff:ff:ff:ff:ff link-netnsid 0 9 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/snap.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Install snappy 3 | # 4 | # Aug 23, 2018: Disabled due to requiring a proxy for testing 5 | # tests do not handle the proxy well at this time. 6 | enabled: False 7 | required_features: 8 | - snap 9 | cloud_config: | 10 | #cloud-config 11 | package_update: true 12 | snap: 13 | squashfuse_in_container: true 14 | commands: 15 | - snap install hello-world 16 | collect_scripts: 17 | snaplist: | 18 | #!/bin/bash 19 | snap list 20 | 21 | # vi: ts=4 expandtab 22 | -------------------------------------------------------------------------------- /systemd/cloud-config.service.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | [Unit] 3 | Description=Apply the settings specified in cloud-config 4 | After=network-online.target cloud-config.target 5 | After=snapd.seeded.service 6 | Wants=network-online.target cloud-config.target 7 | 8 | [Service] 9 | Type=oneshot 10 | ExecStart=/usr/bin/cloud-init modules --mode=config 11 | RemainAfterExit=yes 12 | TimeoutSec=0 13 | 14 | # Output needs to appear in instance console output 15 | StandardOutput=journal+console 16 | 17 | [Install] 18 | WantedBy=cloud-init.target 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/timezone.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestTimezone(base.CloudTestCase): 8 | """Test timezone module.""" 9 | 10 | def test_timezone(self): 11 | """Test date prints correct timezone.""" 12 | out = self.get_data_file('timezone') 13 | self.assertEqual('HDT', out.rstrip()) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /packages/debian/cloud-init.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cleanup_lp1552999() { 3 | local oldver="$1" last_bad_ver="0.7.7~bzr1178" 4 | dpkg --compare-versions "$oldver" le "$last_bad_ver" || return 0 5 | local edir="/etc/systemd/system/multi-user.target.wants" 6 | rm -f "$edir/cloud-config.service" "$edir/cloud-final.service" \ 7 | "$edir/cloud-init-local.service" "$edir/cloud-init.service" 8 | } 9 | 10 | 11 | #DEBHELPER# 12 | 13 | if [ "$1" = "configure" ]; then 14 | oldver="$2" 15 | cleanup_lp1552999 "$oldver" 16 | fi 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/run_commands.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestRunCmd(base.CloudTestCase): 8 | """Example cloud-config test.""" 9 | 10 | def test_run_cmd(self): 11 | """Test run command worked.""" 12 | out = self.get_data_file('run_cmd') 13 | self.assertIn('cloud-init run cmd test', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/bootcmd.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestBootCmd(base.CloudTestCase): 8 | """Test bootcmd module.""" 9 | 10 | def test_bootcmd_host(self): 11 | """Test boot cmd worked.""" 12 | out = self.get_data_file('hosts') 13 | self.assertIn('192.168.1.130 us.archive.ubuntu.com', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /cloudinit/distros/fedora.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Canonical Ltd. 2 | # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. 3 | # Copyright (C) 2012 Yahoo! Inc. 4 | # 5 | # Author: Scott Moser 6 | # Author: Juerg Haefliger 7 | # Author: Joshua Harlow 8 | # 9 | # This file is part of cloud-init. See LICENSE file for license information. 10 | 11 | from cloudinit.distros import rhel 12 | 13 | 14 | class Distro(rhel.Distro): 15 | pass 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/debug_enable.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestDebugEnable(base.CloudTestCase): 8 | """Test debug messages.""" 9 | 10 | def test_debug_enable(self): 11 | """Test debug messages in cloud-init log.""" 12 | out = self.get_data_file('cloud-init.log') 13 | self.assertIn('[DEBUG]', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/guestcust_error.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Canonical Ltd. 2 | # Copyright (C) 2016 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | 9 | class GuestCustErrorEnum(object): 10 | """Specifies different errors of Guest Customization engine""" 11 | 12 | GUESTCUST_ERROR_SUCCESS = 0 13 | GUESTCUST_ERROR_SCRIPT_DISABLED = 6 14 | GUESTCUST_ERROR_WRONG_META_FORMAT = 9 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/locale.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set locale to non-default option and verify 3 | # 4 | required_features: 5 | - engb_locale 6 | - locale_gen 7 | cloud_config: | 8 | #cloud-config 9 | locale: en_GB.UTF-8 10 | locale_configfile: /etc/default/locale 11 | collect_scripts: 12 | locale_default: | 13 | #!/bin/bash 14 | cat /etc/default/locale 15 | locale_a: | 16 | #!/bin/bash 17 | locale -a 18 | locale_gen: | 19 | #!/bin/bash 20 | cat /etc/locale.gen | grep -v '^#' | uniq 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/lp1511485.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestLP1511485(base.CloudTestCase): 8 | """Test LP# 1511485.""" 9 | 10 | def test_final_message(self): 11 | """Test final message exists.""" 12 | out = self.get_data_file('cloud-init-output.log') 13 | self.assertIn('Final message from cloud-config', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Emtpy NTP config to setup using defaults 3 | # 4 | cloud_config: | 5 | #cloud-config 6 | ntp: 7 | ntp_client: ntp 8 | pools: [] 9 | servers: [] 10 | collect_scripts: 11 | ntp_installed: | 12 | #!/bin/bash 13 | ntpd --version > /dev/null 2>&1 14 | echo $? 15 | ntp_conf_dist_empty: | 16 | #!/bin/bash 17 | ls /etc/ntp.conf.dist | wc -l 18 | ntp_conf_pool_list: | 19 | #!/bin/bash 20 | grep 'pool.ntp.org' /etc/ntp.conf | grep -v ^# 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-gluster.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # vim: syntax=yaml 3 | # Mounts volfile exported by glusterfsd running on 4 | # "volfile-server-hostname" onto the local mount point '/mnt/data' 5 | # 6 | # In reality, replace 'volfile-server-hostname' with one of your nodes 7 | # running glusterfsd. 8 | # 9 | packages: 10 | - glusterfs-client 11 | 12 | mounts: 13 | - [ 'volfile-server-hostname:6996', /mnt/data, glusterfs, "defaults,nofail", "0", "2" ] 14 | 15 | runcmd: 16 | - [ modprobe, fuse ] 17 | - [ mkdir, '-p', /mnt/data ] 18 | - [ mount, '-a' ] 19 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: cloud-init 2 | version: master 3 | summary: Init scripts for cloud instances 4 | description: | 5 | Cloud instances need special scripts to run during initialization to 6 | retrieve and install ssh keys and to let the user run various scripts. 7 | 8 | grade: stable 9 | confinement: classic 10 | 11 | apps: 12 | cloud-init: 13 | # LP: #1669306 14 | command: usr/bin/python3 $SNAP/bin/cloud-init 15 | 16 | parts: 17 | cloud-init: 18 | plugin: python 19 | source-type: git 20 | source: https://git.launchpad.net/cloud-init 21 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/run_commands_first_boot.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestBootCmd(base.CloudTestCase): 8 | """Example cloud-config test.""" 9 | 10 | def test_bootcmd_host(self): 11 | """Test boot command worked.""" 12 | out = self.get_data_file('hosts') 13 | self.assertIn('192.168.1.130 us.archive.ubuntu.com', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureDisableSuites(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_empty_sourcelist(self): 11 | """Test source list is empty.""" 12 | out = self.get_data_file('sources.list') 13 | self.assertEqual('', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_timesyncd.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestNtpTimesyncd(base.CloudTestCase): 8 | """Test ntp module with systemd-timesyncd client""" 9 | 10 | def test_timesyncd_entries(self): 11 | """Test timesyncd config entries""" 12 | out = self.get_data_file('timesyncd_conf') 13 | self.assertIn('.pool.ntp.org', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/seed_random_data.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestSeedRandom(base.CloudTestCase): 8 | """Test seed random module.""" 9 | 10 | def test_random_seed_data(self): 11 | """Test random data passed in exists.""" 12 | out = self.get_data_file('seed_data') 13 | self.assertIn('MYUb34023nD:LFDK10913jk;dfnk:Df', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_hostname_fqdn.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Set the hostname and update /etc/hosts 3 | # 4 | required_features: 5 | - hostname 6 | cloud_config: | 7 | #cloud-config 8 | manage_etc_hosts: true 9 | hostname: cloudinit1 10 | # this needs changing if CI_DOMAIN were updated. 11 | fqdn: cloudinit2.i9n.cloud-init.io 12 | collect_scripts: 13 | hosts: | 14 | #!/bin/bash 15 | grep ^127 /etc/hosts 16 | hostname: | 17 | #!/bin/bash 18 | hostname 19 | fqdn: | 20 | #!/bin/bash 21 | hostname --fqdn 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/snap.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestSnap(base.CloudTestCase): 8 | """Test snap module""" 9 | 10 | def test_snappy_version(self): 11 | """Expect hello-world and core snaps are installed.""" 12 | out = self.get_data_file('snaplist') 13 | self.assertIn('core', out) 14 | self.assertIn('hello-world', out) 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /templates/systemd.resolved.conf.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # Your system has been configured with 'manage-resolv-conf' set to true. 3 | # As a result, cloud-init has written this file with configuration data 4 | # that it has been provided. Cloud-init, by default, will write this file 5 | # a single time (PER_ONCE). 6 | # 7 | [Resolve] 8 | LLMNR=false 9 | {% if nameservers is defined %} 10 | DNS={% for server in nameservers %}{{server}} {% endfor %} 11 | {% endif %} 12 | 13 | {% if searchdomains is defined %} 14 | Domains={% for search in searchdomains %}{{search}} {% endfor %} 15 | {% endif %} 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_security.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureSecurity(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_security_mirror(self): 11 | """Test security lines added and uncommented in source.list.""" 12 | out = self.get_data_file('sources.list') 13 | self.assertEqual(6, int(out)) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_hostname.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestHostname(base.CloudTestCase): 8 | """Test hostname module.""" 9 | 10 | ex_hostname = "cloudinit2" 11 | 12 | def test_hostname(self): 13 | """Test hostname command shows correct output.""" 14 | out = self.get_data_file('hostname') 15 | self.assertIn(self.ex_hostname, out) 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /systemd/cloud-config.target: -------------------------------------------------------------------------------- 1 | # cloud-init normally emits a "cloud-config" upstart event to inform third 2 | # parties that cloud-config is available, which does us no good when we're 3 | # using systemd. cloud-config.target serves as this synchronization point 4 | # instead. Services that would "start on cloud-config" with upstart can 5 | # instead use "After=cloud-config.target" and "Wants=cloud-config.target" 6 | # as appropriate. 7 | 8 | [Unit] 9 | Description=Cloud-config availability 10 | Wants=cloud-init-local.service cloud-init.service 11 | After=cloud-init-local.service cloud-init.service 12 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/lp1628337.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # LP Bug 1628337: cloud-init tries to install NTP before even configuring the archives 3 | # 4 | required_features: 5 | - apt 6 | - lsb_release 7 | cloud_config: | 8 | #cloud-config 9 | ntp: 10 | servers: ['ntp.ubuntu.com'] 11 | apt: 12 | primary: 13 | - arches: [default] 14 | uri: http://us.archive.ubuntu.com/ubuntu/ 15 | collect_sciprts: 16 | ntp.conf: | 17 | #!/bin/bash 18 | cat /etc/ntp.conf 19 | sources.list: | 20 | #!/bin/bash 21 | cat /etc/apt/sources.list 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_pipelining_os.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptPipeliningOS(base.CloudTestCase): 8 | """Test apt-pipelining module.""" 9 | 10 | def test_os_pipelining(self): 11 | """test 'os' settings does not write apt config file.""" 12 | out = self.get_data_file('90cloud-init-pipelining_not_written') 13 | self.assertEqual(0, int(out)) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/integration_tests/assets/keys/id_rsa.test1.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1GUb3ponbdRG8CA79sGy4uX6Wq5zfnRpLBX3z+Ly+W86fkZVwfJ63+tdCDiVnizSjAbeRbJAVjye9OT4b5Q1Tx83RqcDMEOL7gzOx6OQX2xyNMwWZdWsikgKpXdthA2M+/qv65tB2QPTV27d4H23n/OXziC2yGnSEF2h/LPy7X8Dbmzt9VTrsbIjs90q9pL7K8lIidmdvZ71VDN8kL6oCc3uBRlq0EqN2BS0l6JRR4NpWdpLXtvRqhP2IE7SwhxC05MGViUKMW3VMAwtnrgePdJ8ZkHtiPRn4vMUHYhZfXPOyMjrxiRg8o5Iv81iFBT17nmQlDtaeeA0dj/af8Dt00pIUOaAzlz0haB5nt+Omx8hgCgn8IDEUg0P48Qd3WAJLrGgSFpRXKHlYf9eTAq/WfHgCJnYEUIT7vmTJJEtlQn7nLSvcNTmS0xd5RHNUg/um7RHwMK6X4ZT4z/5MfJa0AQ6B5o0np9imjaKkOFuZNi3eSTaUwhqlHEYEWz7fux0= test1@host 2 | -------------------------------------------------------------------------------- /tests/integration_tests/assets/keys/id_rsa.test2.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC8rnQPY9Y5ziKTIdVElLq0OGrOMvlwqKK8gPinVfwFgJXDzdcAQY4uci1TJVcc0AOWHp+lWrU1joDYlW3KCg8XpkXHymHshYyaeEN2fEsvIaxuF3UzW2JckP9H7dacYdEng8qtBq8wuCodGuJ5XdBVV+MVJ6jqNf/hOu4/pma8hMxlYmtdoamHEn+k/KQR2Q6LwCYpT0U2+KiPI9Lac22P0H/rfkh2Ba+t3tV/lhyzD0xHnktZKJ3BrznpEfrZiXoukQZMebWUmIyTW7zwk9Kq+iGFpSQsqQWlxDBwHSbvpbUo7KWUmyZfxs1euVmwj5aKJgjteXm9CbbXsMS415q+08C0MzG7weZODZQnnk1rF6Ft97aXHaTmRgYbDeLU7U5U3alnb84HvUu5xh3/mrE9rPTfCzBwY4lgY+Q1zjS90RL9Jxzti3weydm7OqTI6DOfQeJQLOhhRgthOkt/7IabDFLIARjTnpo5+QKxugoc4qI6aUnE1plkVCRfV696ngM= test2@host 2 | -------------------------------------------------------------------------------- /tests/integration_tests/assets/keys/id_rsa.test3.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCk8bgx2RhAoPnv+qt4WuH0ZELbbLrqpk5ZlZGMLzzuutu8HM7r2FXImlMheV4kS+laIdhyMxHkbo00Wyc21nh/EOqZJzi9wWPncmwT9c2osqrqmxdp0Jvm+Q2kZvED5nlsmXMn3r0+AkggRuBzzqx6LiSBHYy49aq1ltjkaSk0JOpa4th4Ur7XigWu4DafJYf0w4hEMcr93n3umwfL4tMy3KY7tk+E7nvVpsrDqO+/CJJ4PFUT2RXsoBAi4z39LeB+2+BBCuifcYvfimCYhpt1IZ1t8eoYOiivImGVuq4lkQsE3bfoqBE1MICNW9TOONCvV5E/fGywbBU7oQIEYJAuX9piiACC3CfCP2Jeq1+IsrcTCWCOq5Tj4lDQJW0uEbeAhkH6qgxOFyjSmYdOuO19ALCvO2wEEW6dJrb8Ky25XWZDk7lmtnoAKj3I9EE2Sezr4KIp20y0K3OLeTZEPP2OliY9xqTTcuvsiR0LVOnr6MD7//I8dI7WjgKpbz0hDM0= test3@host 2 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/README.md: -------------------------------------------------------------------------------- 1 | # Bug Test Configs 2 | 3 | ## purpose 4 | Configs that reproduce bugs filed against cloud-init. Having test configs for 5 | cloud-init bugs ensures that the fixes do not break in the future, and makes it 6 | easy to see how many systems and platforms are effected by a new bug. 7 | 8 | ## structure 9 | Should have one test config for most bugs filed. The name of the test should 10 | contain ``lp`` followed by the bug number. It may also be useful to add a 11 | comment to each bug config with a summary copied from the bug report. 12 | 13 | # vi: ts=4 expandtab 14 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_pipelining_disable.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptPipeliningDisable(base.CloudTestCase): 8 | """Test apt-pipelining module.""" 9 | 10 | def test_disable_pipelining(self): 11 | """Test pipelining disabled.""" 12 | out = self.get_data_file('90cloud-init-pipelining') 13 | self.assertIn('Acquire::http::Pipeline-Depth "0";', out) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /cloudinit/sources/helpers/vmware/imc/guestcust_event.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Canonical Ltd. 2 | # Copyright (C) 2016 VMware Inc. 3 | # 4 | # Author: Sankar Tanguturi 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | 9 | class GuestCustEventEnum(object): 10 | """Specifies different types of Guest Customization Events""" 11 | 12 | GUESTCUST_EVENT_CUSTOMIZE_FAILED = 100 13 | GUESTCUST_EVENT_NETWORK_SETUP_FAILED = 101 14 | GUESTCUST_EVENT_ENABLE_NICS = 103 15 | GUESTCUST_EVENT_QUERY_NICS = 104 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | cloud_init.egg-info 3 | dist 4 | *.pyc 5 | __pycache__ 6 | .tox 7 | .coverage 8 | doc/rtd_html 9 | parts 10 | prime 11 | stage 12 | *.snap 13 | *.cover 14 | .idea/ 15 | .venv/ 16 | .pc/ 17 | .cache/ 18 | .mypy_cache/ 19 | .pytest_cache/ 20 | .vscode/ 21 | htmlcov/ 22 | 23 | # Ignore packaging artifacts 24 | cloud-init.dsc 25 | cloud-init_*.build 26 | cloud-init_*.buildinfo 27 | cloud-init_*.changes 28 | cloud-init_*.deb 29 | cloud-init_*.dsc 30 | cloud-init_*.orig.tar.gz 31 | cloud-init_*.tar.xz 32 | cloud-init_*.upload 33 | 34 | # user test settings 35 | tests/integration_tests/user_settings.py 36 | -------------------------------------------------------------------------------- /tools/build-on-openbsd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | fail() { echo "FAILED:" "$@" 1>&2; exit 1; } 4 | 5 | # Check dependencies: 6 | depschecked=/tmp/c-i.dependencieschecked 7 | pkgs=" 8 | bash 9 | dmidecode 10 | py3-configobj 11 | py3-jinja2 12 | py3-jsonschema 13 | py3-oauthlib 14 | py3-requests 15 | py3-setuptools 16 | py3-six 17 | py3-yaml 18 | sudo-- 19 | " 20 | [ -f "$depschecked" ] || pkg_add ${pkgs} || fail "install packages" 21 | 22 | touch $depschecked 23 | 24 | python3 setup.py build 25 | python3 setup.py install -O1 --distro openbsd --skip-build 26 | 27 | echo "Installation completed." 28 | -------------------------------------------------------------------------------- /tests/data/netinfo/netdev-formatted-output-down: -------------------------------------------------------------------------------- 1 | +++++++++++++++++++++++++++Net device info++++++++++++++++++++++++++++ 2 | +--------+-------+-----------+-----------+-------+-------------------+ 3 | | Device | Up | Address | Mask | Scope | Hw-Address | 4 | +--------+-------+-----------+-----------+-------+-------------------+ 5 | | eth0 | False | . | . | . | 00:16:3e:de:51:a6 | 6 | | lo | True | 127.0.0.1 | 255.0.0.0 | host | . | 7 | | lo | True | ::1/128 | . | host | . | 8 | +--------+-------+-----------+-----------+-------+-------------------+ 9 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/install_run_chef_recipes.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestChefExample(base.CloudTestCase): 8 | """Test chef module.""" 9 | 10 | def test_chef_basic(self): 11 | """Test chef installed.""" 12 | out = self.get_data_file('chef_installed') 13 | self.assertIn('install ok', out) 14 | 15 | # FIXME: Add more tests, and/or replace with comprehensive module tests 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/debug_disable.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestDebugDisable(base.CloudTestCase): 8 | """Disable debug messages.""" 9 | 10 | def test_debug_disable(self): 11 | """Test verbose output missing from logs.""" 12 | out = self.get_data_file('cloud-init.log') 13 | self.assertNotIn( 14 | out, r'Skipping module named [a-z].* verbose printing disabled') 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /sysvinit/freebsd/cloudconfig: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudconfig 4 | # REQUIRE: cloudinit cloudinitlocal 5 | # BEFORE: cloudfinal 6 | 7 | . /etc/rc.subr 8 | 9 | PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 10 | 11 | name="cloudconfig" 12 | command="/usr/local/bin/cloud-init" 13 | start_cmd="cloudconfig_start" 14 | stop_cmd=":" 15 | rcvar="cloudinit_enable" 16 | start_cmd="cloudconfig_start" 17 | 18 | cloudconfig_start() 19 | { 20 | echo "${command} starting" 21 | ${command} modules --mode config 22 | } 23 | 24 | load_rc_config $name 25 | 26 | : ${cloudconfig_enable="NO"} 27 | 28 | run_rc_command "$1" 29 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/TODO.md: -------------------------------------------------------------------------------- 1 | # Missing Examples 2 | 3 | Below lists each of the issing examples and why it is not currently added. 4 | 5 | - Chef (takes > 60 seconds to run) 6 | - Puppet (takes > 60 seconds to run) 7 | - Manage resolve.conf (lxd backend overrides changes) 8 | - Adding a yum repository (need centos system) 9 | - Register Red Hat Subscription (need centos system + subscription) 10 | - Adjust mount points mounted (need multiple disks) 11 | - Call a url when finished (need end point) 12 | - Reboot/poweroff when finished (how to test) 13 | - Disk setup (need multiple disks) 14 | 15 | # vi: ts=4 expandtab 16 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_import_id.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestSshImportId(base.CloudTestCase): 8 | """Test ssh import id module.""" 9 | 10 | def test_authorized_keys(self): 11 | """Test that ssh keys were imported.""" 12 | out = self.get_data_file('auth_keys_ubuntu') 13 | 14 | self.assertIn('# ssh-import-id gh:powersj', out) 15 | self.assertIn('# ssh-import-id lp:smoser', out) 16 | 17 | # vi: ts=4 expandtab 18 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-resolv-conf.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # 3 | # This is an example file to automatically configure resolv.conf when the 4 | # instance boots for the first time. 5 | # 6 | # Ensure that your yaml is valid and pass this as user-data when starting 7 | # the instance. Also be sure that your cloud.cfg file includes this 8 | # configuration module in the appropriate section. 9 | # 10 | manage_resolv_conf: true 11 | 12 | resolv_conf: 13 | nameservers: ['8.8.4.4', '8.8.8.8'] 14 | searchdomains: 15 | - foo.example.com 16 | - bar.example.com 17 | domain: example.com 18 | options: 19 | rotate: true 20 | timeout: 1 21 | -------------------------------------------------------------------------------- /sysvinit/freebsd/cloudinit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudinit 4 | # REQUIRE: FILESYSTEMS NETWORKING cloudinitlocal ldconfig devd 5 | # BEFORE: LOGIN cloudconfig cloudfinal 6 | 7 | . /etc/rc.subr 8 | 9 | PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 10 | 11 | name="cloudinit" 12 | command="/usr/local/bin/cloud-init" 13 | start_cmd="cloudinit_start" 14 | stop_cmd=":" 15 | rcvar="cloudinit_enable" 16 | start_cmd="cloudinit_start" 17 | 18 | cloudinit_start() 19 | { 20 | echo -n "${command} starting" 21 | ${command} init 22 | } 23 | 24 | load_rc_config $name 25 | 26 | : ${cloudinit_enable="NO"} 27 | 28 | run_rc_command "$1" 29 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-vendor-data.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # 3 | # This explains how to control vendordata via a cloud-config 4 | # 5 | # On select Datasources, vendors have a channel for the consumptions 6 | # of all support user-data types via a special channel called 7 | # vendordata. Users of the end system are given ultimate control. 8 | # 9 | vendor_data: 10 | enabled: True 11 | prefix: /usr/bin/ltrace 12 | 13 | # enabled: whether it is enabled or not 14 | # prefix: the command to run before any vendor scripts. 15 | # Note: this is a fairly weak method of containment. It should 16 | # be used to profile a script, not to prevent its run 17 | -------------------------------------------------------------------------------- /sysvinit/freebsd/cloudfinal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudfinal 4 | # REQUIRE: LOGIN cloudinit cloudconfig cloudinitlocal 5 | # REQUIRE: cron mail sshd swaplate 6 | 7 | . /etc/rc.subr 8 | 9 | PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 10 | 11 | name="cloudfinal" 12 | command="/usr/local/bin/cloud-init" 13 | start_cmd="cloudfinal_start" 14 | stop_cmd=":" 15 | rcvar="cloudinit_enable" 16 | start_cmd="cloudfinal_start" 17 | 18 | cloudfinal_start() 19 | { 20 | echo -n "${command} starting" 21 | ${command} modules --mode final 22 | } 23 | 24 | load_rc_config $name 25 | 26 | : ${cloudfinal_enable="NO"} 27 | 28 | run_rc_command "$1" 29 | -------------------------------------------------------------------------------- /cloudinit/distros/parsers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Yahoo! Inc. 2 | # 3 | # Author: Joshua Harlow 4 | # 5 | # This file is part of cloud-init. See LICENSE file for license information. 6 | 7 | 8 | def chop_comment(text, comment_chars): 9 | comment_locations = [text.find(c) for c in comment_chars] 10 | comment_locations = [c for c in comment_locations if c != -1] 11 | if not comment_locations: 12 | return (text, '') 13 | min_comment = min(comment_locations) 14 | before_comment = text[0:min_comment] 15 | comment = text[min_comment:] 16 | return (before_comment, comment) 17 | 18 | # vi: ts=4 expandtab 19 | -------------------------------------------------------------------------------- /tests/data/vmware/cust-dhcp-2nic.cfg: -------------------------------------------------------------------------------- 1 | [NETWORK] 2 | NETWORKING = yes 3 | BOOTPROTO = dhcp 4 | HOSTNAME = myhost1 5 | DOMAINNAME = eng.vmware.com 6 | 7 | [NIC-CONFIG] 8 | NICS = NIC1,NIC2 9 | 10 | [NIC1] 11 | MACADDR = 00:50:56:a6:8c:08 12 | ONBOOT = yes 13 | IPv4_MODE = BACKWARDS_COMPATIBLE 14 | BOOTPROTO = dhcp 15 | 16 | [NIC2] 17 | MACADDR = 00:50:56:a6:5a:de 18 | ONBOOT = yes 19 | IPv4_MODE = BACKWARDS_COMPATIBLE 20 | BOOTPROTO = dhcp 21 | 22 | # some random comment 23 | 24 | [PASSWORD] 25 | # secret 26 | -PASS = c2VjcmV0Cg== 27 | 28 | [DNS] 29 | DNSFROMDHCP=yes 30 | SUFFIX|1 = eng.vmware.com 31 | 32 | [DATETIME] 33 | TIMEZONE = Africa/Abidjan 34 | UTC = yes 35 | -------------------------------------------------------------------------------- /upstart/cloud-log-shutdown.conf: -------------------------------------------------------------------------------- 1 | # log shutdowns and reboots to the console (/dev/console) 2 | # this is useful for correlating logs 3 | start on runlevel PREVLEVEL=2 4 | 5 | task 6 | console output 7 | 8 | script 9 | # runlevel(7) says INIT_HALT will be set to HALT or POWEROFF 10 | date=$(date --utc) 11 | case "$RUNLEVEL:$INIT_HALT" in 12 | 6:*) mode="reboot";; 13 | 0:HALT) mode="halt";; 14 | 0:POWEROFF) mode="poweroff";; 15 | 0:*) mode="shutdown-unknown";; 16 | esac 17 | { read seconds idle < /proc/uptime; } 2>/dev/null || : 18 | echo "$date: shutting down for $mode${seconds:+ [up ${seconds%.*}s]}." 19 | end script 20 | -------------------------------------------------------------------------------- /sysvinit/freebsd/cloudinitlocal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # PROVIDE: cloudinitlocal 4 | # REQUIRE: ldconfig mountcritlocal 5 | # BEFORE: NETWORKING cloudinit cloudconfig cloudfinal 6 | 7 | . /etc/rc.subr 8 | 9 | PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 10 | 11 | name="cloudinitlocal" 12 | command="/usr/local/bin/cloud-init" 13 | start_cmd="cloudlocal_start" 14 | stop_cmd=":" 15 | rcvar="cloudinit_enable" 16 | start_cmd="cloudlocal_start" 17 | 18 | cloudlocal_start() 19 | { 20 | echo -n "${command} starting" 21 | ${command} init --local 22 | } 23 | 24 | load_rc_config $name 25 | 26 | : ${cloudinitlocal_enable="NO"} 27 | 28 | run_rc_command "$1" 29 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/test_netbsd.py: -------------------------------------------------------------------------------- 1 | import cloudinit.distros.netbsd 2 | 3 | import pytest 4 | import unittest.mock as mock 5 | 6 | 7 | @pytest.mark.parametrize('with_pkgin', (True, False)) 8 | @mock.patch("cloudinit.distros.netbsd.os") 9 | def test_init(m_os, with_pkgin): 10 | print(with_pkgin) 11 | m_os.path.exists.return_value = with_pkgin 12 | cfg = {} 13 | 14 | distro = cloudinit.distros.netbsd.NetBSD("netbsd", cfg, None) 15 | expectation = ['pkgin', '-y', 'full-upgrade'] if with_pkgin else None 16 | assert distro.pkg_cmd_upgrade_prefix == expectation 17 | assert [mock.call('/usr/pkg/bin/pkgin')] == m_os.path.exists.call_args_list 18 | -------------------------------------------------------------------------------- /tests/integration_tests/bugs/test_gh868.py: -------------------------------------------------------------------------------- 1 | """Ensure no Traceback when 'chef_license' is set""" 2 | import pytest 3 | from tests.integration_tests.instances import IntegrationInstance 4 | 5 | 6 | USERDATA = """\ 7 | #cloud-config 8 | chef: 9 | install_type: omnibus 10 | chef_license: accept 11 | server_url: https://chef.yourorg.invalid 12 | validation_name: some-validator 13 | """ 14 | 15 | 16 | @pytest.mark.adhoc # Can't be regularly reaching out to chef install script 17 | @pytest.mark.user_data(USERDATA) 18 | def test_chef_license(client: IntegrationInstance): 19 | log = client.read_from_file('/var/log/cloud-init.log') 20 | assert 'Traceback' not in log 21 | -------------------------------------------------------------------------------- /packages/debian/cloud-init.preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vi: ts=4 expandtab 3 | 4 | cleanup_lp1552999() { 5 | local oldver="$1" last_bad_ver="0.7.7~bzr1178" 6 | dpkg --compare-versions "$oldver" le "$last_bad_ver" || return 0 7 | local hdir="/var/lib/systemd/deb-systemd-helper-enabled" 8 | hdir="$hdir/multi-user.target.wants" 9 | local edir="/etc/systemd/system/multi-user.target.wants" 10 | rm -f "$hdir/cloud-config.service" "$hdir/cloud-final.service" \ 11 | "$hdir/cloud-init-local.service" "$hdir/cloud-init.service" 12 | } 13 | 14 | 15 | if [ "$1" = "upgrade" ]; then 16 | oldver="$2" 17 | cleanup_lp1552999 "$oldver" 18 | fi 19 | 20 | #DEBHELPER# 21 | -------------------------------------------------------------------------------- /packages/debian/control.in: -------------------------------------------------------------------------------- 1 | ## template:basic 2 | Source: cloud-init 3 | Section: admin 4 | Priority: optional 5 | Maintainer: Scott Moser 6 | Build-Depends: ${build_depends} 7 | XS-Python-Version: all 8 | Standards-Version: 3.9.6 9 | 10 | Package: cloud-init 11 | Architecture: all 12 | Depends: ${misc:Depends}, 13 | ${python3:Depends}, 14 | iproute2, 15 | isc-dhcp-client 16 | Recommends: eatmydata, sudo, software-properties-common, gdisk 17 | Description: Init scripts for cloud instances 18 | Cloud instances need special scripts to run during initialisation 19 | to retrieve and install ssh keys and to let the user run various scripts. 20 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestSshKeyFingerprintsDisable(base.CloudTestCase): 8 | """Test ssh key fingerprints module.""" 9 | 10 | def test_cloud_init_log(self): 11 | """Verify disabled.""" 12 | out = self.get_data_file('cloud-init.log') 13 | self.assertIn('Skipping module named ssh-authkey-fingerprints, ' 14 | 'logging of SSH fingerprints disabled', out) 15 | 16 | # vi: ts=4 expandtab 17 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_servers.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # NTP config using specific servers 3 | # 4 | required_features: 5 | - lsb_release 6 | cloud_config: | 7 | #cloud-config 8 | ntp: 9 | ntp_client: ntp 10 | servers: 11 | - 172.16.15.14 12 | - 172.16.17.18 13 | collect_scripts: 14 | ntp_installed_servers: | 15 | #!/bin/sh 16 | ntpd --version > /dev/null 2>&1 17 | echo $? 18 | ntp_conf_dist_servers: | 19 | #!/bin/sh 20 | cat /etc/ntp.conf.dist | wc -l 21 | ntp_conf_servers: | 22 | #!/bin/sh 23 | grep '^server' /etc/ntp.conf 24 | ntpq_servers: | 25 | #!/bin/sh 26 | ntpq -p -w -n 27 | 28 | # vi: ts=4 expandtab 29 | -------------------------------------------------------------------------------- /systemd/cloud-final.service.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | [Unit] 3 | Description=Execute cloud user/final scripts 4 | After=network-online.target cloud-config.service rc-local.service 5 | {% if variant in ["ubuntu", "unknown", "debian"] %} 6 | After=multi-user.target 7 | Before=apt-daily.service 8 | {% endif %} 9 | Wants=network-online.target cloud-config.service 10 | 11 | 12 | [Service] 13 | Type=oneshot 14 | ExecStart=/usr/bin/cloud-init modules --mode=final 15 | RemainAfterExit=yes 16 | TimeoutSec=0 17 | KillMode=process 18 | TasksMax=infinity 19 | 20 | # Output needs to appear in instance console output 21 | StandardOutput=journal+console 22 | 23 | [Install] 24 | WantedBy=cloud-init.target 25 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Add a sources.list entry with a key from a keyserver 3 | # 4 | required_features: 5 | - apt 6 | - lsb_release 7 | cloud_config: | 8 | #cloud-config 9 | apt: 10 | sources: 11 | source1: 12 | keyid: 1FF0D8535EF7E719E5C81B9C083D06FBE4D304DF 13 | keyserver: keyserver.ubuntu.com 14 | source: "deb http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu $RELEASE main" 15 | collect_scripts: 16 | sources.list: | 17 | #!/bin/bash 18 | cat /etc/apt/sources.list.d/source1.list 19 | apt_key_list: | 20 | #!/bin/bash 21 | apt-key finger 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tools/hook-hotplug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | # This script checks if cloud-init has hotplug hooked and if 5 | # cloud-init has finished; if so invoke cloud-init hotplug-hook 6 | 7 | is_finished() { 8 | [ -e /run/cloud-init/result.json ] 9 | } 10 | 11 | if is_finished; then 12 | # open cloud-init's hotplug-hook fifo rw 13 | exec 3<>/run/cloud-init/hook-hotplug-cmd 14 | env_params=( 15 | --devpath="${DEVPATH}" 16 | --subsystem="${SUBSYSTEM}" 17 | --udevaction="${ACTION}" 18 | ) 19 | # write params to cloud-init's hotplug-hook fifo 20 | echo "${env_params[@]}" >&3 21 | fi 22 | -------------------------------------------------------------------------------- /cloudinit/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Yahoo! Inc. 2 | # 3 | # Author: Joshua Harlow 4 | # 5 | # This file is part of cloud-init. See LICENSE file for license information. 6 | 7 | __VERSION__ = "21.2" 8 | _PACKAGED_VERSION = '@@PACKAGED_VERSION@@' 9 | 10 | FEATURES = [ 11 | # supports network config version 1 12 | 'NETWORK_CONFIG_V1', 13 | # supports network config version 2 (netplan) 14 | 'NETWORK_CONFIG_V2', 15 | ] 16 | 17 | 18 | def version_string(): 19 | """Extract a version string from cloud-init.""" 20 | if not _PACKAGED_VERSION.startswith('@@'): 21 | return _PACKAGED_VERSION 22 | return __VERSION__ 23 | 24 | # vi: ts=4 expandtab 25 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/install_arbitrary_packages.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestInstall(base.CloudTestCase): 8 | """Example cloud-config test.""" 9 | 10 | def test_htop(self): 11 | """Verify htop installed.""" 12 | out = self.get_data_file('htop') 13 | self.assertEqual(1, int(out)) 14 | 15 | def test_tree(self): 16 | """Verify tree installed.""" 17 | out = self.get_data_file('treeutils') 18 | self.assertEqual(1, int(out)) 19 | 20 | # vi: ts=4 expandtab 21 | -------------------------------------------------------------------------------- /tools/validate-yaml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Try to read a YAML file and report any errors. 4 | """ 5 | 6 | import sys 7 | import yaml 8 | 9 | 10 | if __name__ == "__main__": 11 | bads = 0 12 | for fn in sys.argv[1:]: 13 | sys.stdout.write("%s" % (fn)) 14 | try: 15 | fh = open(fn, 'rb') 16 | yaml.safe_load(fh.read().decode('utf-8')) 17 | fh.close() 18 | sys.stdout.write(" - ok\n") 19 | except Exception as e: 20 | sys.stdout.write(" - bad (%s)\n" % (e)) 21 | bads += 1 22 | if bads > 0: 23 | sys.exit(1) 24 | else: 25 | sys.exit(0) 26 | 27 | # vi: ts=4 expandtab 28 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-boot-cmds.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # boot commands 4 | # default: none 5 | # this is very similar to runcmd, but commands run very early 6 | # in the boot process, only slightly after a 'boothook' would run. 7 | # bootcmd should really only be used for things that could not be 8 | # done later in the boot process. bootcmd is very much like 9 | # boothook, but possibly with more friendly. 10 | # - bootcmd will run on every boot 11 | # - the INSTANCE_ID variable will be set to the current instance id. 12 | # - you can use 'cloud-init-per' command to help only run once 13 | bootcmd: 14 | - echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts 15 | - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] 16 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-launch-index.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # vim: syntax=yaml 3 | 4 | # 5 | # This is the configuration syntax that can be provided to have 6 | # a given set of cloud config data show up on a certain launch 7 | # index (and not other launches) by provided a key here which 8 | # will act as a filter on the instances userdata. When 9 | # this key is left out (or non-integer) then the content 10 | # of this file will always be used for all launch-indexes 11 | # (ie the previous behavior). 12 | launch-index: 5 13 | 14 | # Upgrade the instance on first boot 15 | # (ie run apt-get upgrade) 16 | # 17 | # Default: false 18 | # 19 | apt_upgrade: true 20 | 21 | # Other yaml keys below... 22 | # ....... 23 | # ....... 24 | -------------------------------------------------------------------------------- /cloudinit/distros/amazon.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Canonical Ltd. 2 | # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. 3 | # Copyright (C) 2012 Yahoo! Inc. 4 | # Copyright (C) 2014 Amazon.com, Inc. or its affiliates. 5 | # 6 | # Author: Scott Moser 7 | # Author: Juerg Haefliger 8 | # Author: Joshua Harlow 9 | # Author: Andrew Jorgensen 10 | # 11 | # This file is part of cloud-init. See LICENSE file for license information. 12 | 13 | from cloudinit.distros import rhel 14 | 15 | 16 | class Distro(rhel.Distro): 17 | 18 | def update_package_sources(self): 19 | return None 20 | 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /cloud-tests-requirements.txt: -------------------------------------------------------------------------------- 1 | # PyPI requirements for cloud-init cloud tests 2 | # https://cloudinit.readthedocs.io/en/latest/topics/cloud_tests.html 3 | # 4 | # Note: Changes to this requirements may require updates to 5 | # the packages/pkg-deps.json file as well. 6 | # 7 | 8 | # ec2 backend 9 | boto3==1.14.53 10 | 11 | # ssh communication 12 | paramiko==2.7.2 13 | cryptography==3.2 14 | 15 | # lxd backend 16 | pylxd==2.2.11 17 | 18 | # finds latest image information 19 | git+https://git.launchpad.net/simplestreams 20 | 21 | # azure backend 22 | azure-storage==0.36.0 23 | msrestazure==0.6.1 24 | azure-common==1.1.23 25 | azure-mgmt-compute==7.0.0 26 | azure-mgmt-network==5.0.0 27 | azure-mgmt-resource==4.0.0 28 | azure-mgmt-storage==6.0.0 29 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-yum-repo.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # vim: syntax=yaml 3 | # 4 | # Add yum repository configuration to the system 5 | # 6 | # The following example adds the file /etc/yum.repos.d/epel_testing.repo 7 | # which can then subsequently be used by yum for later operations. 8 | yum_repos: 9 | # The name of the repository 10 | epel-testing: 11 | # Any repository configuration options 12 | # See: man yum.conf 13 | # 14 | # This one is required! 15 | baseurl: http://download.fedoraproject.org/pub/epel/testing/5/$basearch 16 | enabled: false 17 | failovermethod: priority 18 | gpgcheck: true 19 | gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL 20 | name: Extra Packages for Enterprise Linux 5 - Testing 21 | -------------------------------------------------------------------------------- /tests/integration_tests/modules/test_runcmd.py: -------------------------------------------------------------------------------- 1 | """Integration test for the runcmd module. 2 | 3 | This test specifies a command to be executed by the ``runcmd`` module 4 | and then checks if that command was executed during boot. 5 | 6 | (This is ported from 7 | ``tests/cloud_tests/testcases/modules/runcmd.yaml``.)""" 8 | 9 | import pytest 10 | 11 | 12 | USER_DATA = """\ 13 | #cloud-config 14 | runcmd: 15 | - echo cloud-init run cmd test > /var/tmp/run_cmd 16 | """ 17 | 18 | 19 | @pytest.mark.ci 20 | class TestRuncmd: 21 | 22 | @pytest.mark.user_data(USER_DATA) 23 | def test_runcmd(self, client): 24 | runcmd_output = client.read_from_file("/var/tmp/run_cmd") 25 | assert runcmd_output.strip() == "cloud-init run cmd test" 26 | -------------------------------------------------------------------------------- /tests/integration_tests/modules/test_timezone.py: -------------------------------------------------------------------------------- 1 | """Integration test for the timezone module. 2 | 3 | This test specifies a timezone to be used by the ``timezone`` module 4 | and then checks that if that timezone was respected during boot. 5 | 6 | (This is ported from 7 | ``tests/cloud_tests/testcases/modules/timezone.yaml``.)""" 8 | 9 | import pytest 10 | 11 | 12 | USER_DATA = """\ 13 | #cloud-config 14 | timezone: US/Aleutian 15 | """ 16 | 17 | 18 | @pytest.mark.ci 19 | class TestTimezone: 20 | 21 | @pytest.mark.user_data(USER_DATA) 22 | def test_timezone(self, client): 23 | timezone_output = client.execute( 24 | 'date "+%Z" --date="Thu, 03 Nov 2016 00:47:00 -0400"') 25 | assert timezone_output.strip() == "HDT" 26 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | import copy 3 | 4 | from cloudinit import distros 5 | from cloudinit import helpers 6 | from cloudinit import settings 7 | 8 | 9 | def _get_distro(dtype, system_info=None): 10 | """Return a Distro class of distro 'dtype'. 11 | 12 | cfg is format of CFG_BUILTIN['system_info']. 13 | 14 | example: _get_distro("debian") 15 | """ 16 | if system_info is None: 17 | system_info = copy.deepcopy(settings.CFG_BUILTIN['system_info']) 18 | system_info['distro'] = dtype 19 | paths = helpers.Paths(system_info['paths']) 20 | distro_cls = distros.fetch(dtype) 21 | return distro_cls(dtype, system_info, paths) 22 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/add_apt_repositories.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # From cloud config examples on cloudinit.readthedocs.io 3 | # 4 | # 2016-11-17: Disabled as covered by module based tests 5 | # 6 | enabled: False 7 | required_features: 8 | - apt 9 | cloud_config: | 10 | #cloud-config 11 | apt: 12 | primary: 13 | - arches: [default] 14 | uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/" 15 | collect_scripts: 16 | ubuntu.sources.list: | 17 | #!/bin/bash 18 | cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep archive.ubuntu.com | wc -l 19 | gatech.sources.list: | 20 | #!/bin/bash 21 | cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep gtlib.gatech.edu | wc -l 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestSshKeyFingerprintsEnable(base.CloudTestCase): 8 | """Test ssh key fingerprints module.""" 9 | 10 | def test_syslog(self): 11 | """Verify output of syslog.""" 12 | out = self.get_data_file('syslog') 13 | self.assertRegex(out, r'256 SHA256:.*(ECDSA)') 14 | self.assertRegex(out, r'256 SHA256:.*(ED25519)') 15 | self.assertNotRegex(out, r'1024 SHA256:.*(DSA)') 16 | self.assertNotRegex(out, r'2048 SHA256:.*(RSA)') 17 | 18 | # vi: ts=4 expandtab 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/add_apt_repositories.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigurePrimary(base.CloudTestCase): 8 | """Example cloud-config test.""" 9 | 10 | def test_ubuntu_sources(self): 11 | """Test no default Ubuntu entries exist.""" 12 | out = self.get_data_file('ubuntu.sources.list') 13 | self.assertEqual(0, int(out)) 14 | 15 | def test_gatech_sources(self): 16 | """Test GaTech entires exist.""" 17 | out = self.get_data_file('gatech.sources.list') 18 | self.assertEqual(20, int(out)) 19 | 20 | # vi: ts=4 expandtab 21 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_conf.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureConf(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_apt_conf_assumeyes(self): 11 | """Test config assumes true.""" 12 | out = self.get_data_file('94cloud-init-config') 13 | self.assertIn('Assume-Yes "true";', out) 14 | 15 | def test_apt_conf_fixbroken(self): 16 | """Test config fixes broken.""" 17 | out = self.get_data_file('94cloud-init-config') 18 | self.assertIn('Fix-Broken "true";', out) 19 | 20 | # vi: ts=4 expandtab 21 | -------------------------------------------------------------------------------- /doc/man/cloud-id.1: -------------------------------------------------------------------------------- 1 | .TH CLOUD-ID 1 2 | 3 | .SH NAME 4 | cloud-id \- Report the canonical cloud-id for this instance 5 | 6 | .SH SYNOPSIS 7 | .BR "cloud-id" " [-h] [-j] [-l] [-i ]" 8 | 9 | .SH OPTIONS 10 | .TP 11 | .B "-h, --help" 12 | Show help message and exit 13 | 14 | .TP 15 | .B "-j, --json" 16 | Report all standardized cloud-id information as json 17 | 18 | .TP 19 | .B "-l, --long" 20 | Report extended cloud-id information as tab-delimited string 21 | 22 | .TP 23 | .BR "-i , --instance-data " 24 | Path to instance-data.json file. Default is 25 | /run/cloud-init/instance-data.json 26 | 27 | .SH COPYRIGHT 28 | Copyright (C) 2020 Canonical Ltd. License GPL-3 or Apache-2.0 29 | 30 | .SH SEE ALSO 31 | Full documentation at: 32 | -------------------------------------------------------------------------------- /tests/data/merge_sources/source7-1.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | users: 4 | - default 5 | - name: foobar 6 | gecos: Foo B. Bar 7 | primary_group: foobar 8 | groups: users 9 | selinux_user: staff_u 10 | expiredate: '2012-09-01' 11 | ssh_import_id: foobar 12 | lock-passwd: false 13 | passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ 14 | - name: barfoo 15 | gecos: Bar B. Foo 16 | sudo: ALL=(ALL) NOPASSWD:ALL 17 | groups: users, admin 18 | ssh_import_id: None 19 | lock-passwd: true 20 | ssh_authorized_keys: 21 | - 22 | - 23 | - name: cloudy 24 | gecos: Magic Cloud App Daemon User 25 | inactive: '5' 26 | system: true 27 | 28 | -------------------------------------------------------------------------------- /tools/motd-hook: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2010 Canonical Ltd. 3 | # 4 | # Authors: Scott Moser 5 | # 6 | # This file is part of cloud-init. See LICENSE file for license information. 7 | 8 | # 92-ec2-upgrade-available - update-motd script 9 | 10 | # Determining if updates are available is possibly slow. 11 | # a cronjob runs occasioinally and updates a file with information 12 | # on the latest available release (if newer than current) 13 | 14 | BUILD_FILE=/var/lib/cloud/data/available.build 15 | 16 | [ -s "${BUILD_FILE}" ] || exit 0 17 | 18 | read suite build_name name serial other < "${BUILD_FILE}" 19 | 20 | cat </dev/null | grep -v ^# | sort -u 31 | 32 | # vi: ts=4 expandtab 33 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestPassword(base.CloudTestCase): 8 | """Test password module.""" 9 | 10 | # TODO add test to make sure password is actually "password" 11 | 12 | def test_shadow(self): 13 | """Test ubuntu user in shadow.""" 14 | out = self.get_data_file('shadow') 15 | self.assertIn('ubuntu:', out) 16 | 17 | def test_sshd_config(self): 18 | """Test sshd config allows passwords.""" 19 | out = self.get_data_file('sshd_config') 20 | self.assertIn('PasswordAuthentication yes', out) 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /tests/data/azure/pubkey_extract_cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB+TCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtSb290 3 | IEFnZW5jeTAeFw0xOTAyMTUxOTA0MDRaFw0yOTAyMTUxOTE0MDRaMGwxDDAKBgNV 4 | BAMMA0NSUDEQMA4GA1UECwwHQXp1cmVSVDEeMBwGA1UECgwVTWljcm9zb2Z0IENv 5 | cnBvcmF0aW9uMRAwDgYDVQQHDAdSZWRtb25kMQswCQYDVQQIDAJXQTELMAkGA1UE 6 | BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHU9IDclbKVYVb 7 | Yuv0+zViX+wTwlKspslmy/uf3hkWLh7pyzyrq70S7qtSW2EGixUPxZS/R8pOLHoi 8 | nlKF9ILgj0gVTCJsSwnWpXRg3rhZwIVoYMHN50BHS1SqVD0lsWNMXmo76LoJcjmW 9 | vwIznvj5C/gnhU+K7+c3m7AlCyU2wjwpBAEYj7PQs6l/wTqpEiaqC5NytNBd7qp+ 10 | lYYysVrpa1PFL0Nj4MMZARIfjkiJtL9qDhy9YZeJRQ6q/Fhz0kjvkZnfxixfKF4y 11 | WzOfhBrAtpF6oOnuYKk3hxjh9KjTTX4/U8zdLojalX09iyHyEjwJKGlGEpzh1aY7 12 | t5btUyvpAgMBAAEwDQYJKoZIhvcNAQEFBQADAQA= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /tests/data/netinfo/new-ifconfig-output-down: -------------------------------------------------------------------------------- 1 | eth0: flags=4098 mtu 1500 2 | ether 00:16:3e:de:51:a6 txqueuelen 1000 (Ethernet) 3 | RX packets 126229 bytes 158139342 (158.1 MB) 4 | RX errors 0 dropped 0 overruns 0 frame 0 5 | TX packets 59317 bytes 4839008 (4.8 MB) 6 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 7 | 8 | lo: flags=73 mtu 65536 9 | inet 127.0.0.1 netmask 255.0.0.0 10 | inet6 ::1 prefixlen 128 scopeid 0x10 11 | loop txqueuelen 1000 (Local Loopback) 12 | RX packets 260 bytes 20092 (20.0 KB) 13 | RX errors 0 dropped 0 overruns 0 frame 0 14 | TX packets 260 bytes 20092 (20.0 KB) 15 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 16 | -------------------------------------------------------------------------------- /tests/integration_tests/modules/test_snap.py: -------------------------------------------------------------------------------- 1 | """Integration test for the snap module. 2 | 3 | This test specifies a command to be executed by the ``snap`` module 4 | and then checks that if that command was executed during boot. 5 | 6 | (This is ported from 7 | ``tests/cloud_tests/testcases/modules/snap.yaml``.)""" 8 | 9 | import pytest 10 | 11 | 12 | USER_DATA = """\ 13 | #cloud-config 14 | package_update: true 15 | snap: 16 | squashfuse_in_container: true 17 | commands: 18 | - snap install hello-world 19 | """ 20 | 21 | 22 | @pytest.mark.ci 23 | @pytest.mark.ubuntu 24 | class TestSnap: 25 | 26 | @pytest.mark.user_data(USER_DATA) 27 | def test_snap(self, client): 28 | snap_output = client.execute("snap list") 29 | assert "core " in snap_output 30 | assert "hello-world " in snap_output 31 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/keys_to_console.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestKeysToConsole(base.CloudTestCase): 8 | """Test proper keys are included and excluded to console.""" 9 | 10 | def test_excluded_keys(self): 11 | """Test excluded keys missing.""" 12 | out = self.get_data_file('syslog') 13 | self.assertNotIn('(DSA)', out) 14 | self.assertNotIn('(ECDSA)', out) 15 | 16 | def test_expected_keys(self): 17 | """Test expected keys exist.""" 18 | out = self.get_data_file('syslog') 19 | self.assertIn('(ED25519)', out) 20 | self.assertIn('(RSA)', out) 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /tests/integration_tests/modules/test_command_output.py: -------------------------------------------------------------------------------- 1 | """Integration test for output redirection. 2 | 3 | This test redirects the output of a command to a file and then checks the file. 4 | 5 | (This is ported from 6 | ``tests/cloud_tests/testcases/main/command_output_simple.yaml``.)""" 7 | import pytest 8 | 9 | from tests.integration_tests.instances import IntegrationInstance 10 | 11 | 12 | USER_DATA = """\ 13 | #cloud-config 14 | output: { all: "| tee -a /var/log/cloud-init-test-output" } 15 | final_message: "should be last line in cloud-init-test-output file" 16 | """ 17 | 18 | 19 | @pytest.mark.ci 20 | @pytest.mark.user_data(USER_DATA) 21 | def test_runcmd(client: IntegrationInstance): 22 | log = client.read_from_file('/var/log/cloud-init-test-output') 23 | assert 'should be last line in cloud-init-test-output file' in log 24 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/gce.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_gce: 2 | 3 | Google Compute Engine 4 | ===================== 5 | 6 | The GCE datasource gets its data from the internal compute metadata server. 7 | Metadata can be queried at the URL 8 | '``http://metadata.google.internal/computeMetadata/v1/``' 9 | from within an instance. For more information see the `GCE metadata docs`_. 10 | 11 | Currently the default project and instance level metadatakeys keys 12 | ``project/attributes/sshKeys`` and ``instance/attributes/ssh-keys`` are merged 13 | to provide ``public-keys``. 14 | 15 | ``user-data`` and ``user-data-encoding`` can be provided to cloud-init by 16 | setting those custom metadata keys for an *instance*. 17 | 18 | .. _GCE metadata docs: https://cloud.google.com/compute/docs/storing-retrieving-metadata#querying 19 | 20 | .. vi: textwidth=78 21 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/test_dragonflybsd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import cloudinit.util 5 | from cloudinit.tests.helpers import mock 6 | 7 | 8 | def test_find_dragonflybsd_part(): 9 | assert cloudinit.util.find_dragonflybsd_part("/dev/vbd0s3") == "vbd0s3" 10 | 11 | 12 | @mock.patch("cloudinit.util.is_DragonFlyBSD") 13 | @mock.patch("cloudinit.subp.subp") 14 | def test_parse_mount(mock_subp, m_is_DragonFlyBSD): 15 | mount_out = """ 16 | vbd0s3 on / (hammer2, local) 17 | devfs on /dev (devfs, nosymfollow, local) 18 | /dev/vbd0s0a on /boot (ufs, local) 19 | procfs on /proc (procfs, local) 20 | tmpfs on /var/run/shm (tmpfs, local) 21 | """ 22 | 23 | mock_subp.return_value = (mount_out, "") 24 | m_is_DragonFlyBSD.return_value = True 25 | assert cloudinit.util.parse_mount("/") == ("vbd0s3", "hammer2", "/") 26 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Add a PPA to source.list 3 | # 4 | # NOTE: on older ubuntu releases the sources file added is named 5 | # 'cloud-init-dev-test-archive-trusty', without 'ubuntu' in the middle 6 | required_features: 7 | - apt 8 | - ppa 9 | - ppa_file_name 10 | cloud_config: | 11 | #cloud-config 12 | apt: 13 | sources: 14 | source1: 15 | keyid: 0165013E 16 | keyserver: keyserver.ubuntu.com 17 | source: "ppa:cloud-init-dev/test-archive" 18 | collect_scripts: 19 | sources.list: | 20 | #!/bin/bash 21 | cat /etc/apt/sources.list.d/cloud-init-dev-ubuntu-test-archive-*.list 22 | apt-key: | 23 | #!/bin/bash 24 | apt-key finger 25 | sources_full: | 26 | #!/bin/bash 27 | cat /etc/apt/sources.list 28 | 29 | # vi: ts=4 expandtab 30 | -------------------------------------------------------------------------------- /tools/hook-network-manager: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | # This script hooks into NetworkManager(8) via its scripts 5 | # arguments are 'interface-name' and 'action' 6 | # 7 | is_azure() { 8 | local dmi_path="/sys/class/dmi/id/board_vendor" vendor="" 9 | if [ -e "$dmi_path" ] && read vendor < "$dmi_path"; then 10 | [ "$vendor" = "Microsoft Corporation" ] && return 0 11 | fi 12 | return 1 13 | } 14 | 15 | is_enabled() { 16 | # only execute hooks if cloud-init is enabled and on azure 17 | [ -e /run/cloud-init/enabled ] || return 1 18 | is_azure 19 | } 20 | 21 | if is_enabled; then 22 | case "$1:$2" in 23 | *:up) exec cloud-init dhclient-hook up "$1";; 24 | *:down) exec cloud-init dhclient-hook down "$1";; 25 | esac 26 | fi 27 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestNtp(base.CloudTestCase): 8 | """Test ntp module""" 9 | 10 | def test_ntp_installed(self): 11 | """Test ntp installed""" 12 | self.assertPackageInstalled('ntp') 13 | 14 | def test_ntp_dist_entries(self): 15 | """Test dist config file is empty""" 16 | out = self.get_data_file('ntp_conf_dist_empty') 17 | self.assertEqual(0, int(out)) 18 | 19 | def test_ntp_entries(self): 20 | """Test config entries""" 21 | out = self.get_data_file('ntp_conf_pool_list') 22 | self.assertIn('pool.ntp.org iburst', out) 23 | 24 | # vi: ts=4 expandtab 25 | -------------------------------------------------------------------------------- /tests/integration_tests/test_logging.py: -------------------------------------------------------------------------------- 1 | """Integration tests relating to cloud-init's logging.""" 2 | 3 | 4 | class TestVarLogCloudInitOutput: 5 | """Integration tests relating to /var/log/cloud-init-output.log.""" 6 | 7 | def test_var_log_cloud_init_output_not_world_readable(self, client): 8 | """ 9 | The log can contain sensitive data, it shouldn't be world-readable. 10 | 11 | LP: #1918303 12 | """ 13 | # Check the file exists 14 | assert client.execute("test -f /var/log/cloud-init-output.log").ok 15 | 16 | # Check its permissions are as we expect 17 | perms, user, group = client.execute( 18 | "stat -c %a:%U:%G /var/log/cloud-init-output.log" 19 | ).split(":") 20 | assert "640" == perms 21 | assert "root" == user 22 | assert "adm" == group 23 | -------------------------------------------------------------------------------- /cloudinit/distros/parsers/networkmanager_conf.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 Red Hat, Inc. 2 | # 3 | # Author: Ryan McCabe 4 | # 5 | # This file is part of cloud-init. See LICENSE file for license information. 6 | 7 | import configobj 8 | 9 | # This module is used to set additional NetworkManager configuration 10 | # in /etc/NetworkManager/conf.d 11 | # 12 | 13 | 14 | class NetworkManagerConf(configobj.ConfigObj): 15 | def __init__(self, contents): 16 | configobj.ConfigObj.__init__(self, contents, 17 | interpolation=False, 18 | write_empty_values=False) 19 | 20 | def set_section_keypair(self, section_name, key, value): 21 | if section_name not in self.sections: 22 | self.main[section_name] = {} 23 | self.main[section_name] = {key: value} 24 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/fallback.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_fallback: 2 | 3 | Fallback/None 4 | ============= 5 | 6 | This is the fallback datasource when no other datasource can be selected. It 7 | is the equivalent of a empty datasource in that it provides a empty string as 8 | userdata and a empty dictionary as metadata. It is useful for testing as well 9 | as for when you do not have a need to have an actual datasource to meet your 10 | instance requirements (ie you just want to run modules that are not concerned 11 | with any external data). It is typically put at the end of the datasource 12 | search list so that if all other datasources are not matched, then this one 13 | will be so that the user is not left with an inaccessible instance. 14 | 15 | **Note:** the instance id that this datasource provides is 16 | ``iid-datasource-none``. 17 | 18 | .. vi: textwidth=78 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/landscape.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Setup landscape client settings 3 | # 4 | # 2016-11-17: Disabled due to this not working 5 | # 6 | enabled: false 7 | required_features: 8 | - landscape 9 | cloud_config: | 10 | #cloud-conifg 11 | landscape: 12 | client: 13 | log_level: "info" 14 | url: "https://landscape.canonical.com/message-system" 15 | ping_url: "http://landscape.canonical.com/ping" 16 | data_path: "/var/lib/landscape/client" 17 | http_proxy: "http://my.proxy.com/foobar" 18 | https_proxy: "https://my.proxy.com/foobar" 19 | tags: "server,cloud" 20 | computer_title: "footitle" 21 | registration_key: "fookey" 22 | account_name: "fooaccount" 23 | collect_scripts: 24 | client.conf: | 25 | #!/bin/bash 26 | cat /etc/landscape/client.conf 27 | 28 | # vi: ts=4 expandtab 29 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password_expire.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestPasswordExpire(base.CloudTestCase): 8 | """Test password module.""" 9 | 10 | def test_shadow(self): 11 | """Test user frozen in shadow.""" 12 | out = self.get_data_file('shadow') 13 | self.assertIn('harry:!:', out) 14 | self.assertIn('dick:!:', out) 15 | self.assertIn('tom:!:', out) 16 | self.assertIn('harry:!:', out) 17 | 18 | def test_sshd_config(self): 19 | """Test sshd config allows passwords.""" 20 | out = self.get_data_file('sshd_config') 21 | self.assertIn('PasswordAuthentication yes', out) 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /cloudinit/type_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Canonical Ltd. 2 | # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. 3 | # Copyright (C) 2012 Yahoo! Inc. 4 | # 5 | # Author: Scott Moser 6 | # Author: Juerg Haefliger 7 | # Author: Joshua Harlow 8 | # 9 | # This file is part of cloud-init. See LICENSE file for license information. 10 | 11 | import types 12 | 13 | 14 | _NAME_TYPES = ( 15 | types.ModuleType, 16 | types.FunctionType, 17 | types.LambdaType, 18 | type, 19 | ) 20 | 21 | 22 | def obj_name(obj): 23 | if isinstance(obj, _NAME_TYPES): 24 | return str(obj.__name__) 25 | else: 26 | if not hasattr(obj, '__class__'): 27 | return repr(obj) 28 | else: 29 | return obj_name(obj.__class__) 30 | 31 | # vi: ts=4 expandtab 32 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_list.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Generate a sources.list 3 | # 4 | required_features: 5 | - apt 6 | - lsb_release 7 | cloud_config: | 8 | #cloud-config 9 | apt: 10 | primary: 11 | - arches: [default] 12 | uri: http://archive.ubuntu.com/ubuntu 13 | security: 14 | - arches: [default] 15 | uri: http://security.ubuntu.com/ubuntu 16 | sources_list: | 17 | deb $MIRROR $RELEASE main restricted 18 | deb-src $MIRROR $RELEASE main restricted 19 | deb $PRIMARY $RELEASE universe restricted 20 | deb-src $PRIMARY $RELEASE universe restricted 21 | deb $SECURITY $RELEASE-security multiverse 22 | deb-src $SECURITY $RELEASE-security multiverse 23 | collect_scripts: 24 | sources.list: | 25 | #/bin/bash 26 | cat /etc/apt/sources.list 27 | 28 | # vi: ts=4 expandtab 29 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_password_expire.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Expire password for all users 3 | # 4 | required_features: 5 | - sshd 6 | cloud_config: | 7 | #cloud-config 8 | chpasswd: { expire: True } 9 | ssh_pwauth: yes 10 | users: 11 | - default 12 | - name: tom 13 | password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. 14 | lock_passwd: false 15 | - name: dick 16 | password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. 17 | lock_passwd: false 18 | - name: harry 19 | password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. 20 | lock_passwd: false 21 | - name: jane 22 | password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. 23 | lock_passwd: false 24 | collect_scripts: 25 | shadow: | 26 | #!/bin/bash 27 | cat /etc/shadow 28 | sshd_config: | 29 | #!/bin/bash 30 | grep '^PasswordAuth' /etc/ssh/sshd_config 31 | 32 | # vi: ts=4 expandtab 33 | -------------------------------------------------------------------------------- /tests/integration_tests/bugs/test_lp1886531.py: -------------------------------------------------------------------------------- 1 | """Integration test for LP: #1886531 2 | 3 | This test replicates the failure condition (absent /etc/fstab) on all releases 4 | by removing it in a bootcmd; this runs well before the part of cloud-init which 5 | causes the failure. 6 | 7 | The only required assertion is that cloud-init does not emit a WARNING to the 8 | log: this indicates that the fstab parsing code has not failed. 9 | 10 | https://bugs.launchpad.net/ubuntu/+source/cloud-init/+bug/1886531 11 | """ 12 | import pytest 13 | 14 | 15 | USER_DATA = """\ 16 | #cloud-config 17 | bootcmd: 18 | - rm -f /etc/fstab 19 | """ 20 | 21 | 22 | class TestLp1886531: 23 | 24 | @pytest.mark.user_data(USER_DATA) 25 | def test_lp1886531(self, client): 26 | log_content = client.read_from_file("/var/log/cloud-init.log") 27 | assert "WARNING" not in log_content 28 | -------------------------------------------------------------------------------- /doc/rtd/topics/network-config-format-eni.rst: -------------------------------------------------------------------------------- 1 | .. _network_config_eni: 2 | 3 | Network Configuration ENI (Legacy) 4 | ---------------------------------- 5 | 6 | `Cloud-init`_ supports reading and writing network config in the ``ENI`` 7 | format which is consumed by the ``ifupdown`` tool to parse and apply network 8 | configuration. 9 | 10 | As an input format this is **legacy**. In cases where ENI format is available 11 | and another format is also available, it will prefer to use the other format. 12 | This can happen in either :ref:`datasource_nocloud` or 13 | :ref:`datasource_openstack` datasources. 14 | 15 | Please reference existing `documentation`_ for the 16 | ``/etc/network/interfaces(5)`` format. 17 | 18 | .. _Cloud-init: https://launchpad.net/cloud-init 19 | .. _documentation: http://manpages.ubuntu.com/manpages/trusty/en/man5/interfaces.5.html 20 | .. vi: textwidth=78 21 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/rbxcloud.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_rbx: 2 | 3 | Rbx Cloud 4 | ========= 5 | 6 | The Rbx datasource consumes the metadata drive available on platform 7 | `HyperOne`_ and `Rootbox`_ platform. 8 | 9 | Datasource supports, in particular, network configurations, hostname, 10 | user accounts and user metadata. 11 | 12 | Metadata drive 13 | -------------- 14 | 15 | Drive metadata is a `FAT`_-formatted partition with the ```CLOUDMD``` label on 16 | the system disk. Its contents are refreshed each time the virtual machine 17 | is restarted, if the partition exists. For more information see 18 | `HyperOne Virtual Machine docs`_. 19 | 20 | .. _HyperOne: http://www.hyperone.com/ 21 | .. _Rootbox: https://rootbox.com/ 22 | .. _HyperOne Virtual Machine docs: http://www.hyperone.com/ 23 | .. _FAT: https://en.wikipedia.org/wiki/File_Allocation_Table 24 | 25 | .. vi: textwidth=78 26 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-ipaddrshow-output: -------------------------------------------------------------------------------- 1 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 2 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 3 | inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever 4 | inet6 ::1/128 scope host \ valid_lft forever preferred_lft forever 5 | 2: enp0s25: mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 6 | link/ether 50:7b:9d:2c:af:91 brd ff:ff:ff:ff:ff:ff 7 | inet 192.168.2.18/24 brd 192.168.2.255 scope global dynamic enp0s25 8 | valid_lft 84174sec preferred_lft 84174sec 9 | inet6 fe80::7777:2222:1111:eeee/64 scope global 10 | valid_lft forever preferred_lft forever 11 | inet6 fe80::8107:2b92:867e:f8a6/64 scope link 12 | valid_lft forever preferred_lft forever 13 | 14 | -------------------------------------------------------------------------------- /systemd/cloud-init-local.service.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | [Unit] 3 | Description=Initial cloud-init job (pre-networking) 4 | {% if variant in ["ubuntu", "unknown", "debian"] %} 5 | DefaultDependencies=no 6 | {% endif %} 7 | Wants=network-pre.target 8 | After=hv_kvp_daemon.service 9 | After=systemd-remount-fs.service 10 | Before=NetworkManager.service 11 | Before=network-pre.target 12 | Before=shutdown.target 13 | {% if variant in ["ubuntu", "unknown", "debian"] %} 14 | Before=sysinit.target 15 | Conflicts=shutdown.target 16 | {% endif %} 17 | RequiresMountsFor=/var/lib/cloud 18 | 19 | [Service] 20 | Type=oneshot 21 | ExecStart=/usr/bin/cloud-init init --local 22 | ExecStart=/bin/touch /run/cloud-init/network-config-ready 23 | RemainAfterExit=yes 24 | TimeoutSec=0 25 | 26 | # Output needs to appear in instance console output 27 | StandardOutput=journal+console 28 | 29 | [Install] 30 | WantedBy=cloud-init.target 31 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/main/command_output_simple.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestCommandOutputSimple(base.CloudTestCase): 8 | """Test functionality of simple output redirection.""" 9 | 10 | expected_warnings = ('Stdout, stderr changing to',) 11 | 12 | def test_output_file(self): 13 | """Ensure that the output file is not empty and has all stages.""" 14 | data = self.get_data_file('cloud-init-test-output') 15 | self.assertNotEqual(len(data), 0, "specified log empty") 16 | self.assertEqual(self.get_config_entry('final_message'), 17 | data.splitlines()[-1].strip()) 18 | # TODO: need to test that all stages redirected here 19 | 20 | 21 | # vi: ts=4 expandtab 22 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/byobu.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestByobu(base.CloudTestCase): 8 | """Test Byobu module.""" 9 | 10 | def test_byobu_installed(self): 11 | """Test byobu installed.""" 12 | self.assertPackageInstalled('byobu') 13 | 14 | def test_byobu_profile_enabled(self): 15 | """Test byobu profile.d file exists.""" 16 | out = self.get_data_file('byobu_profile_enabled') 17 | self.assertIn('/etc/profile.d/Z97-byobu.sh', out) 18 | 19 | def test_byobu_launch_exists(self): 20 | """Test byobu-launch exists.""" 21 | out = self.get_data_file('byobu_launch_exists') 22 | self.assertIn('/usr/bin/byobu-launch', out) 23 | 24 | # vi: ts=4 expandtab 25 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-landscape.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # Landscape-client configuration 3 | # 4 | # Anything under the top 'landscape: client' entry 5 | # will be basically rendered into a ConfigObj formated file 6 | # under the '[client]' section of /etc/landscape/client.conf 7 | # 8 | # Note: 'tags' should be specified as a comma delimited string 9 | # rather than a list. 10 | # 11 | # You can get example key/values by running 'landscape-config', 12 | # answer question, then look at /etc/landscape/client.config 13 | landscape: 14 | client: 15 | url: "https://landscape.canonical.com/message-system" 16 | ping_url: "http://landscape.canonical.com/ping" 17 | data_path: "/var/lib/landscape/client" 18 | http_proxy: "http://my.proxy.com/foobar" 19 | tags: "server,cloud" 20 | computer_title: footitle 21 | https_proxy: fooproxy 22 | registration_key: fookey 23 | account_name: fooaccount 24 | -------------------------------------------------------------------------------- /doc/examples/part-handler.txt: -------------------------------------------------------------------------------- 1 | #part-handler 2 | 3 | def list_types(): 4 | # return a list of mime-types that are handled by this module 5 | return(["text/plain", "text/go-cubs-go"]) 6 | 7 | def handle_part(data,ctype,filename,payload): 8 | # data: the cloudinit object 9 | # ctype: '__begin__', '__end__', or the specific mime-type of the part 10 | # filename: the filename for the part, or dynamically generated part if 11 | # no filename is given attribute is present 12 | # payload: the content of the part (empty for begin or end) 13 | if ctype == "__begin__": 14 | print "my handler is beginning" 15 | return 16 | if ctype == "__end__": 17 | print "my handler is ending" 18 | return 19 | 20 | print "==== received ctype=%s filename=%s ====" % (ctype,filename) 21 | print payload 22 | print "==== end ctype=%s filename=%s" % (ctype, filename) 23 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureSourcesPPA(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_ppa(self): 11 | """Test specific ppa added.""" 12 | out = self.get_data_file('sources.list') 13 | self.assertIn( 14 | 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out) 15 | 16 | def test_ppa_key(self): 17 | """Test ppa key added.""" 18 | out = self.get_data_file('apt-key') 19 | self.assertIn( 20 | '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out) 21 | self.assertIn('Launchpad PPA for cloud init development team', out) 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-iproute-output-v6: -------------------------------------------------------------------------------- 1 | 2a00:abcd:82ae:cd33::657 dev enp0s25 proto kernel metric 256 expires 2334sec pref medium 2 | 2a00:abcd:82ae:cd33::/64 dev enp0s25 proto ra metric 100 pref medium 3 | 2a00:abcd:82ae:cd33::/56 via fe80::32ee:54de:cd43:b4e1 dev enp0s25 proto ra metric 100 pref medium 4 | fd81:123f:654::657 dev enp0s25 proto kernel metric 256 pref medium 5 | fd81:123f:654::/64 dev enp0s25 proto ra metric 100 pref medium 6 | fd81:123f:654::/48 via fe80::32ee:54de:cd43:b4e1 dev enp0s25 proto ra metric 100 pref medium 7 | fe80::abcd:ef12:bc34:da21 dev enp0s25 proto static metric 100 pref medium 8 | fe80::/64 dev enp0s25 proto kernel metric 256 pref medium 9 | default via fe80::32ee:54de:cd43:b4e1 dev enp0s25 proto static metric 100 pref medium 10 | local ::1 dev lo table local proto none metric 0 pref medium 11 | local 2600:1f16:b80:ad00:90a:c915:bca6:5ff2 dev lo table local proto none metric 0 pref medium 12 | -------------------------------------------------------------------------------- /tools/hook-dhclient: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | # This script writes DHCP lease information into the cloud-init run directory 5 | # It is sourced, not executed. For more information see dhclient-script(8). 6 | 7 | is_azure() { 8 | local dmi_path="/sys/class/dmi/id/board_vendor" vendor="" 9 | if [ -e "$dmi_path" ] && read vendor < "$dmi_path"; then 10 | [ "$vendor" = "Microsoft Corporation" ] && return 0 11 | fi 12 | return 1 13 | } 14 | 15 | is_enabled() { 16 | # only execute hooks if cloud-init is enabled and on azure 17 | [ -e /run/cloud-init/enabled ] || return 1 18 | is_azure 19 | } 20 | 21 | if is_enabled; then 22 | case "$reason" in 23 | BOUND) cloud-init dhclient-hook up "$interface";; 24 | DOWN|RELEASE|REBOOT|STOP|EXPIRE) 25 | cloud-init dhclient-hook down "$interface";; 26 | esac 27 | fi 28 | -------------------------------------------------------------------------------- /tools/hook-rhel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | # Current versions of RHEL and CentOS do not honor the directory 5 | # /etc/dhcp/dhclient-exit-hooks.d so this file can be placed in 6 | # /etc/dhcp/dhclient.d instead 7 | is_azure() { 8 | local dmi_path="/sys/class/dmi/id/board_vendor" vendor="" 9 | if [ -e "$dmi_path" ] && read vendor < "$dmi_path"; then 10 | [ "$vendor" = "Microsoft Corporation" ] && return 0 11 | fi 12 | return 1 13 | } 14 | 15 | is_enabled() { 16 | # only execute hooks if cloud-init is enabled and on azure 17 | [ -e /run/cloud-init/enabled ] || return 1 18 | is_azure 19 | } 20 | 21 | hook-rhel_config(){ 22 | is_enabled || return 0 23 | cloud-init dhclient-hook up "$interface" 24 | } 25 | 26 | hook-rhel_restore(){ 27 | is_enabled || return 0 28 | cloud-init dhclient-hook down "$interface" 29 | } 30 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_proxy.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureProxy(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_proxy_config(self): 11 | """Test proxy options added to apt config.""" 12 | out = self.get_data_file('90cloud-init-aptproxy') 13 | self.assertIn( 14 | 'Acquire::http::Proxy "http://squid.internal:3128";', out) 15 | self.assertIn( 16 | 'Acquire::http::Proxy "http://squid.internal:3128";', out) 17 | self.assertIn( 18 | 'Acquire::ftp::Proxy "ftp://squid.internal:3128";', out) 19 | self.assertIn( 20 | 'Acquire::https::Proxy "https://squid.internal:3128";', out) 21 | 22 | # vi: ts=4 expandtab 23 | -------------------------------------------------------------------------------- /tests/data/vmware/cust-static-2nic.cfg: -------------------------------------------------------------------------------- 1 | [NETWORK] 2 | NETWORKING = yes 3 | BOOTPROTO = dhcp 4 | HOSTNAME = myhost1 5 | DOMAINNAME = eng.vmware.com 6 | 7 | [NIC-CONFIG] 8 | NICS = NIC1,NIC2 9 | 10 | [NIC1] 11 | MACADDR = 00:50:56:a6:8c:08 12 | ONBOOT = yes 13 | IPv4_MODE = BACKWARDS_COMPATIBLE 14 | BOOTPROTO = static 15 | IPADDR = 10.20.87.154 16 | NETMASK = 255.255.252.0 17 | GATEWAY = 10.20.87.253, 10.20.87.105 18 | IPv6ADDR|1 = fc00:10:20:87::154 19 | IPv6NETMASK|1 = 64 20 | IPv6GATEWAY|1 = fc00:10:20:87::253 21 | [NIC2] 22 | MACADDR = 00:50:56:a6:ef:7d 23 | ONBOOT = yes 24 | IPv4_MODE = BACKWARDS_COMPATIBLE 25 | BOOTPROTO = static 26 | IPADDR = 192.168.6.102 27 | NETMASK = 255.255.0.0 28 | GATEWAY = 192.168.0.10 29 | 30 | [DNS] 31 | DNSFROMDHCP=no 32 | SUFFIX|1 = eng.vmware.com 33 | SUFFIX|2 = proxy.vmware.com 34 | NAMESERVER|1 = 10.20.145.1 35 | NAMESERVER|2 = 10.20.145.2 36 | 37 | [DATETIME] 38 | TIMEZONE = Africa/Abidjan 39 | UTC = yes 40 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/bugs/lp1628337.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestLP1628337(base.CloudTestCase): 8 | """Test LP# 1511485.""" 9 | 10 | def test_fetch_indices(self): 11 | """Verify no apt errors.""" 12 | out = self.get_data_file('cloud-init-output.log') 13 | self.assertNotIn('W: Failed to fetch', out) 14 | self.assertNotIn('W: Some index files failed to download. ' 15 | 'They have been ignored, or old ones used instead.', 16 | out) 17 | 18 | def test_ntp(self): 19 | """Verify can find ntp and install it.""" 20 | out = self.get_data_file('cloud-init-output.log') 21 | self.assertNotIn('E: Unable to locate package ntp', out) 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_key.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureSourcesKey(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_apt_key_list(self): 11 | """Test key list updated.""" 12 | out = self.get_data_file('apt_key_list') 13 | self.assertIn( 14 | '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out) 15 | self.assertIn('Launchpad PPA for cloud init development team', out) 16 | 17 | def test_source_list(self): 18 | """Test source.list updated.""" 19 | out = self.get_data_file('sources.list') 20 | self.assertIn( 21 | 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out) 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_pools.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # NTP config using specific pools 3 | # 4 | # NOTE: lsb_release listed here because with recent cloud-init deb with 5 | # (LP: 1628337) resolved, cloud-init will attempt to configure archives. 6 | # this fails without lsb_release as UNAVAILABLE is used for $RELEASE 7 | required_features: 8 | - lsb_release 9 | cloud_config: | 10 | #cloud-config 11 | ntp: 12 | ntp_client: ntp 13 | pools: 14 | - 0.cloud-init.mypool 15 | - 1.cloud-init.mypool 16 | - 172.16.15.14 17 | collect_scripts: 18 | ntp_installed_pools: | 19 | #!/bin/bash 20 | ntpd --version > /dev/null 2>&1 21 | echo $? 22 | ntp_conf_dist_pools: | 23 | #!/bin/bash 24 | ls /etc/ntp.conf.dist | wc -l 25 | ntp_conf_pools: | 26 | #!/bin/bash 27 | grep '^pool' /etc/ntp.conf 28 | ntpq_servers: | 29 | #!/bin/sh 30 | ntpq -p -w -n 31 | 32 | # vi: ts=4 expandtab 33 | -------------------------------------------------------------------------------- /tools/.github-cla-signers: -------------------------------------------------------------------------------- 1 | ader1990 2 | ajmyyra 3 | AlexBaranowski 4 | Aman306 5 | andrewbogott 6 | andrewlukoshko 7 | antonyc 8 | aswinrajamannar 9 | beezly 10 | bipinbachhao 11 | BirknerAlex 12 | bmhughes 13 | candlerb 14 | cawamata 15 | dankenigsberg 16 | ddymko 17 | dermotbradley 18 | dhensby 19 | eandersson 20 | eb3095 21 | emmanuelthome 22 | esposem 23 | giggsoff 24 | hamalq 25 | irishgordo 26 | izzyleung 27 | johnsonshi 28 | jordimassaguerpla 29 | jqueuniet 30 | jsf9k 31 | klausenbusk 32 | landon912 33 | lucasmoura 34 | lungj 35 | mal 36 | mamercad 37 | manuelisimo 38 | marlluslustosa 39 | matthewruffell 40 | mitechie 41 | nazunalika 42 | nicolasbock 43 | nishigori 44 | olivierlemasle 45 | omBratteng 46 | onitake 47 | qubidt 48 | renanrodrigo 49 | riedel 50 | slyon 51 | smoser 52 | sshedi 53 | stappersg 54 | TheRealFalcon 55 | taoyama 56 | timothegenzmer 57 | tnt-dev 58 | tomponline 59 | tsanghan 60 | Vultaire 61 | WebSpider 62 | xiachen-rh 63 | xnox 64 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigureSourcesKeyserver(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_apt_key_list(self): 11 | """Test specific key added.""" 12 | out = self.get_data_file('apt_key_list') 13 | self.assertIn( 14 | '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out) 15 | self.assertIn('Launchpad PPA for cloud init development team', out) 16 | 17 | def test_source_list(self): 18 | """Test source.list updated.""" 19 | out = self.get_data_file('sources.list') 20 | self.assertIn( 21 | 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out) 22 | 23 | # vi: ts=4 expandtab 24 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-archive-launch-index.txt: -------------------------------------------------------------------------------- 1 | #cloud-config-archive 2 | 3 | # This is an example of a cloud archive 4 | # format which includes a set of launch indexes 5 | # that will be filtered on (thus only showing 6 | # up in instances with that launch index), this 7 | # is done by adding the 'launch-index' key which 8 | # maps to the integer 'launch-index' that the 9 | # corresponding content should be used with. 10 | # 11 | # It is possible to leave this value out which 12 | # will mean that the content will be applicable 13 | # for all instances 14 | 15 | - type: foo/wark 16 | filename: bar 17 | content: | 18 | This is my payload 19 | hello 20 | launch-index: 1 # I will only be used on launch-index 1 21 | - this is also payload 22 | - | 23 | multi line payload 24 | here 25 | - 26 | type: text/upstart-job 27 | filename: my-upstart.conf 28 | content: | 29 | whats this, yo? 30 | launch-index: 0 # I will only be used on launch-index 0 31 | -------------------------------------------------------------------------------- /systemd/cloud-init-hotplugd.service: -------------------------------------------------------------------------------- 1 | # Paired with cloud-init-hotplugd.socket to read from the FIFO 2 | # /run/cloud-init/hook-hotplug-cmd which is created during a udev network 3 | # add or remove event as processed by 10-cloud-init-hook-hotplug.rules. 4 | 5 | # On start, read args from the FIFO, process and provide structured arguments 6 | # to `cloud-init devel hotplug-hook` which will setup or teardown network 7 | # devices as configured by user-data. 8 | 9 | # Known bug with an enforcing SELinux policy: LP: #1936229 10 | # cloud-init-hotplud.service will read args from file descriptor 3 11 | 12 | [Unit] 13 | Description=cloud-init hotplug hook daemon 14 | After=cloud-init-hotplugd.socket 15 | 16 | [Service] 17 | Type=simple 18 | ExecStart=/bin/bash -c 'read args <&3; echo "args=$args"; \ 19 | exec /usr/bin/cloud-init devel hotplug-hook $args; \ 20 | exit 0' 21 | SyslogIdentifier=cloud-init-hotplugd 22 | TimeoutStopSec=5 23 | -------------------------------------------------------------------------------- /tests/data/filter_cloud_multipart_2.email: -------------------------------------------------------------------------------- 1 | From nobody Fri Aug 31 17:43:04 2012 2 | Content-Type: multipart/mixed; boundary="===============1668325974==" 3 | MIME-Version: 1.0 4 | 5 | --===============1668325974== 6 | Content-Type: text/cloud-config; charset="us-ascii" 7 | MIME-Version: 1.0 8 | Content-Transfer-Encoding: 7bit 9 | 10 | 11 | #cloud-config 12 | b: c 13 | launch-index: 2 14 | 15 | 16 | --===============1668325974== 17 | Content-Type: text/plain; charset="us-ascii" 18 | MIME-Version: 1.0 19 | Content-Transfer-Encoding: 7bit 20 | 21 | 22 | #cloud-config-archive 23 | - content: The quick brown fox jumps over the lazy dog 24 | filename: b3.txt 25 | launch-index: 3 26 | type: plain/text 27 | 28 | --===============1668325974== 29 | Content-Type: text/plain; charset="us-ascii" 30 | MIME-Version: 1.0 31 | Content-Transfer-Encoding: 7bit 32 | 33 | 34 | #cloud-config 35 | b: c 36 | launch-index: 2 37 | 38 | 39 | --===============1668325974==-- 40 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-ntp.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # ntp: configure ntp services 4 | # servers: List of NTP servers with which to sync 5 | # pools: List of NTP pool servers with which to sync (pools are typically 6 | # DNS hostnames which resolve to different specific servers to load 7 | # balance a set of services) 8 | # 9 | # Each server in the list will be added in list-order in the following format: 10 | # 11 | # [pool|server] iburst 12 | # 13 | # 14 | # If no servers or pools are defined but ntp is enabled, then cloud-init will 15 | # render the distro default list of pools 16 | # 17 | # pools = [ 18 | # '0.{distro}.pool.ntp.org', 19 | # '1.{distro}.pool.ntp.org', 20 | # '2.{distro}.pool.ntp.org', 21 | # '3.{distro}.pool.ntp.org', 22 | # ] 23 | # 24 | 25 | ntp: 26 | pools: ['0.company.pool.ntp.org', '1.company.pool.ntp.org', 'ntp.myorg.org'] 27 | servers: ['my.ntp.server.local', 'ntp.ubuntu.com', '192.168.23.2'] 28 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/zstack.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_zstack: 2 | 3 | ZStack 4 | ====== 5 | ZStack platform provides a AWS Ec2 metadata service, but with different 6 | datasource identity. 7 | More information about ZStack can be found at `ZStack `__. 8 | 9 | Discovery 10 | --------- 11 | To determine whether a vm running on ZStack platform, cloud-init checks DMI 12 | information by 'dmidecode -s chassis-asset-tag', if the output ends with 13 | '.zstack.io', it's running on ZStack platform: 14 | 15 | 16 | Metadata 17 | ^^^^^^^^ 18 | Same as EC2, instance metadata can be queried at 19 | 20 | :: 21 | 22 | GET http://169.254.169.254/2009-04-04/meta-data/ 23 | instance-id 24 | local-hostname 25 | 26 | Userdata 27 | ^^^^^^^^ 28 | Same as EC2, instance userdata can be queried at 29 | 30 | :: 31 | 32 | GET http://169.254.169.254/2009-04-04/user-data/ 33 | meta_data.json 34 | user_data 35 | password 36 | 37 | .. vi: textwidth=78 38 | -------------------------------------------------------------------------------- /templates/hosts.photon.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | {# 3 | This file /etc/cloud/templates/hosts.photon.tmpl is only utilized 4 | if enabled in cloud-config. Specifically, in order to enable it 5 | you need to add the following to config: 6 | manage_etc_hosts: True 7 | -#} 8 | # Your system has configured 'manage_etc_hosts' as True. 9 | # As a result, if you wish for changes to this file to persist 10 | # then you will need to either 11 | # a.) make changes to the master file in /etc/cloud/templates/hosts.photon.tmpl 12 | # b.) change or remove the value of 'manage_etc_hosts' in 13 | # /etc/cloud/cloud.cfg or cloud-config from user-data 14 | # 15 | # The following lines are desirable for IPv4 capable hosts 16 | 127.0.0.1 {{fqdn}} {{hostname}} 17 | 127.0.0.1 localhost.localdomain localhost 18 | 127.0.0.1 localhost4.localdomain4 localhost4 19 | 20 | # The following lines are desirable for IPv6 capable hosts 21 | ::1 {{fqdn}} {{hostname}} 22 | ::1 localhost6.localdomain6 localhost6 23 | -------------------------------------------------------------------------------- /tests/integration_tests/modules/test_seed_random_data.py: -------------------------------------------------------------------------------- 1 | """Integration test for the random seed module. 2 | 3 | This test specifies a command to be executed by the ``seed_random`` module, by 4 | providing a different data to be used as seed data. We will then check 5 | if that seed data was actually used. 6 | 7 | (This is ported from 8 | ``tests/cloud_tests/testcases/modules/seed_random_data.yaml``.)""" 9 | 10 | import pytest 11 | 12 | 13 | USER_DATA = """\ 14 | #cloud-config 15 | random_seed: 16 | data: 'MYUb34023nD:LFDK10913jk;dfnk:Df' 17 | encoding: raw 18 | file: /root/seed 19 | """ 20 | 21 | 22 | @pytest.mark.ci 23 | class TestSeedRandomData: 24 | 25 | @pytest.mark.user_data(USER_DATA) 26 | def test_seed_random_data(self, client): 27 | # Only read the first 31 characters, because the rest could be 28 | # binary data 29 | result = client.execute("head -c 31 < /root/seed") 30 | assert result.startswith("MYUb34023nD:LFDK10913jk;dfnk:Df") 31 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ssh_keys_generate.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # SSH keys generated using cloud-init 3 | # 4 | required_features: 5 | - ubuntu_user 6 | cloud_config: | 7 | #cloud-config 8 | ssh_genkeytypes: 9 | - ecdsa 10 | - ed25519 11 | authkey_hash: sha512 12 | collect_scripts: 13 | dsa_public: | 14 | #!/bin/bash 15 | cat /etc/ssh/ssh_host_dsa_key.pub 16 | dsa_private: | 17 | #!/bin/bash 18 | cat /etc/ssh/ssh_host_dsa_key 19 | rsa_public: | 20 | #!/bin/bash 21 | cat /etc/ssh/ssh_host_rsa_key.pub 22 | rsa_private: | 23 | #!/bin/bash 24 | cat /etc/ssh/ssh_host_rsa_key 25 | ecdsa_public: | 26 | #!/bin/bash 27 | cat /etc/ssh/ssh_host_ecdsa_key.pub 28 | ecdsa_private: | 29 | #!/bin/bash 30 | cat /etc/ssh/ssh_host_ecdsa_key 31 | ed25519_public: | 32 | #!/bin/bash 33 | cat /etc/ssh/ssh_host_ed25519_key.pub 34 | ed25519_private: | 35 | #!/bin/bash 36 | cat /etc/ssh/ssh_host_ed25519_key 37 | 38 | # vi: ts=4 expandtab 39 | -------------------------------------------------------------------------------- /tests/data/netinfo/netdev-formatted-output: -------------------------------------------------------------------------------- 1 | +++++++++++++++++++++++++++++++++++++++Net device info++++++++++++++++++++++++++++++++++++++++ 2 | +---------+------+------------------------------+---------------+--------+-------------------+ 3 | | Device | Up | Address | Mask | Scope | Hw-Address | 4 | +---------+------+------------------------------+---------------+--------+-------------------+ 5 | | enp0s25 | True | 192.168.2.18 | 255.255.255.0 | . | 50:7b:9d:2c:af:91 | 6 | | enp0s25 | True | fe80::7777:2222:1111:eeee/64 | . | global | 50:7b:9d:2c:af:91 | 7 | | enp0s25 | True | fe80::8107:2b92:867e:f8a6/64 | . | link | 50:7b:9d:2c:af:91 | 8 | | lo | True | 127.0.0.1 | 255.0.0.0 | . | . | 9 | | lo | True | ::1/128 | . | host | . | 10 | +---------+------+------------------------------+---------------+--------+-------------------+ 11 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/ntp_chrony.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | import unittest 5 | 6 | from tests.cloud_tests.testcases import base 7 | 8 | 9 | class TestNtpChrony(base.CloudTestCase): 10 | """Test ntp module with chrony client""" 11 | 12 | def setUp(self): 13 | """Skip this suite of tests on lxd and artful or older.""" 14 | if self.platform == 'lxd': 15 | if self.is_distro('ubuntu') and self.os_version_cmp('artful') <= 0: 16 | raise unittest.SkipTest( 17 | 'No support for chrony on containers <= artful.' 18 | ' LP: #1589780') 19 | return super(TestNtpChrony, self).setUp() 20 | 21 | def test_chrony_entries(self): 22 | """Test chrony config entries""" 23 | out = self.get_data_file('chrony_conf') 24 | self.assertIn('.pool.ntp.org', out) 25 | 26 | # vi: ts=4 expandtab 27 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark and close stale pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" # Daily @ 00:00 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v1 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | days-before-stale: 14 17 | days-before-close: 7 18 | stale-pr-message: | 19 | Hello! Thank you for this proposed change to cloud-init. This pull request is now marked as stale as it has not seen any activity in 14 days. If no activity occurs within the next 7 days, this pull request will automatically close. 20 | 21 | If you are waiting for code review and you are seeing this message, apologies! Please reply, tagging mitechie, and he will ensure that someone takes a look soon. 22 | 23 | (If the pull request is closed and you would like to continue working on it, please do tag mitechie to reopen it.) 24 | stale-pr-label: 'stale-pr' 25 | -------------------------------------------------------------------------------- /templates/hosts.freebsd.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | {# 3 | This file /etc/cloud/templates/hosts.freebsd.tmpl is only utilized 4 | if enabled in cloud-config. Specifically, in order to enable it 5 | you need to add the following to config: 6 | manage_etc_hosts: True 7 | -#} 8 | # Your system has configured 'manage_etc_hosts' as True. 9 | # As a result, if you wish for changes to this file to persist 10 | # then you will need to either 11 | # a.) make changes to the master file in /etc/cloud/templates/hosts.freebsd.tmpl 12 | # b.) change or remove the value of 'manage_etc_hosts' in 13 | # /etc/cloud/cloud.cfg or cloud-config from user-data 14 | 15 | # The following lines are desirable for IPv6 capable hosts 16 | ::1 {{fqdn}} {{hostname}} 17 | ::1 localhost.localdomain localhost 18 | ::1 localhost6.localdomain6 localhost6 19 | 20 | # The following lines are desirable for IPv4 capable hosts 21 | 127.0.0.1 {{fqdn}} {{hostname}} 22 | 127.0.0.1 localhost.localdomain localhost 23 | 127.0.0.1 localhost4.localdomain4 localhost4 24 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/apt_configure_primary.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestAptconfigurePrimary(base.CloudTestCase): 8 | """Test apt-configure module.""" 9 | 10 | def test_ubuntu_sources(self): 11 | """Test no default Ubuntu entries exist.""" 12 | out = self.get_data_file('sources.list') 13 | ubuntu_source_count = len( 14 | [line for line in out.split('\n') if 'archive.ubuntu.com' in line]) 15 | self.assertEqual(0, ubuntu_source_count) 16 | 17 | def test_gatech_sources(self): 18 | """Test GaTech entries exist.""" 19 | out = self.get_data_file('sources.list') 20 | gatech_source_count = len( 21 | [line for line in out.split('\n') if 'gtlib.gatech.edu' in line]) 22 | self.assertGreater(gatech_source_count, 0) 23 | 24 | # vi: ts=4 expandtab 25 | -------------------------------------------------------------------------------- /templates/hosts.debian.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | {# 3 | This file (/etc/cloud/templates/hosts.debian.tmpl) is only utilized 4 | if enabled in cloud-config. Specifically, in order to enable it 5 | you need to add the following to config: 6 | manage_etc_hosts: True 7 | -#} 8 | # Your system has configured 'manage_etc_hosts' as True. 9 | # As a result, if you wish for changes to this file to persist 10 | # then you will need to either 11 | # a.) make changes to the master file in /etc/cloud/templates/hosts.debian.tmpl 12 | # b.) change or remove the value of 'manage_etc_hosts' in 13 | # /etc/cloud/cloud.cfg or cloud-config from user-data 14 | # 15 | {# The value '{{hostname}}' will be replaced with the local-hostname -#} 16 | 127.0.1.1 {{fqdn}} {{hostname}} 17 | 127.0.0.1 localhost 18 | 19 | # The following lines are desirable for IPv6 capable hosts 20 | ::1 ip6-localhost ip6-loopback 21 | fe00::0 ip6-localnet 22 | ff00::0 ip6-mcastprefix 23 | ff02::1 ip6-allnodes 24 | ff02::2 ip6-allrouters 25 | ff02::3 ip6-allhosts 26 | 27 | -------------------------------------------------------------------------------- /templates/hosts.redhat.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | {# 3 | This file /etc/cloud/templates/hosts.redhat.tmpl is only utilized 4 | if enabled in cloud-config. Specifically, in order to enable it 5 | you need to add the following to config: 6 | manage_etc_hosts: True 7 | -#} 8 | # Your system has configured 'manage_etc_hosts' as True. 9 | # As a result, if you wish for changes to this file to persist 10 | # then you will need to either 11 | # a.) make changes to the master file in /etc/cloud/templates/hosts.redhat.tmpl 12 | # b.) change or remove the value of 'manage_etc_hosts' in 13 | # /etc/cloud/cloud.cfg or cloud-config from user-data 14 | # 15 | # The following lines are desirable for IPv4 capable hosts 16 | 127.0.0.1 {{fqdn}} {{hostname}} 17 | 127.0.0.1 localhost.localdomain localhost 18 | 127.0.0.1 localhost4.localdomain4 localhost4 19 | 20 | # The following lines are desirable for IPv6 capable hosts 21 | ::1 {{fqdn}} {{hostname}} 22 | ::1 localhost.localdomain localhost 23 | ::1 localhost6.localdomain6 localhost6 24 | 25 | -------------------------------------------------------------------------------- /tests/data/filter_cloud_multipart.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config-archive 2 | --- 3 | - content: "\n blah: true\n launch-index: 3\n" 4 | type: text/cloud-config 5 | - content: "\n blah: true\n launch-index: 4\n" 6 | type: text/cloud-config 7 | - content: The quick brown fox jumps over the lazy dog 8 | filename: b0.txt 9 | launch-index: 0 10 | type: plain/text 11 | - content: The quick brown fox jumps over the lazy dog 12 | filename: b3.txt 13 | launch-index: 3 14 | type: plain/text 15 | - content: The quick brown fox jumps over the lazy dog 16 | filename: b2.txt 17 | launch-index: 2 18 | type: plain/text 19 | - content: '#!/bin/bash \n echo "stuff"' 20 | filename: b2.txt 21 | launch-index: 2 22 | - content: '#!/bin/bash \n echo "stuff"' 23 | filename: b2.txt 24 | launch-index: 1 25 | - content: '#!/bin/bash \n echo "stuff"' 26 | filename: b2.txt 27 | # Use a string to see if conversion works 28 | launch-index: "1" 29 | ... 30 | 31 | -------------------------------------------------------------------------------- /tools/Z99-cloudinit-warnings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | # Purpose: show user warnings on login. 5 | 6 | cloud_init_warnings() { 7 | command -v local >/dev/null && local _local="local" || 8 | typeset _local="typeset" 9 | $_local warning="" idir="/var/lib/cloud/instance" n=0 10 | $_local warndir="$idir/warnings" 11 | $_local ufile="$HOME/.cloud-warnings.skip" sfile="$warndir/.skip" 12 | [ -d "$warndir" ] || return 0 13 | [ ! -f "$ufile" ] || return 0 14 | [ ! -f "$sfile" ] || return 0 15 | 16 | for warning in "$warndir"/*; do 17 | [ -f "$warning" ] || continue 18 | cat "$warning" 19 | n=$((n+1)) 20 | done 21 | [ $n -eq 0 ] && return 0 22 | echo "" 23 | echo "Disable the warnings above by:" 24 | echo " touch $ufile" 25 | echo "or" 26 | echo " touch $sfile" 27 | } 28 | 29 | cloud_init_warnings 1>&2 30 | unset cloud_init_warnings 31 | 32 | # vi: syntax=sh ts=4 expandtab 33 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/upcloud.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_upcloud: 2 | 3 | UpCloud 4 | ============= 5 | 6 | The `UpCloud`_ datasource consumes information from UpCloud's `metadata 7 | service`_. This metadata service serves information about the 8 | running server via HTTP over the address 169.254.169.254 available in every 9 | DHCP-configured interface. The metadata API endpoints are fully described in 10 | UpCloud API documentation at 11 | `https://developers.upcloud.com/1.3/8-servers/#metadata-service 12 | `_. 13 | 14 | Providing user-data 15 | ------------------- 16 | 17 | When creating a server, user-data is provided by specifying it as `user_data` 18 | in the API or via the server creation tool in the control panel. User-data is 19 | immutable during server's lifetime and can be removed by deleting the server. 20 | 21 | .. _UpCloud: https://upcloud.com/ 22 | .. _metadata service: https://upcloud.com/community/tutorials/upcloud-metadata-service/ 23 | 24 | .. vi: textwidth=78 25 | -------------------------------------------------------------------------------- /tests/data/netinfo/new-ifconfig-output: -------------------------------------------------------------------------------- 1 | enp0s25: flags=4163 mtu 1500 2 | inet 192.168.2.18 netmask 255.255.255.0 broadcast 192.168.2.255 3 | inet6 fe80::7777:2222:1111:eeee prefixlen 64 scopeid 0x30 4 | inet6 fe80::8107:2b92:867e:f8a6 prefixlen 64 scopeid 0x20 5 | ether 50:7b:9d:2c:af:91 txqueuelen 1000 (Ethernet) 6 | RX packets 3017 bytes 10601563 (10.1 MiB) 7 | RX errors 0 dropped 39 overruns 0 frame 0 8 | TX packets 2627 bytes 196976 (192.3 KiB) 9 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 10 | 11 | lo: flags=73 mtu 65536 12 | inet 127.0.0.1 netmask 255.0.0.0 13 | inet6 ::1 prefixlen 128 scopeid 0x10 14 | loop txqueuelen 1 (Local Loopback) 15 | RX packets 0 bytes 0 (0.0 B) 16 | RX errors 0 dropped 0 overruns 0 frame 0 17 | TX packets 0 bytes 0 (0.0 B) 18 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 19 | -------------------------------------------------------------------------------- /tests/data/mountinfo_raring_btrfs.txt: -------------------------------------------------------------------------------- 1 | 15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw 2 | 16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 3 | 17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=865556k,nr_inodes=216389,mode=755 4 | 18 17 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 5 | 19 20 0:15 / /run rw,nosuid,relatime - tmpfs tmpfs rw,size=348196k,mode=755 6 | 20 1 0:16 /@ / rw,relatime - btrfs /dev/vda1 rw,compress=lzo,space_cache 7 | 21 15 0:19 / /sys/fs/fuse/connections rw,relatime - fusectl none rw 8 | 22 15 0:6 / /sys/kernel/debug rw,relatime - debugfs none rw 9 | 23 15 0:10 / /sys/kernel/security rw,relatime - securityfs none rw 10 | 24 19 0:20 / /run/lock rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=5120k 11 | 25 19 0:21 / /run/shm rw,nosuid,nodev,relatime - tmpfs none rw 12 | 26 19 0:22 / /run/user rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=102400k,mode=755 13 | 27 20 0:16 /@home /home rw,relatime - btrfs /dev/vda1 rw,compress=lzo,space_cache 14 | -------------------------------------------------------------------------------- /tests/integration_tests/bugs/test_lp1897099.py: -------------------------------------------------------------------------------- 1 | """ Integration test for LP #187099 2 | 3 | Ensure that if fallocate fails during mkswap that we fall back to using dd 4 | 5 | https://bugs.launchpad.net/cloud-init/+bug/1897099 6 | """ 7 | 8 | import pytest 9 | 10 | 11 | USER_DATA = """\ 12 | #cloud-config 13 | bootcmd: 14 | - echo 'whoops' > /usr/bin/fallocate 15 | swap: 16 | filename: /swap.img 17 | size: 10000000 18 | maxsize: 10000000 19 | """ 20 | 21 | 22 | @pytest.mark.sru_2020_11 23 | @pytest.mark.user_data(USER_DATA) 24 | @pytest.mark.no_container('Containers cannot configure swap') 25 | def test_fallocate_fallback(client): 26 | log = client.read_from_file('/var/log/cloud-init.log') 27 | assert '/swap.img' in client.execute('cat /proc/swaps') 28 | assert '/swap.img' in client.execute('cat /etc/fstab') 29 | assert 'fallocate swap creation failed, will attempt with dd' in log 30 | assert "Running command ['dd', 'if=/dev/zero', 'of=/swap.img'" in log 31 | assert 'SUCCESS: config-mounts ran successfully' in log 32 | -------------------------------------------------------------------------------- /tests/data/netinfo/old-ifconfig-output: -------------------------------------------------------------------------------- 1 | enp0s25 Link encap:Ethernet HWaddr 50:7b:9d:2c:af:91 2 | inet addr:192.168.2.18 Bcast:192.168.2.255 Mask:255.255.255.0 3 | inet6 addr: fe80::7777:2222:1111:eeee/64 Scope:Global 4 | inet6 addr: fe80::8107:2b92:867e:f8a6/64 Scope:Link 5 | UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 6 | RX packets:8106427 errors:55 dropped:0 overruns:0 frame:37 7 | TX packets:9339739 errors:0 dropped:0 overruns:0 carrier:0 8 | collisions:0 txqueuelen:1000 9 | RX bytes:4953721719 (4.9 GB) TX bytes:7731890194 (7.7 GB) 10 | Interrupt:20 Memory:e1200000-e1220000 11 | 12 | lo Link encap:Local Loopback 13 | inet addr:127.0.0.1 Mask:255.0.0.0 14 | inet6 addr: ::1/128 Scope:Host 15 | UP LOOPBACK RUNNING MTU:65536 Metric:1 16 | RX packets:579230851 errors:0 dropped:0 overruns:0 frame:0 17 | TX packets:579230851 errors:0 dropped:0 overruns:0 carrier:0 18 | collisions:0 txqueuelen:1 19 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/package_update_upgrade_install.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Update/upgrade via apt and then install a pair of packages 3 | # 4 | # NOTE: this should not require apt feature, use 'which' rather than 'dpkg -l' 5 | # NOTE: the testcase for this looks for the command in history.log as 6 | # /usr/bin/apt-get..., which is not how it always appears. it should 7 | # instead look for just apt-get... 8 | # NOTE: this testcase should not require 'apt_up_out', and should look for a 9 | # call to 'apt-get upgrade' or 'apt-get dist-upgrade' in cloud-init.log 10 | # rather than 'Calculating upgrade...' in output 11 | required_features: 12 | - apt 13 | - apt_hist_fmt 14 | - apt_up_out 15 | cloud_config: | 16 | #cloud-config 17 | packages: 18 | - sl 19 | - tree 20 | package_update: true 21 | package_upgrade: true 22 | collect_scripts: 23 | apt_history_cmdline: | 24 | #!/bin/bash 25 | grep ^Commandline: /var/log/apt/history.log 26 | dpkg_show: | 27 | #!/bin/bash 28 | dpkg-query --show 29 | 30 | # vi: ts=4 expandtab 31 | -------------------------------------------------------------------------------- /tests/integration_tests/bugs/test_lp1900837.py: -------------------------------------------------------------------------------- 1 | """Integration test for LP: #1900836. 2 | 3 | This test mirrors the reproducing steps from the reported bug: it changes the 4 | permissions on cloud-init.log to 600 and confirms that they remain 600 after a 5 | reboot. 6 | """ 7 | import pytest 8 | 9 | 10 | def _get_log_perms(client): 11 | return client.execute("stat -c %a /var/log/cloud-init.log") 12 | 13 | 14 | @pytest.mark.sru_2020_11 15 | class TestLogPermissionsNotResetOnReboot: 16 | def test_permissions_unchanged(self, client): 17 | # Confirm that the current permissions aren't 600 18 | assert "644" == _get_log_perms(client) 19 | 20 | # Set permissions to 600 and confirm our assertion passes pre-reboot 21 | client.execute("chmod 600 /var/log/cloud-init.log") 22 | assert "600" == _get_log_perms(client) 23 | 24 | # Reboot 25 | client.restart() 26 | assert client.execute('cloud-init status').ok 27 | 28 | # Check that permissions are not reset on reboot 29 | assert "600" == _get_log_perms(client) 30 | -------------------------------------------------------------------------------- /tools/.lp-to-git-user: -------------------------------------------------------------------------------- 1 | { 2 | "adobrawy": "ad-m", 3 | "afranceschini": "andreaf74", 4 | "ahosmanmsft": "AOhassan", 5 | "andreipoltavchenko": "pa-yourserveradmin-com", 6 | "askon": "ask0n", 7 | "b1sandmann": "B1Sandmann", 8 | "bitfehler": "bitfehler", 9 | "chad.smith": "blackboxsw", 10 | "chcheng": "chengcheng-chcheng", 11 | "d-info-e": "do3meli", 12 | "daniel-thewatkins": "OddBloke", 13 | "eric-lafontaine1": "elafontaine", 14 | "fredlefebvre": "fred-lefebvre", 15 | "goneri": "goneri", 16 | "harald-jensas": "hjensas", 17 | "i.galic": "igalic", 18 | "kgarloff": "garloff", 19 | "killermoehre": "killermoehre", 20 | "larsks": "larsks", 21 | "legovini": "paride", 22 | "louis": "karibou", 23 | "lp-markusschade": "asciiprod", 24 | "madhuri-rai07": "madhuri-rai07", 25 | "momousta": "Moustafa-Moustafa", 26 | "otubo": "otubo", 27 | "pengpengs": "PengpengSun", 28 | "powersj": "powersj", 29 | "raharper": "raharper", 30 | "rjschwei": "rjschwei", 31 | "tribaal": "chrisglass", 32 | "trstringer": "trstringer", 33 | "vtqanh": "anhvoms", 34 | "xiaofengw": "xiaofengw-vmware" 35 | } 36 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-run-cmds.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # run commands 4 | # default: none 5 | # runcmd contains a list of either lists or a string 6 | # each item will be executed in order at rc.local like level with 7 | # output to the console 8 | # - runcmd only runs during the first boot 9 | # - if the item is a list, the items will be properly executed as if 10 | # passed to execve(3) (with the first arg as the command). 11 | # - if the item is a string, it will be simply written to the file and 12 | # will be interpreted by 'sh' 13 | # 14 | # Note, that the list has to be proper yaml, so you have to quote 15 | # any characters yaml would eat (':' can be problematic) 16 | runcmd: 17 | - [ ls, -l, / ] 18 | - [ sh, -xc, "echo $(date) ': hello world!'" ] 19 | - [ sh, -c, echo "=========hello world'=========" ] 20 | - ls -l /root 21 | # Note: Don't write files to /tmp from cloud-init use /run/somedir instead. 22 | # Early boot environments can race systemd-tmpfiles-clean LP: #1707222. 23 | - mkdir /run/mydir 24 | - [ wget, "http://slashdot.org", -O, /run/mydir/index.html ] 25 | 26 | -------------------------------------------------------------------------------- /tests/data/netinfo/sample-route-output-v6: -------------------------------------------------------------------------------- 1 | Kernel IPv6 routing table 2 | Destination Next Hop Flag Met Re Use If 3 | 2a00:abcd:82ae:cd33::657/128 :: Ue 256 1 0 enp0s25 4 | 2a00:abcd:82ae:cd33::/64 :: U 100 1 0 enp0s25 5 | 2a00:abcd:82ae:cd33::/56 fe80::32ee:54de:cd43:b4e1 UG 100 1 0 enp0s25 6 | fd81:123f:654::657/128 :: U 256 1 0 enp0s25 7 | fd81:123f:654::/64 :: U 100 1 0 enp0s25 8 | fd81:123f:654::/48 fe80::32ee:54de:cd43:b4e1 UG 100 1 0 enp0s25 9 | fe80::abcd:ef12:bc34:da21/128 :: U 100 1 2 enp0s25 10 | fe80::/64 :: U 256 1 16880 enp0s25 11 | ::/0 fe80::32ee:54de:cd43:b4e1 UG 100 1 0 enp0s25 12 | ::/0 :: !n -1 1424956 lo 13 | ::1/128 :: Un 0 4 26289 lo 14 | -------------------------------------------------------------------------------- /templates/resolv.conf.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # Your system has been configured with 'manage-resolv-conf' set to true. 3 | # As a result, cloud-init has written this file with configuration data 4 | # that it has been provided. Cloud-init, by default, will write this file 5 | # a single time (PER_ONCE). 6 | # 7 | {% if nameservers is defined %} 8 | {% for server in nameservers %} 9 | nameserver {{server}} 10 | {% endfor %} 11 | 12 | {% endif -%} 13 | {% if searchdomains is defined %} 14 | search {% for search in searchdomains %}{{search}} {% endfor %} 15 | 16 | {% endif %} 17 | {% if domain is defined %} 18 | domain {{domain}} 19 | {% endif %} 20 | {% if sortlist is defined %} 21 | 22 | sortlist {% for sort in sortlist %}{{sort}} {% endfor %} 23 | {% endif %} 24 | {# 25 | Flags and options are required to be on the 26 | same line preceded by "options" keyword 27 | #} 28 | {% if options or flags %} 29 | 30 | options 31 | {%- for flag in flags %} 32 | {{flag-}} 33 | {% endfor %} 34 | 35 | {%- for key, value in options.items()|sort %} 36 | {{key}}:{{value-}} 37 | {% endfor %} 38 | {% endif %} 39 | -------------------------------------------------------------------------------- /tools/cloudconfig-schema: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # This file is part of cloud-init. See LICENSE file for license information. 3 | 4 | """cloudconfig-schema 5 | 6 | Validate existing files against cloud-config schema or provide supported schema 7 | documentation. 8 | """ 9 | 10 | import os 11 | import sys 12 | 13 | 14 | def call_entry_point(name): 15 | (istr, dot, ent) = name.rpartition('.') 16 | try: 17 | __import__(istr) 18 | except ImportError: 19 | # if that import failed, check dirname(__file__/..) 20 | # to support ./bin/program with modules in . 21 | _tdir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) 22 | sys.path.insert(0, _tdir) 23 | try: 24 | __import__(istr) 25 | except ImportError as e: 26 | sys.stderr.write("Unable to find %s: %s\n" % (name, e)) 27 | sys.exit(2) 28 | 29 | sys.exit(getattr(sys.modules[istr], ent)()) 30 | 31 | 32 | if __name__ == '__main__': 33 | call_entry_point("cloudinit.config.schema.main") 34 | 35 | # vi: ts=4 expandtab syntax=python 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Pypi requirements for cloud-init to work 2 | 3 | # Used for untemplating any files or strings with parameters. 4 | jinja2 5 | 6 | # This one is currently only used by the MAAS datasource. If that 7 | # datasource is removed, this is no longer needed 8 | oauthlib 9 | 10 | # This one is currently used only by the CloudSigma and SmartOS datasources. 11 | # If these datasources are removed, this is no longer needed. 12 | # 13 | # This will not work in py2.6 so it is only optionally installed on 14 | # python 2.7 and later. 15 | # 16 | # pyserial 17 | 18 | # This is only needed for places where we need to support configs in a manner 19 | # that the built-in config parser is not sufficent (ie 20 | # when we need to preserve comments, or do not have a top-level 21 | # section)... 22 | configobj>=5.0.2 23 | 24 | # All new style configurations are in the yaml format 25 | pyyaml 26 | 27 | # Requests handles ssl correctly! 28 | requests 29 | 30 | # For patching pieces of cloud-config together 31 | jsonpatch 32 | 33 | # For validating cloud-config sections per schema definitions 34 | jsonschema 35 | -------------------------------------------------------------------------------- /templates/hosts.alpine.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | {# 3 | This file /etc/cloud/templates/hosts.alpine.tmpl is only utilized 4 | if enabled in cloud-config. Specifically, in order to enable it 5 | you need to add the following to config: 6 | manage_etc_hosts: True 7 | -#} 8 | # Your system has configured 'manage_etc_hosts' as True. 9 | # As a result, if you wish for changes to this file to persist 10 | # then you will need to either 11 | # a.) make changes to the master file in /etc/cloud/templates/hosts.alpine.tmpl 12 | # b.) change or remove the value of 'manage_etc_hosts' in 13 | # /etc/cloud/cloud.cfg or cloud-config from user-data 14 | # 15 | # The following lines are desirable for IPv4 capable hosts 16 | 127.0.1.1 {{fqdn}} {{hostname}} 17 | 127.0.0.1 localhost.localdomain localhost 18 | 127.0.0.1 localhost4.localdomain4 localhost4 19 | 20 | # The following lines are desirable for IPv6 capable hosts 21 | ::1 {{fqdn}} {{hostname}} 22 | ::1 localhost6.localdomain6 localhost6 23 | 24 | fe00::0 ip6-localnet 25 | ff00::0 ip6-mcastprefix 26 | ff02::1 ip6-allnodes 27 | ff02::2 ip6-allrouters 28 | ff02::3 ip6-allhosts 29 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/locale.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | from cloudinit import util 7 | 8 | 9 | class TestLocale(base.CloudTestCase): 10 | """Test locale is set properly.""" 11 | 12 | def test_locale(self): 13 | """Test locale is set properly.""" 14 | data = util.load_shell_content(self.get_data_file('locale_default')) 15 | self.assertIn("LANG", data) 16 | self.assertEqual('en_GB.UTF-8', data['LANG']) 17 | 18 | def test_locale_a(self): 19 | """Test locale -a has both options.""" 20 | out = self.get_data_file('locale_a') 21 | self.assertIn('en_GB.utf8', out) 22 | self.assertIn('en_US.utf8', out) 23 | 24 | def test_locale_gen(self): 25 | """Test local.gen file has all entries.""" 26 | out = self.get_data_file('locale_gen') 27 | self.assertIn('en_GB.UTF-8', out) 28 | self.assertIn('en_US.UTF-8', out) 29 | 30 | # vi: ts=4 expandtab 31 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/lxd_dir.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestLxdDir(base.CloudTestCase): 8 | """Test LXD module.""" 9 | 10 | @classmethod 11 | def maybeSkipTest(cls): 12 | """Skip on cosmic for two reasons: 13 | a.) LP: #1795036 - 'lxd init' fails on cosmic kernel. 14 | b.) apt install lxd installs via snap which can be slow 15 | as that will download core snap and lxd.""" 16 | os_name = cls.data.get('os_name', 'UNKNOWN') 17 | if os_name == "cosmic": 18 | raise base.SkipTest('Skipping test on cosmic (LP: #1795036).') 19 | 20 | def test_lxd(self): 21 | """Test lxd installed.""" 22 | out = self.get_data_file('lxd') 23 | self.assertIn('/lxd', out) 24 | 25 | def test_lxc(self): 26 | """Test lxc installed.""" 27 | out = self.get_data_file('lxc') 28 | self.assertIn('/lxc', out) 29 | 30 | # vi: ts=4 expandtab 31 | -------------------------------------------------------------------------------- /cloudinit/mergers/m_str.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Yahoo! Inc. 2 | # 3 | # Author: Joshua Harlow 4 | # 5 | # This file is part of cloud-init. See LICENSE file for license information. 6 | 7 | 8 | class Merger(object): 9 | def __init__(self, _merger, opts): 10 | self._append = 'append' in opts 11 | 12 | def __str__(self): 13 | return 'StringMerger: (append=%s)' % (self._append) 14 | 15 | # On encountering a unicode object to merge value with 16 | # we will for now just proxy into the string method to let it handle it. 17 | def _on_unicode(self, value, merge_with): 18 | return self._on_str(value, merge_with) 19 | 20 | # On encountering a string object to merge with we will 21 | # perform the following action, if appending we will 22 | # merge them together, otherwise we will just return value. 23 | def _on_str(self, value, merge_with): 24 | if not isinstance(value, str): 25 | return merge_with 26 | if not self._append: 27 | return merge_with 28 | return value + merge_with 29 | 30 | # vi: ts=4 expandtab 31 | -------------------------------------------------------------------------------- /doc/examples/kernel-cmdline.txt: -------------------------------------------------------------------------------- 1 | cloud-config can be provided via the kernel command line. 2 | configuration that comes from the kernel command line has higher priority 3 | than configuration in /etc/cloud/cloud.cfg 4 | 5 | The format is: 6 | cc: [end_cc] 7 | 8 | cloud-config will consider any content after 'cc:' to be cloud-config 9 | data. If an 'end_cc' string is present, then it will stop reading there. 10 | otherwise it considers everthing after 'cc:' to be cloud-config content. 11 | 12 | In order to allow carriage returns, you must enter '\\n', literally, 13 | on the command line two backslashes followed by a letter 'n'. 14 | 15 | The yaml content may also be URL encoded (urllib.parse.quote()). 16 | 17 | Here are some examples: 18 | root=/dev/sda1 cc: ssh_import_id: [smoser, kirkland]\\n 19 | root=LABEL=uec-rootfs cc: ssh_import_id: [smoser, bob]\\nruncmd: [ [ ls, -l ], echo hi ] end_cc 20 | cc:ssh_import_id: [smoser] end_cc cc:runcmd: [ [ ls, -l ] ] end_cc root=/dev/sda1 21 | cc:ssh_import_id: %5Bsmoser%5D end_cc cc:runcmd: %5B %5B ls, -l %5D %5D end_cc root=/dev/sda1 22 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/modules/set_hostname_fqdn.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests import CI_DOMAIN 5 | from tests.cloud_tests.testcases import base 6 | 7 | 8 | class TestHostnameFqdn(base.CloudTestCase): 9 | """Test Hostname module.""" 10 | 11 | ex_hostname = "cloudinit1" 12 | ex_fqdn = "cloudinit2." + CI_DOMAIN 13 | 14 | def test_hostname(self): 15 | """Test hostname output.""" 16 | out = self.get_data_file('hostname') 17 | self.assertIn(self.ex_hostname, out) 18 | 19 | def test_hostname_fqdn(self): 20 | """Test hostname fqdn output.""" 21 | out = self.get_data_file('fqdn') 22 | self.assertIn(self.ex_fqdn, out) 23 | 24 | def test_hosts(self): 25 | """Test /etc/hosts file.""" 26 | out = self.get_data_file('hosts') 27 | self.assertIn('127.0.1.1 %s %s' % (self.ex_fqdn, self.ex_hostname), 28 | out) 29 | self.assertIn('127.0.0.1 localhost', out) 30 | 31 | # vi: ts=4 expandtab 32 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/vultr.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_vultr: 2 | 3 | Vultr 4 | ===== 5 | 6 | The `Vultr`_ datasource retrieves basic configuration values from the locally 7 | accessible `metadata service`_. All data is served over HTTP from the address 8 | 169.254.169.254. The endpoints are documented in, 9 | `https://www.vultr.com/metadata/ 10 | `_ 11 | 12 | Configuration 13 | ------------- 14 | 15 | Vultr's datasource can be configured as follows: 16 | 17 | datasource: 18 | Vultr: 19 | url: 'http://169.254.169.254' 20 | retries: 3 21 | timeout: 2 22 | wait: 2 23 | 24 | - *url*: The URL used to aquire the metadata configuration from 25 | - *retries*: Determines the number of times to attempt to connect to the 26 | metadata service 27 | - *timeout*: Determines the timeout in seconds to wait for a response from the 28 | metadata service 29 | - *wait*: Determines the timeout in seconds to wait before retrying after 30 | accessible failure 31 | 32 | .. _Vultr: https://www.vultr.com/ 33 | .. _metadata service: https://www.vultr.com/metadata/ 34 | 35 | .. vi: textwidth=78 36 | -------------------------------------------------------------------------------- /doc/examples/cloud-config-growpart.txt: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # 3 | # growpart entry is a dict, if it is not present at all 4 | # in config, then the default is used ({'mode': 'auto', 'devices': ['/']}) 5 | # 6 | # mode: 7 | # values: 8 | # * auto: use any option possible (any available) 9 | # if none are available, do not warn, but debug. 10 | # * growpart: use growpart to grow partitions 11 | # if growpart is not available, this is an error. 12 | # * off, false 13 | # 14 | # devices: 15 | # a list of things to resize. 16 | # items can be filesystem paths or devices (in /dev) 17 | # examples: 18 | # devices: [/, /dev/vdb1] 19 | # 20 | # ignore_growroot_disabled: 21 | # a boolean, default is false. 22 | # if the file /etc/growroot-disabled exists, then cloud-init will not grow 23 | # the root partition. This is to allow a single file to disable both 24 | # cloud-initramfs-growroot and cloud-init's growroot support. 25 | # 26 | # true indicates that /etc/growroot-disabled should be ignored 27 | # 28 | growpart: 29 | mode: auto 30 | devices: ['/'] 31 | ignore_growroot_disabled: false 32 | -------------------------------------------------------------------------------- /doc/rtd/topics/datasources/digitalocean.rst: -------------------------------------------------------------------------------- 1 | .. _datasource_digital_ocean: 2 | 3 | DigitalOcean 4 | ============ 5 | 6 | The `DigitalOcean`_ datasource consumes the content served from DigitalOcean's 7 | `metadata service`_. This metadata service serves information about the 8 | running droplet via HTTP over the link local address 169.254.169.254. The 9 | metadata API endpoints are fully described at 10 | `https://developers.digitalocean.com/metadata/ 11 | `_. 12 | 13 | Configuration 14 | ------------- 15 | 16 | DigitalOcean's datasource can be configured as follows: 17 | 18 | datasource: 19 | DigitalOcean: 20 | retries: 3 21 | timeout: 2 22 | 23 | - *retries*: Determines the number of times to attempt to connect to the 24 | metadata service 25 | - *timeout*: Determines the timeout in seconds to wait for a response from the 26 | metadata service 27 | 28 | .. _DigitalOcean: http://digitalocean.com/ 29 | .. _metadata service: https://developers.digitalocean.com/metadata/ 30 | .. _Full documentation: https://developers.digitalocean.com/metadata/ 31 | 32 | .. vi: textwidth=78 33 | -------------------------------------------------------------------------------- /tests/unittests/test_distros/test_gentoo.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | from cloudinit import util 4 | from cloudinit import atomic_helper 5 | from cloudinit.tests.helpers import CiTestCase 6 | from . import _get_distro 7 | 8 | 9 | class TestGentoo(CiTestCase): 10 | 11 | def test_write_hostname(self): 12 | distro = _get_distro("gentoo") 13 | hostname = "myhostname" 14 | hostfile = self.tmp_path("hostfile") 15 | distro._write_hostname(hostname, hostfile) 16 | self.assertEqual('hostname="myhostname"\n', util.load_file(hostfile)) 17 | 18 | def test_write_existing_hostname_with_comments(self): 19 | distro = _get_distro("gentoo") 20 | hostname = "myhostname" 21 | contents = '#This is the hostname\nhostname="localhost"' 22 | hostfile = self.tmp_path("hostfile") 23 | atomic_helper.write_file(hostfile, contents, omode="w") 24 | distro._write_hostname(hostname, hostfile) 25 | self.assertEqual('#This is the hostname\nhostname="myhostname"\n', 26 | util.load_file(hostfile)) 27 | -------------------------------------------------------------------------------- /cloudinit/tests/test_event.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | """Tests related to cloudinit.event module.""" 3 | from cloudinit.event import EventType, EventScope, userdata_to_events 4 | 5 | 6 | class TestEvent: 7 | def test_userdata_to_events(self): 8 | userdata = {'network': {'when': ['boot']}} 9 | expected = {EventScope.NETWORK: {EventType.BOOT}} 10 | assert expected == userdata_to_events(userdata) 11 | 12 | def test_invalid_scope(self, caplog): 13 | userdata = {'networkasdfasdf': {'when': ['boot']}} 14 | userdata_to_events(userdata) 15 | assert ( 16 | "'networkasdfasdf' is not a valid EventScope! Update data " 17 | "will be ignored for 'networkasdfasdf' scope" 18 | ) in caplog.text 19 | 20 | def test_invalid_event(self, caplog): 21 | userdata = {'network': {'when': ['bootasdfasdf']}} 22 | userdata_to_events(userdata) 23 | assert ( 24 | "'bootasdfasdf' is not a valid EventType! Update data " 25 | "will be ignored for 'network' scope" 26 | ) in caplog.text 27 | -------------------------------------------------------------------------------- /tests/data/mount_parse_ext.txt: -------------------------------------------------------------------------------- 1 | /dev/mapper/vg00-lv_root on / type ext4 (rw,errors=remount-ro) 2 | proc on /proc type proc (rw,noexec,nosuid,nodev) 3 | sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) 4 | none on /sys/fs/cgroup type tmpfs (rw) 5 | none on /sys/fs/fuse/connections type fusectl (rw) 6 | none on /sys/kernel/debug type debugfs (rw) 7 | none on /sys/kernel/security type securityfs (rw) 8 | udev on /dev type devtmpfs (rw,mode=0755) 9 | devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620) 10 | none on /tmp type tmpfs (rw) 11 | tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755) 12 | none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880) 13 | none on /run/shm type tmpfs (rw,nosuid,nodev) 14 | none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755) 15 | none on /sys/fs/pstore type pstore (rw) 16 | /dev/mapper/vg00-lv_var on /var type ext4 (rw) 17 | rpc_pipefs on /run/rpc_pipefs type rpc_pipefs (rw) 18 | systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd) 19 | 10.0.1.1:/backup on /backup type nfs (rw,noexec,nosuid,nodev,bg,nolock,tcp,nfsvers=3,hard,addr=10.0.1.1) -------------------------------------------------------------------------------- /tests/data/merge_sources/expected7.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | users: 4 | - default 5 | - name: foobar 6 | gecos: Foo B. Bar 7 | primary_group: foobar 8 | groups: users 9 | selinux_user: staff_u 10 | expiredate: '2012-09-01' 11 | ssh_import_id: foobar 12 | lock-passwd: false 13 | passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ 14 | - name: barfoo 15 | gecos: Bar B. Foo 16 | sudo: ALL=(ALL) NOPASSWD:ALL 17 | groups: users, admin 18 | ssh_import_id: None 19 | lock-passwd: true 20 | ssh_authorized_keys: 21 | - 22 | - 23 | - name: cloudy 24 | gecos: Magic Cloud App Daemon User 25 | inactive: '5' 26 | system: true 27 | - bob 28 | - joe 29 | - sue 30 | - name: foobar_jr 31 | gecos: Foo B. Bar Jr 32 | primary_group: foobar 33 | groups: users 34 | selinux_user: staff_u 35 | expiredate: '2012-09-01' 36 | ssh_import_id: foobar 37 | lock-passwd: false 38 | passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ 39 | -------------------------------------------------------------------------------- /packages/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | INIT_SYSTEM ?= systemd 3 | export PYBUILD_INSTALL_ARGS=--init-system=$(INIT_SYSTEM) 4 | DEB_VERSION := $(shell dpkg-parsechangelog --show-field=Version) 5 | 6 | %: 7 | dh $@ --with python3,systemd --buildsystem pybuild 8 | 9 | override_dh_install: 10 | dh_install 11 | install -d debian/cloud-init/etc/rsyslog.d 12 | install -d debian/cloud-init/usr/share/apport/package-hooks 13 | cp tools/21-cloudinit.conf debian/cloud-init/etc/rsyslog.d/21-cloudinit.conf 14 | install -D ./tools/Z99-cloud-locale-test.sh debian/cloud-init/etc/profile.d/Z99-cloud-locale-test.sh 15 | install -D ./tools/Z99-cloudinit-warnings.sh debian/cloud-init/etc/profile.d/Z99-cloudinit-warnings.sh 16 | flist=$$(find $(CURDIR)/debian/ -type f -name version.py) && sed -i 's,@@PACKAGED_VERSION@@,$(DEB_VERSION),' $${flist:-did-not-find-version-py-for-replacement} 17 | 18 | override_dh_auto_test: 19 | ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS))) 20 | http_proxy= make check 21 | else 22 | @echo check disabled by DEB_BUILD_OPTIONS=$(DEB_BUILD_OPTIONS) 23 | endif 24 | 25 | override_dh_systemd_start: 26 | dh_systemd_start --no-restart-on-upgrade --no-start 27 | -------------------------------------------------------------------------------- /templates/chrony.conf.sles.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # Use public servers from the pool.ntp.org project. 3 | # Please consider joining the pool (http://www.pool.ntp.org/join.html). 4 | {% if pools %}# pools 5 | {% endif %} 6 | {% for pool in pools -%} 7 | pool {{pool}} iburst 8 | {% endfor %} 9 | {%- if servers %}# servers 10 | {% endif %} 11 | {% for server in servers -%} 12 | server {{server}} iburst 13 | {% endfor %} 14 | 15 | # Record the rate at which the system clock gains/losses time. 16 | driftfile /var/lib/chrony/drift 17 | 18 | # In first three updates step the system clock instead of slew 19 | # if the adjustment is larger than 1 second. 20 | makestep 1.0 3 21 | 22 | # Enable kernel synchronization of the real-time clock (RTC). 23 | rtcsync 24 | 25 | # Allow NTP client access from local network. 26 | #allow 192.168/16 27 | 28 | # Serve time even if not synchronized to any NTP server. 29 | #local stratum 10 30 | 31 | # Specify file containing keys for NTP authentication. 32 | #keyfile /etc/chrony.keys 33 | 34 | # Specify directory for log files. 35 | logdir /var/log/chrony 36 | 37 | # Select which information is logged. 38 | #log measurements statistics tracking 39 | -------------------------------------------------------------------------------- /tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py: -------------------------------------------------------------------------------- 1 | # This file is part of cloud-init. See LICENSE file for license information. 2 | 3 | """cloud-init Integration Test Verify Script.""" 4 | from tests.cloud_tests.testcases import base 5 | 6 | 7 | class TestTrustedCA(base.CloudTestCase): 8 | """Example cloud-config test.""" 9 | 10 | def test_cert_count_ca(self): 11 | """Test correct count of CAs in .crt.""" 12 | out = self.get_data_file('cert_count_ca') 13 | self.assertIn('7 /etc/ssl/certs/ca-certificates.crt', out) 14 | 15 | def test_cert_count_cloudinit(self): 16 | """Test correct count of CAs in .pem.""" 17 | out = self.get_data_file('cert_count_cloudinit') 18 | self.assertIn('7 /etc/ssl/certs/cloud-init-ca-certs.pem', out) 19 | 20 | def test_cloudinit_certs(self): 21 | """Test text of cert.""" 22 | out = self.get_data_file('cloudinit_certs') 23 | self.assertIn('-----BEGIN CERTIFICATE-----', out) 24 | self.assertIn('YOUR-ORGS-TRUSTED-CA-CERT-HERE', out) 25 | self.assertIn('-----END CERTIFICATE-----', out) 26 | 27 | # vi: ts=4 expandtab 28 | -------------------------------------------------------------------------------- /templates/chrony.conf.opensuse.tmpl: -------------------------------------------------------------------------------- 1 | ## template:jinja 2 | # Use public servers from the pool.ntp.org project. 3 | # Please consider joining the pool (http://www.pool.ntp.org/join.html). 4 | {% if pools %}# pools 5 | {% endif %} 6 | {% for pool in pools -%} 7 | pool {{pool}} iburst 8 | {% endfor %} 9 | {%- if servers %}# servers 10 | {% endif %} 11 | {% for server in servers -%} 12 | server {{server}} iburst 13 | {% endfor %} 14 | 15 | # Record the rate at which the system clock gains/losses time. 16 | driftfile /var/lib/chrony/drift 17 | 18 | # In first three updates step the system clock instead of slew 19 | # if the adjustment is larger than 1 second. 20 | makestep 1.0 3 21 | 22 | # Enable kernel synchronization of the real-time clock (RTC). 23 | rtcsync 24 | 25 | # Allow NTP client access from local network. 26 | #allow 192.168/16 27 | 28 | # Serve time even if not synchronized to any NTP server. 29 | #local stratum 10 30 | 31 | # Specify file containing keys for NTP authentication. 32 | #keyfile /etc/chrony.keys 33 | 34 | # Specify directory for log files. 35 | logdir /var/log/chrony 36 | 37 | # Select which information is logged. 38 | #log measurements statistics tracking 39 | --------------------------------------------------------------------------------