Merge lp:~cloud-init-dev/cloud-init/trunk into lp:~hannes-georg-0/cloud-init/add_mkswap_force_flag

Proposed by Hannes
Status: Merged
Merge reported by: Scott Moser
Merged at revision: not available
Proposed branch: lp:~cloud-init-dev/cloud-init/trunk
Merge into: lp:~hannes-georg-0/cloud-init/add_mkswap_force_flag
Diff against target: 51583 lines (+11/-49380) (has conflicts)
424 files modified
.bzrignore (+0/-4)
ChangeLog (+0/-761)
HACKING.rst (+0/-48)
LICENSE (+0/-674)
MANIFEST.in (+0/-8)
Makefile (+0/-82)
README (+11/-0)
TODO.rst (+0/-43)
bin/cloud-init (+0/-673)
cloudinit/__init__.py (+0/-21)
cloudinit/cloud.py (+0/-109)
cloudinit/config/__init__.py (+0/-58)
cloudinit/config/cc_apt_configure.py (+0/-292)
cloudinit/config/cc_apt_pipelining.py (+0/-57)
cloudinit/config/cc_bootcmd.py (+0/-54)
cloudinit/config/cc_byobu.py (+0/-80)
cloudinit/config/cc_ca_certs.py (+0/-104)
cloudinit/config/cc_chef.py (+0/-342)
cloudinit/config/cc_debug.py (+0/-109)
cloudinit/config/cc_disable_ec2_metadata.py (+0/-36)
cloudinit/config/cc_emit_upstart.py (+0/-69)
cloudinit/config/cc_fan.py (+0/-101)
cloudinit/config/cc_final_message.py (+0/-73)
cloudinit/config/cc_foo.py (+0/-52)
cloudinit/config/cc_growpart.py (+0/-300)
cloudinit/config/cc_grub_dpkg.py (+0/-73)
cloudinit/config/cc_keys_to_console.py (+0/-62)
cloudinit/config/cc_landscape.py (+0/-99)
cloudinit/config/cc_locale.py (+0/-37)
cloudinit/config/cc_lxd.py (+0/-176)
cloudinit/config/cc_mcollective.py (+0/-88)
cloudinit/config/cc_migrator.py (+0/-85)
cloudinit/config/cc_mounts.py (+0/-405)
cloudinit/config/cc_package_update_upgrade_install.py (+0/-99)
cloudinit/config/cc_phone_home.py (+0/-122)
cloudinit/config/cc_power_state_change.py (+0/-223)
cloudinit/config/cc_puppet.py (+0/-118)
cloudinit/config/cc_resizefs.py (+0/-185)
cloudinit/config/cc_resolv_conf.py (+0/-116)
cloudinit/config/cc_rh_subscription.py (+0/-408)
cloudinit/config/cc_rightscale_userdata.py (+0/-102)
cloudinit/config/cc_rsyslog.py (+0/-366)
cloudinit/config/cc_runcmd.py (+0/-38)
cloudinit/config/cc_salt_minion.py (+0/-59)
cloudinit/config/cc_scripts_per_boot.py (+0/-41)
cloudinit/config/cc_scripts_per_instance.py (+0/-41)
cloudinit/config/cc_scripts_per_once.py (+0/-41)
cloudinit/config/cc_scripts_user.py (+0/-42)
cloudinit/config/cc_scripts_vendor.py (+0/-43)
cloudinit/config/cc_seed_random.py (+0/-94)
cloudinit/config/cc_set_hostname.py (+0/-37)
cloudinit/config/cc_set_passwords.py (+0/-167)
cloudinit/config/cc_snappy.py (+0/-304)
cloudinit/config/cc_ssh.py (+0/-142)
cloudinit/config/cc_ssh_authkey_fingerprints.py (+0/-105)
cloudinit/config/cc_ssh_import_id.py (+0/-99)
cloudinit/config/cc_timezone.py (+0/-39)
cloudinit/config/cc_ubuntu_init_switch.py (+0/-162)
cloudinit/config/cc_update_etc_hosts.py (+0/-60)
cloudinit/config/cc_update_hostname.py (+0/-43)
cloudinit/config/cc_users_groups.py (+0/-34)
cloudinit/config/cc_write_files.py (+0/-103)
cloudinit/config/cc_yum_add_repo.py (+0/-107)
cloudinit/cs_utils.py (+0/-105)
cloudinit/distros/__init__.py (+0/-950)
cloudinit/distros/arch.py (+0/-201)
cloudinit/distros/debian.py (+0/-227)
cloudinit/distros/fedora.py (+0/-31)
cloudinit/distros/freebsd.py (+0/-417)
cloudinit/distros/gentoo.py (+0/-160)
cloudinit/distros/net_util.py (+0/-182)
cloudinit/distros/parsers/__init__.py (+0/-28)
cloudinit/distros/parsers/hostname.py (+0/-88)
cloudinit/distros/parsers/hosts.py (+0/-92)
cloudinit/distros/parsers/resolv_conf.py (+0/-169)
cloudinit/distros/parsers/sys_conf.py (+0/-113)
cloudinit/distros/rhel.py (+0/-222)
cloudinit/distros/rhel_util.py (+0/-89)
cloudinit/distros/sles.py (+0/-179)
cloudinit/distros/ubuntu.py (+0/-31)
cloudinit/ec2_utils.py (+0/-201)
cloudinit/filters/__init__.py (+0/-21)
cloudinit/filters/launch_index.py (+0/-75)
cloudinit/handlers/__init__.py (+0/-274)
cloudinit/handlers/boot_hook.py (+0/-70)
cloudinit/handlers/cloud_config.py (+0/-163)
cloudinit/handlers/shell_script.py (+0/-55)
cloudinit/handlers/upstart_job.py (+0/-119)
cloudinit/helpers.py (+0/-458)
cloudinit/importer.py (+0/-58)
cloudinit/log.py (+0/-155)
cloudinit/mergers/__init__.py (+0/-166)
cloudinit/mergers/m_dict.py (+0/-88)
cloudinit/mergers/m_list.py (+0/-89)
cloudinit/mergers/m_str.py (+0/-46)
cloudinit/net/__init__.py (+0/-771)
cloudinit/net/network_state.py (+0/-447)
cloudinit/net/udev.py (+0/-54)
cloudinit/netinfo.py (+0/-249)
cloudinit/patcher.py (+0/-58)
cloudinit/registry.py (+0/-37)
cloudinit/reporting/__init__.py (+0/-42)
cloudinit/reporting/events.py (+0/-248)
cloudinit/reporting/handlers.py (+0/-91)
cloudinit/safeyaml.py (+0/-32)
cloudinit/settings.py (+0/-68)
cloudinit/signal_handler.py (+0/-71)
cloudinit/sources/DataSourceAltCloud.py (+0/-293)
cloudinit/sources/DataSourceAzure.py (+0/-651)
cloudinit/sources/DataSourceBigstep.py (+0/-57)
cloudinit/sources/DataSourceCloudSigma.py (+0/-141)
cloudinit/sources/DataSourceCloudStack.py (+0/-253)
cloudinit/sources/DataSourceConfigDrive.py (+0/-424)
cloudinit/sources/DataSourceDigitalOcean.py (+0/-110)
cloudinit/sources/DataSourceEc2.py (+0/-211)
cloudinit/sources/DataSourceGCE.py (+0/-167)
cloudinit/sources/DataSourceMAAS.py (+0/-353)
cloudinit/sources/DataSourceNoCloud.py (+0/-336)
cloudinit/sources/DataSourceNone.py (+0/-57)
cloudinit/sources/DataSourceOVF.py (+0/-429)
cloudinit/sources/DataSourceOpenNebula.py (+0/-455)
cloudinit/sources/DataSourceOpenStack.py (+0/-173)
cloudinit/sources/DataSourceSmartOS.py (+0/-536)
cloudinit/sources/__init__.py (+0/-337)
cloudinit/sources/helpers/__init__.py (+0/-13)
cloudinit/sources/helpers/azure.py (+0/-279)
cloudinit/sources/helpers/openstack.py (+0/-499)
cloudinit/sources/helpers/vmware/__init__.py (+0/-13)
cloudinit/sources/helpers/vmware/imc/__init__.py (+0/-13)
cloudinit/sources/helpers/vmware/imc/boot_proto.py (+0/-25)
cloudinit/sources/helpers/vmware/imc/config.py (+0/-95)
cloudinit/sources/helpers/vmware/imc/config_file.py (+0/-129)
cloudinit/sources/helpers/vmware/imc/config_namespace.py (+0/-25)
cloudinit/sources/helpers/vmware/imc/config_nic.py (+0/-247)
cloudinit/sources/helpers/vmware/imc/config_source.py (+0/-23)
cloudinit/sources/helpers/vmware/imc/guestcust_error.py (+0/-24)
cloudinit/sources/helpers/vmware/imc/guestcust_event.py (+0/-27)
cloudinit/sources/helpers/vmware/imc/guestcust_state.py (+0/-25)
cloudinit/sources/helpers/vmware/imc/guestcust_util.py (+0/-128)
cloudinit/sources/helpers/vmware/imc/ipv4_mode.py (+0/-45)
cloudinit/sources/helpers/vmware/imc/nic.py (+0/-147)
cloudinit/sources/helpers/vmware/imc/nic_base.py (+0/-154)
cloudinit/ssh_util.py (+0/-314)
cloudinit/stages.py (+0/-844)
cloudinit/templater.py (+0/-149)
cloudinit/type_utils.py (+0/-52)
cloudinit/url_helper.py (+0/-509)
cloudinit/user_data.py (+0/-352)
cloudinit/util.py (+0/-2226)
cloudinit/version.py (+0/-27)
config/cloud.cfg (+0/-115)
config/cloud.cfg-freebsd (+0/-88)
config/cloud.cfg.d/05_logging.cfg (+0/-66)
config/cloud.cfg.d/README (+0/-3)
doc/README (+0/-4)
doc/examples/cloud-config-add-apt-repos.txt (+0/-34)
doc/examples/cloud-config-archive-launch-index.txt (+0/-30)
doc/examples/cloud-config-archive.txt (+0/-16)
doc/examples/cloud-config-boot-cmds.txt (+0/-15)
doc/examples/cloud-config-ca-certs.txt (+0/-31)
doc/examples/cloud-config-chef-oneiric.txt (+0/-90)
doc/examples/cloud-config-chef.txt (+0/-95)
doc/examples/cloud-config-datasources.txt (+0/-73)
doc/examples/cloud-config-disk-setup.txt (+0/-251)
doc/examples/cloud-config-final-message.txt (+0/-7)
doc/examples/cloud-config-gluster.txt (+0/-18)
doc/examples/cloud-config-growpart.txt (+0/-31)
doc/examples/cloud-config-install-packages.txt (+0/-15)
doc/examples/cloud-config-landscape.txt (+0/-22)
doc/examples/cloud-config-launch-index.txt (+0/-23)
doc/examples/cloud-config-lxd.txt (+0/-55)
doc/examples/cloud-config-mcollective.txt (+0/-49)
doc/examples/cloud-config-mount-points.txt (+0/-46)
doc/examples/cloud-config-phone-home.txt (+0/-14)
doc/examples/cloud-config-power-state.txt (+0/-40)
doc/examples/cloud-config-puppet.txt (+0/-51)
doc/examples/cloud-config-reporting.txt (+0/-17)
doc/examples/cloud-config-resolv-conf.txt (+0/-20)
doc/examples/cloud-config-rh_subscription.txt (+0/-49)
doc/examples/cloud-config-rsyslog.txt (+0/-46)
doc/examples/cloud-config-run-cmds.txt (+0/-22)
doc/examples/cloud-config-salt-minion.txt (+0/-53)
doc/examples/cloud-config-seed-random.txt (+0/-32)
doc/examples/cloud-config-ssh-keys.txt (+0/-46)
doc/examples/cloud-config-update-apt.txt (+0/-7)
doc/examples/cloud-config-update-packages.txt (+0/-8)
doc/examples/cloud-config-user-groups.txt (+0/-109)
doc/examples/cloud-config-vendor-data.txt (+0/-16)
doc/examples/cloud-config-write-files.txt (+0/-33)
doc/examples/cloud-config-yum-repo.txt (+0/-20)
doc/examples/cloud-config.txt (+0/-645)
doc/examples/include-once.txt (+0/-7)
doc/examples/include.txt (+0/-5)
doc/examples/kernel-cmdline.txt (+0/-18)
doc/examples/part-handler-v2.txt (+0/-38)
doc/examples/part-handler.txt (+0/-23)
doc/examples/plain-ignored.txt (+0/-2)
doc/examples/seed/README (+0/-22)
doc/examples/seed/meta-data (+0/-30)
doc/examples/seed/user-data (+0/-3)
doc/examples/upstart-cloud-config.txt (+0/-12)
doc/examples/upstart-rclocal.txt (+0/-12)
doc/examples/user-script.txt (+0/-8)
doc/merging.rst (+0/-188)
doc/rtd/conf.py (+0/-77)
doc/rtd/index.rst (+0/-31)
doc/rtd/static/logo.svg (+0/-89)
doc/rtd/topics/availability.rst (+0/-20)
doc/rtd/topics/capabilities.rst (+0/-24)
doc/rtd/topics/datasources.rst (+0/-200)
doc/rtd/topics/dir_layout.rst (+0/-81)
doc/rtd/topics/examples.rst (+0/-133)
doc/rtd/topics/format.rst (+0/-159)
doc/rtd/topics/hacking.rst (+0/-1)
doc/rtd/topics/merging.rst (+0/-5)
doc/rtd/topics/modules.rst (+0/-342)
doc/rtd/topics/moreinfo.rst (+0/-12)
doc/sources/altcloud/README.rst (+0/-87)
doc/sources/azure/README.rst (+0/-134)
doc/sources/cloudsigma/README.rst (+0/-38)
doc/sources/cloudstack/README.rst (+0/-29)
doc/sources/configdrive/README.rst (+0/-123)
doc/sources/digitalocean/README.rst (+0/-21)
doc/sources/kernel-cmdline.txt (+0/-48)
doc/sources/nocloud/README.rst (+0/-71)
doc/sources/opennebula/README.rst (+0/-142)
doc/sources/openstack/README.rst (+0/-24)
doc/sources/ovf/README (+0/-83)
doc/sources/ovf/example/ovf-env.xml (+0/-46)
doc/sources/ovf/example/ubuntu-server.ovf (+0/-130)
doc/sources/ovf/make-iso (+0/-156)
doc/sources/ovf/ovf-env.xml.tmpl (+0/-28)
doc/sources/ovf/ovfdemo.pem (+0/-27)
doc/sources/ovf/user-data (+0/-7)
doc/sources/smartos/README.rst (+0/-149)
doc/status.txt (+0/-53)
doc/userdata.txt (+0/-79)
doc/var-lib-cloud.txt (+0/-63)
doc/vendordata.txt (+0/-53)
packages/bddeb (+0/-260)
packages/brpm (+0/-277)
packages/debian/changelog.in (+0/-6)
packages/debian/cloud-init.postinst (+0/-16)
packages/debian/cloud-init.preinst (+0/-20)
packages/debian/compat (+0/-1)
packages/debian/control.in (+0/-29)
packages/debian/copyright (+0/-29)
packages/debian/dirs (+0/-6)
packages/debian/rules.in (+0/-23)
packages/debian/watch (+0/-2)
packages/redhat/cloud-init.spec.in (+0/-200)
packages/suse/cloud-init.spec.in (+0/-163)
requirements.txt (+0/-36)
setup.py (+0/-215)
systemd/cloud-config.service (+0/-16)
systemd/cloud-config.target (+0/-11)
systemd/cloud-final.service (+0/-17)
systemd/cloud-init-generator (+0/-133)
systemd/cloud-init-local.service (+0/-22)
systemd/cloud-init.service (+0/-18)
systemd/cloud-init.target (+0/-6)
sysvinit/debian/cloud-config (+0/-64)
sysvinit/debian/cloud-final (+0/-66)
sysvinit/debian/cloud-init (+0/-64)
sysvinit/debian/cloud-init-local (+0/-63)
sysvinit/freebsd/cloudconfig (+0/-35)
sysvinit/freebsd/cloudfinal (+0/-35)
sysvinit/freebsd/cloudinit (+0/-35)
sysvinit/freebsd/cloudinitlocal (+0/-35)
sysvinit/gentoo/cloud-config (+0/-13)
sysvinit/gentoo/cloud-final (+0/-11)
sysvinit/gentoo/cloud-init (+0/-12)
sysvinit/gentoo/cloud-init-local (+0/-13)
sysvinit/redhat/cloud-config (+0/-121)
sysvinit/redhat/cloud-final (+0/-121)
sysvinit/redhat/cloud-init (+0/-121)
sysvinit/redhat/cloud-init-local (+0/-124)
templates/chef_client.rb.tmpl (+0/-58)
templates/hosts.debian.tmpl (+0/-26)
templates/hosts.freebsd.tmpl (+0/-24)
templates/hosts.redhat.tmpl (+0/-24)
templates/hosts.suse.tmpl (+0/-26)
templates/resolv.conf.tmpl (+0/-30)
templates/sources.list.debian.tmpl (+0/-32)
templates/sources.list.ubuntu.tmpl (+0/-58)
test-requirements.txt (+0/-17)
tests/configs/sample1.yaml (+0/-52)
tests/data/filter_cloud_multipart.yaml (+0/-30)
tests/data/filter_cloud_multipart_1.email (+0/-11)
tests/data/filter_cloud_multipart_2.email (+0/-39)
tests/data/filter_cloud_multipart_header.email (+0/-11)
tests/data/merge_sources/expected1.yaml (+0/-1)
tests/data/merge_sources/expected10.yaml (+0/-7)
tests/data/merge_sources/expected11.yaml (+0/-5)
tests/data/merge_sources/expected12.yaml (+0/-5)
tests/data/merge_sources/expected2.yaml (+0/-3)
tests/data/merge_sources/expected3.yaml (+0/-1)
tests/data/merge_sources/expected4.yaml (+0/-2)
tests/data/merge_sources/expected5.yaml (+0/-7)
tests/data/merge_sources/expected6.yaml (+0/-9)
tests/data/merge_sources/expected7.yaml (+0/-38)
tests/data/merge_sources/expected8.yaml (+0/-7)
tests/data/merge_sources/expected9.yaml (+0/-5)
tests/data/merge_sources/source1-1.yaml (+0/-3)
tests/data/merge_sources/source1-2.yaml (+0/-5)
tests/data/merge_sources/source10-1.yaml (+0/-6)
tests/data/merge_sources/source10-2.yaml (+0/-6)
tests/data/merge_sources/source11-1.yaml (+0/-5)
tests/data/merge_sources/source11-2.yaml (+0/-3)
tests/data/merge_sources/source11-3.yaml (+0/-3)
tests/data/merge_sources/source12-1.yaml (+0/-8)
tests/data/merge_sources/source12-2.yaml (+0/-5)
tests/data/merge_sources/source2-1.yaml (+0/-6)
tests/data/merge_sources/source2-2.yaml (+0/-5)
tests/data/merge_sources/source3-1.yaml (+0/-4)
tests/data/merge_sources/source3-2.yaml (+0/-4)
tests/data/merge_sources/source4-1.yaml (+0/-3)
tests/data/merge_sources/source4-2.yaml (+0/-6)
tests/data/merge_sources/source5-1.yaml (+0/-6)
tests/data/merge_sources/source5-2.yaml (+0/-8)
tests/data/merge_sources/source6-1.yaml (+0/-5)
tests/data/merge_sources/source6-2.yaml (+0/-8)
tests/data/merge_sources/source7-1.yaml (+0/-27)
tests/data/merge_sources/source7-2.yaml (+0/-17)
tests/data/merge_sources/source8-1.yaml (+0/-7)
tests/data/merge_sources/source8-2.yaml (+0/-6)
tests/data/merge_sources/source9-1.yaml (+0/-5)
tests/data/merge_sources/source9-2.yaml (+0/-6)
tests/data/mountinfo_precise_ext4.txt (+0/-24)
tests/data/mountinfo_raring_btrfs.txt (+0/-13)
tests/data/roots/simple_ubuntu/etc/networks/interfaces (+0/-3)
tests/data/user_data.1.txt (+0/-15)
tests/data/vmware/cust-dhcp-2nic.cfg (+0/-34)
tests/data/vmware/cust-static-2nic.cfg (+0/-39)
tests/unittests/helpers.py (+0/-346)
tests/unittests/test__init__.py (+0/-220)
tests/unittests/test_builtin_handlers.py (+0/-73)
tests/unittests/test_cli.py (+0/-54)
tests/unittests/test_cs_util.py (+0/-84)
tests/unittests/test_data.py (+0/-559)
tests/unittests/test_datasource/test_altcloud.py (+0/-452)
tests/unittests/test_datasource/test_azure.py (+0/-646)
tests/unittests/test_datasource/test_azure_helper.py (+0/-421)
tests/unittests/test_datasource/test_cloudsigma.py (+0/-99)
tests/unittests/test_datasource/test_cloudstack.py (+0/-87)
tests/unittests/test_datasource/test_configdrive.py (+0/-407)
tests/unittests/test_datasource/test_digitalocean.py (+0/-127)
tests/unittests/test_datasource/test_gce.py (+0/-166)
tests/unittests/test_datasource/test_maas.py (+0/-163)
tests/unittests/test_datasource/test_nocloud.py (+0/-187)
tests/unittests/test_datasource/test_opennebula.py (+0/-300)
tests/unittests/test_datasource/test_openstack.py (+0/-347)
tests/unittests/test_datasource/test_smartos.py (+0/-585)
tests/unittests/test_distros/test_generic.py (+0/-233)
tests/unittests/test_distros/test_hostname.py (+0/-38)
tests/unittests/test_distros/test_hosts.py (+0/-41)
tests/unittests/test_distros/test_netconfig.py (+0/-321)
tests/unittests/test_distros/test_resolv.py (+0/-67)
tests/unittests/test_distros/test_sysconfig.py (+0/-82)
tests/unittests/test_distros/test_user_data_normalize.py (+0/-297)
tests/unittests/test_ec2_util.py (+0/-139)
tests/unittests/test_filters/test_launch_index.py (+0/-132)
tests/unittests/test_handler/test_handler_apt_configure.py (+0/-109)
tests/unittests/test_handler/test_handler_ca_certs.py (+0/-271)
tests/unittests/test_handler/test_handler_chef.py (+0/-192)
tests/unittests/test_handler/test_handler_debug.py (+0/-81)
tests/unittests/test_handler/test_handler_disk_setup.py (+0/-30)
tests/unittests/test_handler/test_handler_growpart.py (+0/-220)
tests/unittests/test_handler/test_handler_locale.py (+0/-67)
tests/unittests/test_handler/test_handler_lxd.py (+0/-134)
tests/unittests/test_handler/test_handler_mounts.py (+0/-133)
tests/unittests/test_handler/test_handler_power_state.py (+0/-127)
tests/unittests/test_handler/test_handler_rsyslog.py (+0/-174)
tests/unittests/test_handler/test_handler_seed_random.py (+0/-227)
tests/unittests/test_handler/test_handler_set_hostname.py (+0/-72)
tests/unittests/test_handler/test_handler_snappy.py (+0/-306)
tests/unittests/test_handler/test_handler_timezone.py (+0/-76)
tests/unittests/test_handler/test_handler_write_files.py (+0/-112)
tests/unittests/test_handler/test_handler_yum_add_repo.py (+0/-68)
tests/unittests/test_helpers.py (+0/-33)
tests/unittests/test_merging.py (+0/-257)
tests/unittests/test_net.py (+0/-130)
tests/unittests/test_pathprefix2dict.py (+0/-44)
tests/unittests/test_registry.py (+0/-28)
tests/unittests/test_reporting.py (+0/-369)
tests/unittests/test_rh_subscription.py (+0/-214)
tests/unittests/test_runs/test_merge_run.py (+0/-54)
tests/unittests/test_runs/test_simple_run.py (+0/-81)
tests/unittests/test_sshutil.py (+0/-171)
tests/unittests/test_templating.py (+0/-119)
tests/unittests/test_util.py (+0/-489)
tests/unittests/test_vmware_config_file.py (+0/-103)
tools/21-cloudinit.conf (+0/-6)
tools/Z99-cloud-locale-test.sh (+0/-98)
tools/build-on-freebsd (+0/-66)
tools/ccfg-merge-debug (+0/-90)
tools/cloud-init-per (+0/-60)
tools/hacking.py (+0/-170)
tools/make-dist-tarball (+0/-21)
tools/make-mime.py (+0/-60)
tools/make-tarball (+0/-39)
tools/mock-meta.py (+0/-454)
tools/motd-hook (+0/-35)
tools/read-dependencies (+0/-29)
tools/read-version (+0/-26)
tools/run-pep8 (+0/-22)
tools/run-pyflakes (+0/-18)
tools/run-pyflakes3 (+0/-2)
tools/tox-venv (+0/-42)
tools/uncloud-init (+0/-141)
tools/validate-yaml.py (+0/-25)
tools/write-ssh-key-fingerprints (+0/-38)
tox.ini (+0/-35)
udev/66-azure-ephemeral.rules (+0/-18)
udev/79-cloud-init-net-wait.rules (+0/-10)
udev/cloud-init-wait (+0/-70)
upstart/cloud-config.conf (+0/-9)
upstart/cloud-final.conf (+0/-10)
upstart/cloud-init-blocknet.conf (+0/-83)
upstart/cloud-init-container.conf (+0/-57)
upstart/cloud-init-local.conf (+0/-16)
upstart/cloud-init-nonet.conf (+0/-66)
upstart/cloud-init.conf (+0/-9)
upstart/cloud-log-shutdown.conf (+0/-19)
Conflict: can't delete cloudinit because it is not empty.  Not deleting.
Conflict because cloudinit is not versioned, but has versioned children.  Versioned directory.
Conflict: can't delete cloudinit/config because it is not empty.  Not deleting.
Conflict because cloudinit/config is not versioned, but has versioned children.  Versioned directory.
Contents conflict in cloudinit/config/cc_disk_setup.py
To merge this branch: bzr merge lp:~cloud-init-dev/cloud-init/trunk
Reviewer Review Type Date Requested Status
Chad Smith (community) Needs Fixing
Hannes Pending
Review via email: mp+296021@code.launchpad.net

Description of the change

Hi

The force field table in cc_disk_setup lacks an entry for swap.

Thank you
Hannes

To post a comment you must log in.
lp:~cloud-init-dev/cloud-init/trunk updated
1223. By Dan Watkins

Improve merging documentation

1224. By Scott Moser

Apt sources configuration improvements

- keyid-only (no source statement)
- key only (no source statement)
- custom source.list template
- support long gpg key fingerprints with spaces
- fix issue with key's that were already in the local gpg keyring
- allowing a new format to specify apt_sources in a dictionary instead of a
  list to allow merging of configurations

1225. By Scott Moser

improve network configuration

This branch accomplishes several things:
 - centrally handle 'dsmode' to be 'local' or 'net.
   This allows local data sources to run before networking
   but still have user-data read by default when networking is available.

 - support networking information being read on dreamcompute
   dreamcompute's openstack declares networking via the
   /etc/network/interfaces style 'network_config' format.

 - support reading and applying networking information on SmartOS

 - improve reading networking from openstack network_data.json (LP: #1577982)
   add support for mtu and routes and many miscellaneous fixes.

 - support for renaming devices in a container (LP: #1579130).
   Also rename network devices as instructed by the host on
   every boot where cloud-init networking is enabled. This is required
   because a.) containers do not get systemd.link files applied
   as they do not have udev. b.) if the initramfs is out of date
   then we need to apply them.

 - remove blocking of udev rules (LP: #1577844, LP: #1571761)

1226. By Scott Moser

tests: fix apt tests to run inside ubuntu build environment

This just mocks out use of lsb_release as it is not available
in a build environment.
Additionally mocks out use of getkeybyid. This admittedly
makes the test for a long key fingerprint not useful as it was
broken only inside getkeybyid.

Also fix 'make yaml' for cloud-config.txt

1227. By Scott Moser

skip test_apt_source_list_debian_mirrorfail for now

I've opened bug 1589174 with the intent to fix these tests
that I quickly fixed in the last 2 commits. Those were done
in haste so that we could get a functional trunk build again.

1228. By Scott Moser

make networking config provided in system config override datasource.

while datasource provided networking is more dynamic in most cases,
preference should still be given to networking configuration provided
in the system.

This is because the user of the image should be ultimately in control
of the networking configuration if they so choose.

1229. By Scott Moser

Change missing Cheetah log warning to debug [Andrew Jorgensen]

In the absence of cheetah, which is a fairly heavy templating engine, and
not strictly needed by anything in cloud-init, the only warning we saw in
the logs was this one from the templater. Degrading this to a debug
message makes any other warnings more relevant.

1230. By Scott Moser

Fix apt configure unittests to run in more environments

As well as some improvements that were found along testing them and due to
the fact that we review some of that code again in the scope of curtin
currently.

Tests:
 - add a test for an alternate keyserver
 - harden mirrorfail tests to detect and skip if no network is available
 - improve apt_source related tests to work on CentOS7

Changes:
 - gpg key handling is now in python instead of a shell blob and moved
   to its own module.
 - packages/bddeb has an option to sign as someone else than smoser
 - make exception handling of apt_source features more specific
   (do not catch broad 'Exception')
 - rename some functions to reflect better what they actually do
 - capture some helper subp calls output to avoid spilling into stdout when
   not intended

1231. By Scott Moser

clean up temp files made in tests

After a 'tox' run, now there are no tmpdirs left in /tmp.

1232. By Joshua Harlow

Refactor a large part of the networking code.

Splits off distro specific code into specific files so that
other kinds of networking configuration can be written by the
various distro(s) that cloud-init supports.

It also isolates some of the cloudinit.net code so that it can
be more easily used on its own (and incorporated into other
projects such as curtin).

During this process it adds tests so that the net process can
be tested (to some level) so that the format conversion processes
can be tested going forward.

1233. By Joshua Harlow

Fix the broken import and 'parse_net_config_data' function usage

1234. By Dan Watkins

Remove trailing dot from GCE metadata URL (LP: #1581200) [Phil Roche]

1235. By Scott Moser

[Revert] Remove trailing dot from GCE metadata URL

This change broke tox tests.

1236. By Scott Moser

fix pep8 failure introduced in recent commit.

The commit 1232 (Refactor a large part of the networking code) broke pep8.

1237. By Dan Watkins

Re-apply "Remove trailing dot from GCE metadata URL (LP: #1581200) [Phil Roche]"

This commit includes the content of that commit, plus a fix for the tests
(provided by Phil).

1238. By Scott Moser

move 'main' into cloudinit/cmd/ for easier testing

This moves bin/cloud-init's content into cloudinit/cmd/main.py,
and then fixes the pep8/flake8 issues with that.

The end result is easier testing of main.

1239. By Scott Moser

fix some errors reported by pylint

pylint --errors-only found several errors. Some of the changes
here represent real errors, others just code that pylint did
not like.

1240. By Scott Moser

fix usage of OSError.message that will not work in python3

python3's OSError does not have a .message attribute.

1241. By Scott Moser

DataSourceNoCloud: fix stack trace on reboot, default to dsmode=net

On reboot (loading module from obj.pkl) we would hit a AttributeError
when trying to access cmdline_id.
Addtionally, dsmode was inadvertantly defaulting to local for
DataSourceNoCloud.

1242. By Scott Moser

support network rendering to sysconfig (for centos and RHEL)

This intends to add support for rendering of network data under sysconfig
distributions (centos and rhel). The end result will be support for
network configuration via ConfigDrive or NoCloud on these OS.

1243. By Scott Moser

do not render systemd.link files

When fixing bug 1579130, we made cloud-init rename devices itself,
rather than relying on the systemd.link files to do that.
That was necessary to
 - rename devices in a container
 - rename devices on first boot or in any situation when the
   link files in the initramfs were stale.

However, cloud-init was still writing .link files like:
 /etc/systemd/network/50-cloud-init-ens2.link

That leads to just a confusing situation as cloud-init will trump
any renaming systemd does in all cases.

Also added here is a header into the rendered ENI file:
 /etc/network/interfaces.d/50-cloud-init.cfg

that describes how to disable cloud-init networking.

1244. By Scott Moser

write_files: if no permissions are given, just use default without warn.

if no permissions were given in a write_files stanza, then
a warning would be emitted.

The fix here is just to special case handling of None.

1245. By Scott Moser

user_data: fix error when user-data is not utf-8 decodable

when user-data was not decodable, cloud-init would raise exception.
This also changes the signature of user_data.convert_string.
The 'headers' argument was never used, and woudl have been broken
if it was, as it was expected to be a dictionary but then was
passed in with *headers.

1246. By Scott Moser

fix restoring from a datasource that did not have dsmode

On upgrade and reboot, if datasource restored from obj.pkl did not have
a dsmode attribute, then 'init --local' would fail due to stack trace.

1247. By Scott Moser

distros/debian.py: fix calling of eni renderer to not render link files

Under revno 1243 a failed attempt was made to not render systemd.link
files into /etc/systemd/network/ . The 'config' that was passed in was
incorrect though, and resulted in link files still getting rendered.

(original bug was LP: #1594546).

1248. By Joshua Harlow

Dict comprehensions don't work in 2.6

This fixes a small case of a leftover
dict comprehension being found that stops cloud-init
from working on centos6/rhel6 (which still use py2.6)

1249. By Joshua Harlow

Fixes missing/unpacked rpm files

There are a few new files that are missing from being
included in the rpm specification file (which if missing
causes rpmbuild to die) so make sure we add them in.

1250. By Joshua Harlow

Remove another stray dict comprehension

1251. By Joshua Harlow

Another stray occurence of a dict comprehension being removed

1252. By Joshua Harlow

String format requires positions on python 2.6

1253. By Joshua Harlow

Fix SmartOS datasource usage of dict comprehensions

1254. By Scott Moser

Fix mcollective module with python3

fixes mcollective when used with python3 and also adds a unit test.

1255. By Scott Moser

ConfigDrive: fix writing of 'injected' files and legacy networking

Previous commit inadvertently disabled the consumption of 'injected' files
in configdrive (openstack server boot --file=/target/file=local-file)
unless the datasource was in 'pass' mode. The default mode is 'net' so
that was not likely to happen.

Also here are:
a.) some comments to apply_network_config

b.) add backwards compatibility for distros that do not yet implement
    apply_network_config by converting the network config into ENI format
    and calling apply_network.

    This is required because prior to the previous commit, those distros
    would have had 'apply_network' called with the openstack provided
    ENI file. But after this change they will have apply_network_config
    called by cloudinit's main.

c.) add network_state_to_eni for converting net config to eni
    it supports the not-actually-correct 'hwaddress' field in ENI

1256. By Scott Moser

improvements to eni rendering

Some improvements here, and some bug fixes.
 - bring curtin revno 394's to support post-up for interface aliases.
 - sort attributes per interface for nicer order and consistent rendering
 - use arrays for each 'section' rather than content += . This allows
   better separation of the sections and also will perform better as long
   strings with += are slow.
 - improve how 'lo' is handled. If a network state that was being rendered
   had an entry for 'lo', then the rendered ENI would have 2 'lo'
   sections.
 - no longer skip 'lo' sections when loading an ENI in parse_deb_config
 - fix inet value for subnets, don't add interface attributes to alias
   (LP: #1588547)

Also add some tests of reading yaml and rendering ENI.

1257. By Joshua Harlow

Avoid depending on argparse in 2.7 or greater

At least (currently) for rhel7 the argparse package does
not get installed (even though rpm say it is installed by
the python core package) and this causes things that mention
argparse in there requirements to not believe that argparse
is installed (even though it is) so to avoid this whole mess
we can just avoid depending on argparse in python versions
where we don't need to (since it was included in the stdlib
in python 2.7+)

1258. By Scott Moser

mcollective: add tests, cleanups and bug fix when no config in /etc.

Things here:
 - restart rather than 'start' the service, to pick up a config change
   that we would have written.
 - update the config and write cert files whether or not the file
   existed on the system. Previously it would only write the cert
   files if /etc/mcollective/server.cfg already existed.
 - improve test coverage

1259. By Scott Moser

README: indicate move to git.

cloud-init development has moved its revision control to git.
It is available at
  https://code.launchpad.net/cloud-init

Clone with
  git clone https://git.launchpad.net/cloud-init
or
  git clone git+ssh://git.launchpad.net/cloud-ini

For more information see
  https://git.launchpad.net/cloud-init/tree/HACKING.rst

Revision history for this message
Chad Smith (chad.smith) wrote :

Hello,

Thank you for taking the time to contribute to cloud-init Cloud-init has moved its revision control system to git. As a result, we are marking all bzr merge proposals as 'rejected'. If you would like to re-submit this proposal for review, please do so by following the current HACKING documentation at http://cloudinit.readthedocs.io/en/latest/topics/hacking.html.

Thanks again,
The Cloud init folks

review: Needs Fixing
Revision history for this message
Scott Moser (smoser) wrote :

I'm not sure what exactly this merge proposal was for (it seems backwards).
I've marked it 'merged', to get it off of lists.
if you were using it for something ,please feel free to set it to another state.

but remember that cloud-init is now done in git.
Thanks.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file '.bzrignore'
--- .bzrignore 2015-01-21 20:35:56 +0000
+++ .bzrignore 1970-01-01 00:00:00 +0000
@@ -1,4 +0,0 @@
1.tox
2dist
3cloud_init.egg-info
4__pycache__
50
=== removed file 'ChangeLog'
--- ChangeLog 2016-05-26 13:02:17 +0000
+++ ChangeLog 1970-01-01 00:00:00 +0000
@@ -1,761 +0,0 @@
10.7.7:
2 - open 0.7.7
3 - Digital Ocean: add datasource for Digital Ocean. [Neal Shrader]
4 - expose uses_systemd as a distro function (fix rhel7)
5 - fix broken 'output' config (LP: #1387340)
6 - begin adding cloud config module docs to config modules (LP: #1383510)
7 - retain trailing eol from template files (sources.list) when
8 rendered with jinja (LP: #1355343)
9 - Only use datafiles and initsys addon outside virtualenvs
10 - Fix the digital ocean test case on python 2.6
11 - Increase the usefulness, robustness, configurability of the chef module
12 so that it is more useful, more documented and better for users
13 - Fix how '=' signs are not handled that well in ssh_utils (LP: #1391303)
14 - Be more tolerant of ssh keys passed into 'ssh_authorized_keys'; allowing
15 for list, tuple, set, dict, string types and warning on other unexpected
16 types
17 - Update to use newer/better OMNIBUS_URL for chef module
18 - GCE: Allow base64 encoded user-data (LP: #1404311) [Wayne Witzell III]
19 - GCE: use short hostname rather than fqdn (LP: #1383794) [Ben Howard]
20 - systemd: make init stage run before login prompts shown [Steve Langasek]
21 - hostname: on first boot apply hostname to be same as is written for
22 persistent hostname. (LP: #1246485)
23 - remove usage of dmidecode on linux in favor of /sys interface [Ben Howard]
24 - python3 support [Barry Warsaw, Daniel Watkins, Josh Harlow] (LP: #1247132)
25 - support managing gpt partitions in disk config [Daniel Watkins]
26 - Azure: utilze gpt support for ephemeral formating [Daniel Watkins]
27 - CloudStack: support fetching password from virtual router [Daniel Watkins]
28 (LP: #1422388)
29 - readurl, read_file_or_url returns bytes, user must convert as necessary
30 - SmartOS: use v2 metadata service (LP: #1436417) [Daniel Watkins]
31 - NoCloud: fix local datasource claiming found without explicit dsmode
32 - Snappy: add support for installing snappy packages and configuring.
33 - systemd: use network-online instead of network.target (LP: #1440180)
34 [Steve Langasek]
35 - Add functionality to fixate the uid of a newly added user.
36 - Don't overwrite the hostname if the user has changed it after we set it.
37 - GCE datasource does not handle instance ssh keys (LP: 1403617)
38 - sysvinit: make cloud-init-local run before network (LP: #1275098)
39 [Surojit Pathak]
40 - Azure: do not re-set hostname if user has changed it (LP: #1375252)
41 - Fix exception when running with no arguments on Python 3. [Daniel Watkins]
42 - Centos: detect/expect use of systemd on centos 7. [Brian Rak]
43 - Azure: remove dependency on walinux-agent [Daniel Watkins]
44 - EC2: know about eu-central-1 availability-zone (LP: #1456684)
45 - Azure: remove password from on-disk ovf-env.xml (LP: #1443311) [Ben Howard]
46 - Doc: include information on user-data in OpenStack [Daniel Watkins]
47 - Systemd: check for systemd using sd_booted symantics (LP: #1461201)
48 [Lars Kellogg-Stedman]
49 - Add an rh_subscription module to handle registration of Red Hat instances.
50 [Brent Baude]
51 - cc_apt_configure: fix importing keys under python3 (LP: #1463373)
52 - cc_growpart: fix specification of 'devices' list (LP: #1465436)
53 - CloudStack: fix password setting on cloudstack > 4.5.1 (LP: #1464253)
54 - GCE: fix determination of availability zone (LP: #1470880)
55 - ssh: generate ed25519 host keys (LP: #1461242)
56 - distro mirrors: provide datasource to mirror selection code to support
57 GCE regional mirrors. (LP: #1470890)
58 - add udev rules that identify ephemeral device on Azure (LP: #1411582)
59 - _read_dmi_syspath: fix bad log message causing unintended exception
60 - rsyslog: add additional configuration mode (LP: #1478103)
61 - status_wrapper in main: fix use of print_exc when handling exception
62 - reporting: add reporting module for web hook or logging of events.
63 - NoCloud: fix consumption of vendordata (LP: #1493453)
64 - power_state_change: support 'condition' to disable or enable poweroff
65 - ubuntu fan: support for config and installing of ubuntu fan (LP: #1504604)
66 - Azure: support extracting SSH key values from ovf-env.xml (LP: #1506244)
67 - AltCloud: fix call to udevadm settle (LP: #1507526)
68 - Ubuntu templates: modify sources.list template to provide same sources
69 as install from server or desktop ISO. (LP: #1177432)
70 - cc_mounts: use 'nofail' if system uses systemd. (LP: #1514485)
71 - Azure: get instance id from dmi instead of SharedConfig (LP: #1506187)
72 - systemd/power_state: fix power_state to work even if cloud-final
73 exited non-zero (LP: #1449318)
74 - SmartOS: Add support for Joyent LX-Brand Zones (LP: #1540965)
75 [Robert C Jennings]
76 - systemd: support using systemd-detect-virt to detect container
77 (LP: #1539016) [Martin Pitt]
78 - docs: fix lock_passwd documentation [Robert C Jennings]
79 - Azure: Handle escaped quotes in WALinuxAgentShim.find_endpoint.
80 (LP: #1488891) [Dan Watkins]
81 - lxd: add support for setting up lxd using 'lxd init' (LP: #1522879)
82 - Add Image Customization Parser for VMware vSphere Hypervisor
83 Support. [Sankar Tanguturi]
84 - timezone: use a symlink rather than copy for /etc/localtime
85 unless it is already a file (LP: #1543025).
86 - Enable password changing via a hashed string [Alex Sirbu]
87 - Added BigStep datasource [Alex Sirbu]
88 - No longer run pollinate in seed_random (LP: #1554152)
89 - groups: add defalt user to 'lxd' group. Create groups listed
90 for a user if they do not exist. (LP: #1539317)
91 - dmi data: fix failure of reading dmi data for unset dmi values
92 - doc: mention label for nocloud datasource must be 'cidata' [Peter Hurley]
93 - ssh_pwauth: fix module to support 'unchanged' and match behavior
94 described in documentation [Chris Cosby]
95 - quickly check to see if the previous instance id is still valid to
96 avoid dependency on network metadata service on every boot (LP: #1553815)
97 - support network configuration in cloud-init --local with support
98 device naming via systemd.link.
99 - FreeBSD: add support for installing packages, setting password and
100 timezone. Change default user to 'freebsd'. [Ben Arblaster]
101 - locale: list unsupported environment settings in warning (LP: #1558069)
102 - disk_setup: correctly send --force to mkfs on block devices (LP: #1548772)
103 - chef: fix chef install from gems (LP: #1553345)
104 - systemd: do not specify After of obsolete syslog.target (LP: #1536964)
105 - centos: Ensure that resolve conf object is written as a str (LP: #1479988)
106 - chef: straighten out validation_cert and validation_key (LP: #1568940)
107 - phone_home: allow usage of fqdn (LP: #1566824) [Ollie Armstrong]
108 - cloudstack: Only use DHCPv4 lease files as a datasource (LP: #1576273)
109 [Wido den Hollander]
110 - Paths: fix instance path if datasource's id has a '/'. (LP: #1575938)
111 [Robert Jennings]
112 - Ec2: do not retry requests for user-data path on 404.
113 - settings on the kernel command line (cc:) override all local settings
114 rather than only those in /etc/cloud/cloud.cfg (LP: #1582323)
115
1160.7.6:
117 - open 0.7.6
118 - Enable vendordata on CloudSigma datasource (LP: #1303986)
119 - Poll on /dev/ttyS1 in CloudSigma datasource only if dmidecode says
120 we're running on cloudsigma (LP: #1316475) [Kiril Vladimiroff]
121 - SmartOS test: do not require existance of /dev/ttyS1. [LP: #1316597]
122 - doc: fix user-groups doc to reference plural ssh-authorized-keys
123 (LP: #1327065) [Joern Heissler]
124 - fix 'make test' in python 2.6
125 - support jinja2 as a templating engine. Drop the hard requirement on
126 cheetah. This helps in python3 effort. (LP: #1219223)
127 - change install path for systemd files to /lib/systemd/system
128 [Dimitri John Ledkov]
129 - change trunk debian packaging to use pybuild and drop cdbs.
130 [Dimitri John Ledkov]
131 - SeLinuxGuard: remove invalid check that looked for stat.st_mode in os.lstat.
132 - do not write comments in /etc/timezone (LP: #1341710)
133 - ubuntu: provide 'ubuntu-init-switch' module to aid in systemd testing.
134 - status/result json: remove 'end' entry which was always null
135 - systemd: make cloud-init block ssh service startup to guarantee keys
136 are generated. [Jordan Evans] (LP: #1333920)
137 - default settings: fix typo resulting in OpenStack and GCE not working
138 unless config explicitly provided (LP: #1329583) [Garrett Holmstrom])
139 - fix rendering resolv.conf if no 'options' are provided (LP: #1328953)
140 - docs: fix disk-setup to reference 'table_type' [Rail Aliiev] (LP: #1313114)
141 - ssh_authkey_fingerprints: fix bug that prevented disabling the module.
142 (LP: #1340903) [Patrick Lucas]
143 - no longer use pylint as a checker, fix pep8 [Jay Faulkner].
144 - Openstack: do not load some urls twice.
145 - FreeBsd: fix initscripts and add working config file [Harm Weites]
146 - Datasource: fix broken logic to provide hostname if datasource does not
147 provide one
148 - Improved and less verbose logging.
149 - resizefs: first check that device is writable.
150 - configdrive: fix reading of vendor data to be like metadata service reader.
151 [Jay Faulkner]
152 - resizefs: fix broken background resizing [Jay Faulkner] (LP: #1338614)
153 - cc_grub_dpkg: fix EC2 hvm instances to avoid prompt on grub update.
154 (LP: #1336855)
155 - FreeBsd: support config drive datasource [Joseph bajin]
156 - cc_mounts: support creating a swap file
157 - DigitalOcean & GCE: fix get_hostname consistency
1580.7.5:
159 - open 0.7.5
160 - Add a debug log message around import failures
161 - add a 'debug' module for easily printing out some information about
162 datasource and cloud-init [Shraddha Pandhe]
163 - support running apt with 'eatmydata' via configuration token
164 apt_get_wrapper (LP: #1236531).
165 - convert paths provided in config-drive 'files' to string before writing
166 (LP: #1260072).
167 - Azure: minor changes in logging output. ensure filenames are strings (not
168 unicode).
169 - config/cloud.cfg.d/05_logging.cfg: provide a default 'output' setting, to
170 redirect cloud-init stderr and stdout /var/log/cloud-init-output.log.
171 - drop support for resizing partitions with parted entirely (LP: #1212492).
172 This was broken as it was anyway.
173 - add support for vendordata in SmartOS and NoCloud datasources.
174 - drop dependency on boto for crawling ec2 metadata service.
175 - add 'Requires' on sudo (for OpenNebula datasource) in rpm specs, and
176 'Recommends' in the debian/control.in [Vlastimil Holer]
177 - if mount_info reports /dev/root is a device path for /, then convert
178 that to a device via help of kernel cmdline.
179 - configdrive: consider partitions as possible datasources if they have
180 theh correct filesystem label. [Paul Querna]
181 - initial freebsd support [Harm Weites]
182 - fix in is_ipv4 to accept IP addresses with a '0' in them.
183 - Azure: fix issue when stale data in /var/lib/waagent (LP: #1269626)
184 - skip config_modules that declare themselves only verified on a set of
185 distros. Add them to 'unverified_modules' list to run anyway.
186 - Add CloudSigma datasource [Kiril Vladimiroff]
187 - Add initial support for Gentoo and Arch distributions [Nate House]
188 - Add GCE datasource [Vaidas Jablonskis]
189 - Add native Openstack datasource which reads openstack metadata
190 rather than relying on EC2 data in openstack metadata service.
191 - SmartOS, AltCloud: disable running on arm systems due to bug
192 (LP: #1243287, #1285686) [Oleg Strikov]
193 - Allow running a command to seed random, default is 'pollinate -q'
194 (LP: #1286316) [Dustin Kirkland]
195 - Write status to /run/cloud-init/status.json for consumption by
196 other programs (LP: #1284439)
197 - Azure: if a reboot causes ephemeral storage to be re-provisioned
198 Then we need to re-format it. (LP: #1292648)
199 - OpenNebula: support base64 encoded user-data
200 [Enol Fernandez, Peter Kotcauer]
2010.7.4:
202 - fix issue mounting 'ephemeral0' if ephemeral0 was an alias for a
203 partitioned block device with target filesystem on ephemeral0.1.
204 (LP: #1236594)
205 - fix DataSourceAzure incompatibility with 2.6 (LP: #1232175)
206 - fix power_state_change config module so that example works. Improve
207 its documentation and add reference to 'timeout'
208 - support apt-add-archive with 'cloud-archive:' format. (LP: #1244355)
209 - Change SmartOS verb for availability zone (LP: #1249124)
210 - documentation fix for boothooks to use 'cloud-init-per'
211 - fix resizefs module by supporting kernels that do not have
212 /proc/PID/mountinfo. (LP: #1248625) [Tim Daly Jr.]
213 - fix 'make rpm' by removing 0.6.4 entry from ChangeLog (LP: #1241834)
2140.7.3:
215 - fix omnibus chef installer (LP: #1182265) [Chris Wing]
216 - small fix for OVF datasource for iso transport on non-iso9660 filesystem
217 - determine if upstart version is suitable for
218 'initctl reload-configuration' (LP: #1124384). If so, then invoke it.
219 supports setting up instance-store disk with partition table and filesystem.
220 - add Azure datasource.
221 - add support for SuSE / SLES [Juerg Haefliger]
222 - add a trailing carriage return to chpasswd input, which reportedly
223 caused a problem on rhel5 if missing.
224 - support individual MIME segments to be gzip compressed (LP: #1203203)
225 - always finalize handlers even if processing failed (LP: #1203368)
226 - support merging into cloud-config via jsonp. (LP: #1200476)
227 - add datasource 'SmartOS' for Joyent Cloud. Adds a dependency on serial.
228 - add 'log_time' helper to util for timing how long things take
229 which also reads from uptime. uptime is useful as clock may change during
230 boot due to ntp.
231 - prefer growpart resizer to 'parted resizepart' (LP: #1212492)
232 - support random data seed from config drive or azure, and a module
233 'seed_random' to read that and write it to /dev/urandom.
234 - add OpenNebula Datasource [Vlastimil Holer]
235 - add 'cc_disk_setup' config module for paritioning disks and creating
236 filesystems. Useful if attached disks are not formatted (LP: #1218506)
237 - Fix usage of libselinux-python when selinux is disabled. [Garrett Holmstrom]
238 - multi_log: only write to /dev/console if it exists [Garrett Holmstrom]
239 - config/cloud.cfg: add 'sudo' to list groups for the default user
240 (LP: #1228228)
241 - documentation fix for use of 'mkpasswd' [Eric Nordlund]
242 - respect /etc/growroot-disabled file (LP: #1234331)
2430.7.2:
244 - add a debian watch file
245 - add 'sudo' entry to ubuntu's default user (LP: #1080717)
246 - fix resizefs module when 'noblock' was provided (LP: #1080985)
247 - make sure there is no blank line before cloud-init entry in
248 there are no blank lines in /etc/ca-certificates.conf (LP: #1077020)
249 - fix sudoers writing when entry is a string (LP: #1079002)
250 - tools/write-ssh-key-fingerprints: use '-s' rather than '--stderr'
251 option (LP: #1083715)
252 - make install of puppet configurable (LP: #1090205) [Craig Tracey]
253 - support omnibus installer for chef [Anatoliy Dobrosynets]
254 - fix bug where cloud-config in user-data could not modify system_info
255 settings (LP: #1090482)
256 - fix CloudStack DataSource to use Virtual Router as described by
257 CloudStack documentation if it is available by searching through dhclient
258 lease files. If it is not available, then fall back to the default
259 gateway. (LP: #1089989)
260 - fix redaction of password field in log (LP: #1096417)
261 - fix to cloud-config user setup. Previously, lock_passwd was broken and
262 all accounts would be locked unless 'system' was given (LP: #1096423).
263 - Allow 'sr0' (or sr[0-9]) to be specified without /dev/ as a source for
264 mounts. [Vlastimil Holer]
265 - allow config-drive-data to come from a CD device by more correctly
266 filtering out partitions. (LP: #1100545)
267 - setup docs to be available on read-the-docs
268 https://cloudinit.readthedocs.org/en/latest/ (LP: #1093039)
269 - add HACKING file for information on contributing
270 - handle the legacy 'user:' configuration better, making it affect the
271 configured OS default user (LP: #1100920)
272 - Adding a resolv.conf configuration module (LP: #1100434). Currently only
273 working on redhat systems (no support for resolvconf)
274 - support grouping linux distros into "os_families". This allows a module
275 to operate on the family (redhat or debian) rather than the distro (ubuntu,
276 debian, fedora, rhel) (LP: #1100029)
277 - fix /etc/hosts writing when templates are used (LP: #1100036)
278 - add package versioning logic to package installation
279 functionality (LP: #1108047)
280 - fix documentation for write_files to correctly list 'permissions'
281 rather than 'perms' (LP: #1111205)
282 - cloud-init-container.conf: ensure /run/network before running ifquery
283 - DataSourceNoCloud: allow user-data and meta-data to be specified
284 in config (LP: #1115833).
285 - improve debian support in sysvinit scripts, package build scripts, and
286 split sources.list template to be distro specific.
287 - support for resizing btrfs root filesystems [Blair Zajac]
288 - fix issue when writing ssh keys to .ssh/authorized_keys (LP: #1136343)
289 - upstart: cloud-init-nonet.conf trap the TERM signal, so that dmesg or other
290 output does not get a 'killed by TERM signal' message.
291 - support resizing partitions via growpart or parted (LP: #1136936)
292 - allow specifying apt-get command in distro config ('apt_get_command')
293 - support different and user-suppliable merging algorithms for cloud-config
294 (LP: #1023179)
295 - use python-requests rather than urllib2. By using recent versions of
296 python-requests, we get https support (LP: #1067888).
297 - make apt-get invoke 'dist-upgrade' rather than 'upgrade' for
298 package_upgrade. (LP: #1164147)
299 - improvements for systemd with Fedora 18
300 - workaround 2.6 kernel issue that stopped blkid from showing /dev/sr0
301 - add new, backwards compatible merging syntax so merging of cloud-config
302 can be more useful.
303
3040.7.1:
305 - sysvinit: fix missing dependency in cloud-init job for RHEL 5.6
306 - config-drive: map hostname to local-hostname (LP: #1061964)
307 - landscape: install landscape-client package if not installed.
308 only take action if cloud-config is present (LP: #1066115)
309 - cc_landscape: restart landscape after install or config (LP: #1070345)
310 - multipart/archive. do not fail on unknown headers in multipart
311 mime or cloud-archive config (LP: #1065116).
312 - tools/Z99-cloud-locale-test.sh: avoid warning when user's shell is
313 zsh (LP: #1073077)
314 - fix stack trace when unknown user-data input had unicode (LP: #1075756)
315 - split 'apt-update-upgrade' config module into 'apt-configure' and
316 'package-update-upgrade-install'. The 'package-update-upgrade-install'
317 will be a cross distro module.
318 - Cleanups:
319 - Remove usage of paths.join, as all code should run through util helpers
320 - Fix pylint complaining about tests folder 'helpers.py' not being found
321 - Add a pylintrc file that is used instead options hidden in 'run_pylint'
322 - fix bug where cloud-config from user-data could not affect system_info
323 settings [revno 703] (LP: #1076811)
324 - for write fqdn to system config for rh/fedora [revno 704]
325 - add yaml/cloud config examples checking tool [revno 706]
326 - Fix the merging of group configuration when that group configuration is a
327 dict => members. [revno 707]
328 - add yum_add_repo configuration module for adding additional yum repos
329 - fix public key importing with config-drive-v2 datasource (LP: #1077700)
330 - handle renaming and fixing up of marker names (LP: 1075980) [revno 710]
331 this relieves that burden from the distro/packaging.
332 - group config: fix how group members weren't being translated correctly
333 when the group: [member, member...] format was used (LP: #1077245)
334 - sysconfig: fix how the /etc/sysconfig/network should be using the fully
335 qualified domain name instead of the partially qualified domain name
336 which is used in the ubuntu/debian case (LP: #1076759)
337 - fix how string escaping was not working when the string was a unicode
338 string which was causing the warning message not to be written
339 out (LP: #1075756)
340 - for boto > 0.6.0 there was a lazy load of the metadata added, when
341 cloud-init runs the usage of this lazy loading is hidden and since that lazy
342 loading will be performed on future attribute access we must traverse the
343 lazy loaded dictionary and force it to full expand so that if cloud-init
344 blocks the ec2 metadata port the lazy loaded dictionary will continue
345 working properly instead of trying to make additional url calls which will
346 fail (LP: #1068801)
347 - use a set of helper/parsing classes to perform system configuration
348 for easier test. (/etc/sysconfig, /etc/hostname, resolv.conf, /etc/hosts)
349 - add power_state_change config module for shutting down stystem after
350 cloud-init finishes. (LP: #1064665)
3510.7.0:
352 - add a 'exception_cb' argument to 'wait_for_url'. If provided, this
353 method will be called back with the exception received and the message.
354 - utilize the 'exception_cb' above to modify the oauth timestamp in
355 DataSourceMAAS requests if a 401 or 403 is received. (LP: #978127)
356 - catch signals and exit rather than stack tracing
357 - if logging fails, enable a fallback logger by patching the logging module
358 - do not 'start networking' in cloud-init-nonet, but add
359 cloud-init-container job that runs only if in container and emits
360 net-device-added (LP: #1031065)
361 - search only top level dns for 'instance-data' in
362 DataSourceEc2 (LP: #1040200)
363 - add support for config-drive-v2 (LP:#1037567)
364 - support creating users, including the default user.
365 [Ben Howard] (LP: #1028503)
366 - add apt_reboot_if_required to reboot if an upgrade or package installation
367 forced the need for one (LP: #1038108)
368 - allow distro mirror selection to include availability-zone (LP: #1037727)
369 - allow arch specific mirror selection (select ports.ubuntu.com on arm)
370 LP: #1028501
371 - allow specification of security mirrors (LP: #1006963)
372 - add the 'None' datasource (LP: #906669), which will allow jobs
373 to run even if there is no "real" datasource found.
374 - write ssh authorized keys to console, ssh_authkey_fingerprints
375 config module [Joshua Harlow] (LP: #1010582)
376 - Added RHEVm and vSphere support as source AltCloud [Joseph VLcek]
377 - add write-files module (LP: #1012854)
378 - Add setuptools + cheetah to debian package build dependencies (LP: #1022101)
379 - Adjust the sysvinit local script to provide 'cloud-init-local' and have
380 the cloud-config script depend on that as well.
381 - Add the 'bzr' name to all packages built
382 - Reduce logging levels for certain non-critical cases to DEBUG instead of the
383 previous level of WARNING
384 - unified binary that activates the various stages
385 - Now using argparse + subcommands to specify the various CLI options
386 - a stage module that clearly separates the stages of the different
387 components (also described how they are used and in what order in the
388 new unified binary)
389 - user_data is now a module that just does user data processing while the
390 actual activation and 'handling' of the processed user data is done via
391 a separate set of files (and modules) with the main 'init' stage being the
392 controller of this
393 - creation of boot_hook, cloud_config, shell_script, upstart_job version 2
394 modules (with classes that perform there functionality) instead of those
395 having functionality that is attached to the cloudinit object (which
396 reduces reuse and limits future functionality, and makes testing harder)
397 - removal of global config that defined paths, shared config, now this is
398 via objects making unit testing testing and global side-effects a non issue
399 - creation of a 'helpers.py'
400 - this contains an abstraction for the 'lock' like objects that the various
401 module/handler running stages use to avoid re-running a given
402 module/handler for a given frequency. this makes it separated from
403 the actual usage of that object (thus helpful for testing and clear lines
404 usage and how the actual job is accomplished)
405 - a common 'runner' class is the main entrypoint using these locks to
406 run function objects passed in (along with there arguments) and there
407 frequency
408 - add in a 'paths' object that provides access to the previously global
409 and/or config based paths (thus providing a single entrypoint object/type
410 that provides path information)
411 - this also adds in the ability to change the path when constructing
412 that path 'object' and adding in additional config that can be used to
413 alter the root paths of 'joins' (useful for testing or possibly useful
414 in chroots?)
415 - config options now avaiable that can alter the 'write_root' and the
416 'read_root' when backing code uses the paths join() function
417 - add a config parser subclass that will automatically add unknown sections
418 and return default values (instead of throwing exceptions for these cases)
419 - a new config merging class that will be the central object that knows
420 how to do the common configuration merging from the various configuration
421 sources. The order is the following:
422 - cli config files override environment config files
423 which override instance configs which override datasource
424 configs which override base configuration which overrides
425 default configuration.
426 - remove the passing around of the 'cloudinit' object as a 'cloud' variable
427 and instead pass around an 'interface' object that can be given to modules
428 and handlers as there cloud access layer while the backing of that
429 object can be varied (good for abstraction and testing)
430 - use a single set of functions to do importing of modules
431 - add a function in which will search for a given set of module names with
432 a given set of attributes and return those which are found
433 - refactor logging so that instead of using a single top level 'log' that
434 instead each component/module can use its own logger (if desired), this
435 should be backwards compatible with handlers and config modules that used
436 the passed in logger (its still passed in)
437 - ensure that all places where exception are caught and where applicable
438 that the util logexc() is called, so that no exceptions that may occur
439 are dropped without first being logged (where it makes sense for this
440 to happen)
441 - add a 'requires' file that lists cloud-init dependencies
442 - applying it in package creation (bdeb and brpm) as well as using it
443 in the modified setup.py to ensure dependencies are installed when
444 using that method of packaging
445 - add a 'version.py' that lists the active version (in code) so that code
446 inside cloud-init can report the version in messaging and other config files
447 - cleanup of subprocess usage so that all subprocess calls go through the
448 subp() utility method, which now has an exception type that will provide
449 detailed information on python 2.6 and 2.7
450 - forced all code loading, moving, chmod, writing files and other system
451 level actions to go through standard set of util functions, this greatly
452 helps in debugging and determining exactly which system actions cloud-init
453 is performing
454 - adjust url fetching and url trying to go through a single function that
455 reads urls in the new 'url helper' file, this helps in tracing, debugging
456 and knowing which urls are being called and/or posted to from with-in
457 cloud-init code
458 - add in the sending of a 'User-Agent' header for all urls fetched that
459 do not provide there own header mapping, derive this user-agent from
460 the following template, 'Cloud-Init/{version}' where the version is the
461 cloud-init version number
462 - using prettytable for netinfo 'debug' printing since it provides a standard
463 and defined output that should be easier to parse than a custom format
464 - add a set of distro specific classes, that handle distro specific actions
465 that modules and or handler code can use as needed, this is organized into
466 a base abstract class with child classes that implement the shared
467 functionality. config determines exactly which subclass to load, so it can
468 be easily extended as needed.
469 - current functionality
470 - network interface config file writing
471 - hostname setting/updating
472 - locale/timezone/ setting
473 - updating of /etc/hosts (with templates or generically)
474 - package commands (ie installing, removing)/mirror finding
475 - interface up/down activating
476 - implemented a debian + ubuntu subclass
477 - implemented a redhat + fedora subclass
478 - adjust the root 'cloud.cfg' file to now have distrobution/path specific
479 configuration values in it. these special configs are merged as the normal
480 config is, but the system level config is not passed into modules/handlers
481 - modules/handlers must go through the path and distro object instead
482 - have the cloudstack datasource test the url before calling into boto to
483 avoid the long wait for boto to finish retrying and finally fail when
484 the gateway meta-data address is unavailable
485 - add a simple mock ec2 meta-data python based http server that can serve a
486 very simple set of ec2 meta-data back to callers
487 - useful for testing or for understanding what the ec2 meta-data
488 service can provide in terms of data or functionality
489 - for ssh key and authorized key file parsing add in classes and util
490 functions that maintain the state of individual lines, allowing for a
491 clearer separation of parsing and modification (useful for testing and
492 tracing)
493 - add a set of 'base' init.d scripts that can be used on systems that do
494 not have full upstart or systemd support (or support that does not match
495 the standard fedora/ubuntu implementation)
496 - currently these are being tested on RHEL 6.2
497 - separate the datasources into there own subdirectory (instead of being
498 a top-level item), this matches how config 'modules' and user-data
499 'handlers' are also in there own subdirectory (thus helping new developers
500 and others understand the code layout in a quicker manner)
501 - add the building of rpms based off a new cli tool and template 'spec' file
502 that will templatize and perform the necessary commands to create a source
503 and binary package to be used with a cloud-init install on a 'rpm'
504 supporting system
505 - uses the new standard set of requires and converts those pypi requirements
506 into a local set of package requirments (that are known to exist on RHEL
507 systems but should also exist on fedora systems)
508 - adjust the bdeb builder to be a python script (instead of a shell script)
509 and make its 'control' file a template that takes in the standard set of
510 pypi dependencies and uses a local mapping (known to work on ubuntu) to
511 create the packages set of dependencies (that should also work on
512 ubuntu-like systems)
513 - pythonify a large set of various pieces of code
514 - remove wrapping return statements with () when it has no effect
515 - upper case all constants used
516 - correctly 'case' class and method names (where applicable)
517 - use os.path.join (and similar commands) instead of custom path creation
518 - use 'is None' instead of the frowned upon '== None' which picks up a large
519 set of 'true' cases than is typically desired (ie for objects that have
520 there own equality)
521 - use context managers on locks, tempdir, chdir, file, selinux, umask,
522 unmounting commands so that these actions do not have to be closed and/or
523 cleaned up manually in finally blocks, which is typically not done and
524 will eventually be a bug in the future
525 - use the 'abc' module for abstract classes base where possible
526 - applied in the datasource root class, the distro root class, and the
527 user-data v2 root class
528 - when loading yaml, check that the 'root' type matches a predefined set of
529 valid types (typically just 'dict') and throw a type error if a mismatch
530 occurs, this seems to be a good idea to do when loading user config files
531 - when forking a long running task (ie resizing a filesytem) use a new util
532 function that will fork and then call a callback, instead of having to
533 implement all that code in a non-shared location (thus allowing it to be
534 used by others in the future)
535 - when writing out filenames, go through a util function that will attempt to
536 ensure that the given filename is 'filesystem' safe by replacing '/' with
537 '_' and removing characters which do not match a given whitelist of allowed
538 filename characters
539 - for the varying usages of the 'blkid' command make a function in the util
540 module that can be used as the single point of entry for interaction with
541 that command (and its results) instead of having X separate implementations
542 - place the rfc 8222 time formatting and uptime repeated pieces of code in the
543 util module as a set of function with the name 'time_rfc2822'/'uptime'
544 - separate the pylint+pep8 calling from one tool into two indivudal tools so
545 that they can be called independently, add make file sections that can be
546 used to call these independently
547 - remove the support for the old style config that was previously located in
548 '/etc/ec2-init/ec2-config.cfg', no longer supported!
549 - instead of using a altered config parser that added its own 'dummy' section
550 on in the 'mcollective' module, use configobj which handles the parsing of
551 config without sections better (and it also maintains comments instead of
552 removing them)
553 - use the new defaulting config parser (that will not raise errors on sections
554 that do not exist or return errors when values are fetched that do not
555 exist) in the 'puppet' module
556 - for config 'modules' add in the ability for the module to provide a list of
557 distro names which it is known to work with, if when ran and the distro
558 being used name does not match one of those in this list, a warning will be
559 written out saying that this module may not work correctly on this
560 distrobution
561 - for all dynamically imported modules ensure that they are fixed up before
562 they are used by ensuring that they have certain attributes, if they do not
563 have those attributes they will be set to a sensible set of defaults instead
564 - adjust all 'config' modules and handlers to use the adjusted util functions
565 and the new distro objects where applicable so that those pieces of code can
566 benefit from the unified and enhanced functionality being provided in that
567 util module
568 - fix a potential bug whereby when a #includeonce was encountered it would
569 enable checking of urls against a cache, if later a #include was encountered
570 it would continue checking against that cache, instead of refetching (which
571 would likely be the expected case)
572 - add a openstack/nova based pep8 extension utility ('hacking.py') that allows
573 for custom checks (along with the standard pep8 checks) to occur when
574 running 'make pep8' and its derivatives
575 - support relative path in AuthorizedKeysFile (LP: #970071).
576 - make apt-get update run with --quiet (suitable for logging) (LP: #1012613)
577 - cc_salt_minion: use package 'salt-minion' rather than 'salt' (LP: #996166)
578 - use yaml.safe_load rather than yaml.load (LP: #1015818)
5790.6.3:
580 - add sample systemd config files [Garrett Holmstrom]
581 - add Fedora support [Garrent Holstrom] (LP: #883286)
582 - fix bug in netinfo.debug_info if no net devices available (LP: #883367)
583 - use python module hashlib rather than md5 to avoid deprecation warnings.
584 - support configuration of mirror based on dns name ubuntu-mirror in
585 local domain.
586 - support setting of Acquire::HTTP::Proxy via 'apt_proxy'
587 - DataSourceEc2: more resilliant to slow metadata service
588 - config change: 'retries' dropped, 'max_wait' added, timeout increased
589 - close stdin in all cloud-init programs that are launched at boot
590 (LP: #903993)
591 - revert management of /etc/hosts to 0.6.1 style (LP: #890501, LP: #871966)
592 - write full ssh keys to console for easy machine consumption (LP: #893400)
593 - put INSTANCE_ID environment variable in bootcmd scripts
594 - add 'cloud-init-per' script for easily running things with a given frequency
595 - replace cloud-init-run-module with cloud-init-per
596 - support configuration of landscape-client via cloud-config (LP: #857366)
597 - part-handlers now get base64 decoded content rather than 2xbase64 encoded
598 in the payload parameter. (LP: #874342)
599 - add test case framework [Mike Milner] (LP: #890851)
600 - fix pylint warnings [Juerg Haefliger] (LP: #914739)
601 - add support for adding and deleting CA Certificates [Mike Milner]
602 (LP: #915232)
603 - in ci-info lines, use '.' to indicate empty field for easier machine reading
604 - support empty lines in "#include" files (LP: #923043)
605 - support configuration of salt minions (Jeff Bauer) (LP: #927795)
606 - DataSourceOVF: only search for OVF data on ISO9660 filesystems (LP: #898373)
607 - DataSourceConfigDrive: support getting data from openstack config drive
608 (LP: #857378)
609 - DataSourceNoCloud: support seed from external disk of ISO or vfat
610 (LP: #857378)
611 - DataSourceNoCloud: support inserting /etc/network/interfaces
612 - DataSourceMaaS: add data source for Ubuntu Machines as a Service (MaaS)
613 (LP: #942061)
614 - DataSourceCloudStack: add support for CloudStack datasource [Cosmin Luta]
615 - add option 'apt_pipelining' to address issue with S3 mirrors
616 (LP: #948461) [Ben Howard]
617 - warn on non-multipart, non-handled user-data [Martin Packman]
618 - run resizefs in the background in order to not block boot (LP: #961226)
619 - Fix bug in Chef support where validation_key was present in config, but
620 'validation_cert' was not (LP: #960547)
621 - Provide user friendly message when an invalid locale is set
622 [Ben Howard] (LP: #859814)
623 - Support reading cloud-config from kernel command line parameter and
624 populating local file with it, which can then provide data for DataSources
625 - improve chef examples for working configurations on 11.10 and 12.04
626 [Lorin Hochstein] (LP: #960564)
627
6280.6.2:
629 - fix bug where update was not done unless update was explicitly set.
630 It would not be run if 'upgrade' or packages were set to be installed
631 - fix bug in part-handler code, that prevented working part-handlers
632 (LP: #739694)
633 - fix bug in resizefs cloud-config that would cause trace based on
634 failure of 'blkid /dev/root' (LP: #726938)
635 - convert dos formated files to unix for user-scripts, boothooks,
636 and upstart jobs (LP: #744965)
637 - fix bug in seeding of grub dpkg configuration (LP: #752361) due
638 to renamed devices in newer (natty) kernels (/dev/sda1 -> /dev/xvda1)
639 - make metadata urls configurable, to support eucalyptus in
640 STATIC or SYSTEM modes (LP: #761847)
641 - support disabling byobu in cloud-config
642 - run cc_ssh as a cloud-init module so it is guaranteed to run before
643 ssh starts (LP: #781101)
644 - make prefix for keys added to /root/.ssh/authorized_keys configurable
645 and add 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding'
646 to the default (LP: #798505)
647 - make 'cloud-config ready' command configurable (LP: #785551)
648 - make fstab fields used to 'fill in' shorthand entries configurable
649 This means you do not have to have 'nobootwait' in the values
650 (LP: #785542)
651 - read /etc/ssh/sshd_config for AuthorizedKeysFile rather than
652 assuming ~/.ssh/authorized_keys (LP: #731849)
653 - fix cloud-init in ubuntu lxc containers (LP: #800824)
654 - sanitize hosts file for system's hostname to 127.0.1.1 (LP: #802637)
655 - add chef support (cloudinit/CloudConfig/cc_chef.py) (LP: ##798844)
656 - do not give trace on failure to resize in lxc container (LP: #800856)
657 - increase the timeout on url gets for "seedfrom" values (LP: #812646)
658 - do not write entries for ephemeral0 on t1.micro (LP: #744019)
659 - support 'include-once' so that expiring or one-time use urls can
660 be used for '#include' to provide sensitive data.
661 - support for passing public and private keys to mcollective via cloud-config
662 - support multiple staticly configured network devices, as long as
663 all of them come up early (LP: #810044)
664 - Changes to handling user data mean that:
665 * boothooks will now run more than once as they were intended (and as
666 bootcmd commands do)
667 * cloud-config and user-scripts will be updated from user data every boot
668 - Fix issue where 'isatty' would return true for apt-add-repository.
669 apt-add-repository would get stdin which was attached to a terminal
670 (/dev/console) and would thus hang when running during boot. (LP: 831505)
671 This was done by changing all users of util.subp to have None input unless
672 specified
673 - Add some debug info to the console when cloud-init runs.
674 This is useful if debugging, IP and route information is printed to the
675 console.
676 - change the mechanism for handling .ssh/authorized_keys, to update entries
677 rather than appending. This ensures that the authorized_keys that are
678 being inserted actually do something (LP: #434076, LP: #833499)
679 - log warning on failure to set hostname (LP: #832175)
680 - upstart/cloud-init-nonet.conf: wait for all network interfaces to be up
681 allow for the possibility of /var/run != /run.
682 - DataSourceNoCloud, DataSourceOVF : do not provide a default hostname.
683 This way the configured hostname of the system will be used if not provided
684 by metadata (LP: #838280)
685 - DataSourceOVF: change the default instance id to 'iid-dsovf' from 'nocloud'
686 - Improve the OVF documentation, and provide a simple command line
687 tool for creating a useful ISO file.
688
6890.6.1:
690 - fix bug in fixing permission on /var/log/cloud-init.log (LP: #704509)
691 - improve comment strings in rsyslog file tools/21-cloudinit.conf
692 - add previous-instance-id and previous-datasource files to datadir
693 - add 'datasource' file to instance dir
694 - add setting of passwords and enabling/disabling of PasswordAuthentication
695 for sshd. By default no changes are done to sshd.
696 - fix for puppet configuration options (LP: #709946) [Ryan Lane]
697 - fix pickling of DataSource, which broke seeding.
698 - turn resize_rootfs default to True
699 - avoid mounts in DataSourceOVF if 'read' on device fails
700 'mount /dev/sr0' for an empty virtual cdrom device was taking 18 seconds
701 - add 'manual_cache_clean' option to select manual cleaning of
702 the /var/lib/cloud/instance/ link, for a data source that might
703 not be present on every boot
704 - make DataSourceEc2 retries and timeout configurable
705 - add helper routines for apt-get update and install
706 - add 'bootcmd' like 'runcmd' to cloud-config syntax for running things early
707 - move from '#opt_include' in config file format to conf_d.
708 ie, now files in /etc/cloud.cfg.d/ is read rather than reading
709 '#opt_include <filename>' or '#include <filename>' in cloud.cfg
710 - allow /etc/hosts to be written from hosts.tmpl. which allows
711 getting local-hostname into /etc/hosts (LP: #720440)
712 - better handle startup if there is no eth0 (LP: #714807)
713 - update rather than append in puppet config [Marc Cluet]
714 - add cloud-config for mcollective [Marc Cluet]
7150.6.0:
716 - change permissions of /var/log/cloud-init.log to accomodate
717 syslog writing to it (LP: #704509)
718 - rework of /var/lib/cloud layout
719 - remove updates-check (LP: #653220)
720 - support resizing / on first boot (enabled by default)
721 - added support for running CloudConfig modules at cloud-init time
722 rather than cloud-config time, and the new 'cloud_init_modules'
723 entry in cloud.cfg to indicate which should run then.
724 The driving force behind this was to have the rsyslog module
725 able to run before rsyslog even runs so that a restart would
726 not be needed (rsyslog on ubuntu runs on 'filesystem')
727 - moved setting and updating of hostname to cloud_init_modules
728 this allows the user to easily disable these from running.
729 This also means:
730 - the semaphore name for 'set_hostname' and 'update_hostname'
731 changes to 'config_set_hostname' and 'config_update_hostname'
732 - added cloud-config option 'hostname' for setting hostname
733 - moved upstart/cloud-run-user-script.conf to upstart/cloud-final.conf
734 - cloud-final.conf now runs runs cloud-config modules similar
735 to cloud-config and cloud-init.
736 - LP: #653271
737 - added writing of "boot-finished" to /var/lib/cloud/instance/boot-finished
738 this is the last thing done, indicating cloud-init is finished booting
739 - writes message to console with timestamp and uptime
740 - write ssh keys to console as one of the last things done
741 this is to ensure they don't get run off the 'get-console-ouptut' buffer
742 - user_scripts run via cloud-final and thus semaphore renamed from
743 user_scripts to config_user_scripts
744 - add support for redirecting output of cloud-init, cloud-config, cloud-final
745 via the config file, or user data config file
746 - add support for posting data about the instance to a url (phone_home)
747 - add minimal OVF transport (iso) support
748 - make DataSources that are attempted dynamic and configurable from
749 system config. changen "cloud_type: auto" as configuration for this
750 to 'datasource_list: [ "Ec2" ]'. Each of the items in that list
751 must be modules that can be loaded by "DataSource<item>"
752 - add 'timezone' option to cloud-config (LP: #645458)
753 - Added an additional archive format, that can be used for multi-part
754 input to cloud-init. This may be more user friendly then mime-multipart
755 See example in doc/examples/cloud-config-archive.txt (LP: #641504)
756 - add support for reading Rightscale style user data (LP: #668400)
757 and acting on it in cloud-config (cc_rightscale_userdata.py)
758 - make the message on 'disable_root' more clear (LP: #672417)
759 - do not require public key if private is given in ssh cloud-config
760 (LP: #648905)
761# vi: syntax=text textwidth=79
7620
=== removed file 'HACKING.rst'
--- HACKING.rst 2014-08-26 18:53:44 +0000
+++ HACKING.rst 1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
1=====================
2Hacking on cloud-init
3=====================
4
5To get changes into cloud-init, the process to follow is:
6
7* If you have not already, be sure to sign the CCA:
8
9 - `Canonical Contributor Agreement`_
10
11* Get your changes into a local bzr branch.
12 Initialize a repo, and checkout trunk (init repo is to share bzr info across multiple checkouts, its different than git):
13
14 - ``bzr init-repo cloud-init``
15 - ``bzr branch lp:cloud-init trunk.dist``
16 - ``bzr branch trunk.dist my-topic-branch``
17
18* Commit your changes (note, you can make multiple commits, fixes, more commits.):
19
20 - ``bzr commit``
21
22* Check pep8 and test, and address any issues:
23
24 - ``make test pep8``
25
26* Push to launchpad to a personal branch:
27
28 - ``bzr push lp:~<YOUR_USERNAME>/cloud-init/<BRANCH_NAME>``
29
30* Propose that for a merge into lp:cloud-init via web browser.
31
32 - Open the branch in `Launchpad`_
33
34 - It will typically be at ``https://code.launchpad.net/<YOUR_USERNAME>/<PROJECT>/<BRANCH_NAME>``
35 - ie. https://code.launchpad.net/~smoser/cloud-init/mybranch
36
37* Click 'Propose for merging'
38* Select 'lp:cloud-init' as the target branch
39
40Then, someone on cloud-init-dev (currently `Scott Moser`_ and `Joshua Harlow`_) will
41review your changes and follow up in the merge request.
42
43Feel free to ping and/or join #cloud-init on freenode (irc) if you have any questions.
44
45.. _Launchpad: https://launchpad.net
46.. _Canonical Contributor Agreement: http://www.canonical.com/contributors
47.. _Scott Moser: https://launchpad.net/~smoser
48.. _Joshua Harlow: https://launchpad.net/~harlowja
490
=== removed file 'LICENSE'
--- LICENSE 2011-09-21 19:08:17 +0000
+++ LICENSE 1970-01-01 00:00:00 +0000
@@ -1,674 +0,0 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 3, 29 June 2007
3
4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The GNU General Public License is a free, copyleft license for
11software and other kinds of works.
12
13 The licenses for most software and other practical works are designed
14to take away your freedom to share and change the works. By contrast,
15the GNU General Public License is intended to guarantee your freedom to
16share and change all versions of a program--to make sure it remains free
17software for all its users. We, the Free Software Foundation, use the
18GNU General Public License for most of our software; it applies also to
19any other work released this way by its authors. You can apply it to
20your programs, too.
21
22 When we speak of free software, we are referring to freedom, not
23price. Our General Public Licenses are designed to make sure that you
24have the freedom to distribute copies of free software (and charge for
25them if you wish), that you receive source code or can get it if you
26want it, that you can change the software or use pieces of it in new
27free programs, and that you know you can do these things.
28
29 To protect your rights, we need to prevent others from denying you
30these rights or asking you to surrender the rights. Therefore, you have
31certain responsibilities if you distribute copies of the software, or if
32you modify it: responsibilities to respect the freedom of others.
33
34 For example, if you distribute copies of such a program, whether
35gratis or for a fee, you must pass on to the recipients the same
36freedoms that you received. You must make sure that they, too, receive
37or can get the source code. And you must show them these terms so they
38know their rights.
39
40 Developers that use the GNU GPL protect your rights with two steps:
41(1) assert copyright on the software, and (2) offer you this License
42giving you legal permission to copy, distribute and/or modify it.
43
44 For the developers' and authors' protection, the GPL clearly explains
45that there is no warranty for this free software. For both users' and
46authors' sake, the GPL requires that modified versions be marked as
47changed, so that their problems will not be attributed erroneously to
48authors of previous versions.
49
50 Some devices are designed to deny users access to install or run
51modified versions of the software inside them, although the manufacturer
52can do so. This is fundamentally incompatible with the aim of
53protecting users' freedom to change the software. The systematic
54pattern of such abuse occurs in the area of products for individuals to
55use, which is precisely where it is most unacceptable. Therefore, we
56have designed this version of the GPL to prohibit the practice for those
57products. If such problems arise substantially in other domains, we
58stand ready to extend this provision to those domains in future versions
59of the GPL, as needed to protect the freedom of users.
60
61 Finally, every program is threatened constantly by software patents.
62States should not allow patents to restrict development and use of
63software on general-purpose computers, but in those that do, we wish to
64avoid the special danger that patents applied to a free program could
65make it effectively proprietary. To prevent this, the GPL assures that
66patents cannot be used to render the program non-free.
67
68 The precise terms and conditions for copying, distribution and
69modification follow.
70
71 TERMS AND CONDITIONS
72
73 0. Definitions.
74
75 "This License" refers to version 3 of the GNU General Public License.
76
77 "Copyright" also means copyright-like laws that apply to other kinds of
78works, such as semiconductor masks.
79
80 "The Program" refers to any copyrightable work licensed under this
81License. Each licensee is addressed as "you". "Licensees" and
82"recipients" may be individuals or organizations.
83
84 To "modify" a work means to copy from or adapt all or part of the work
85in a fashion requiring copyright permission, other than the making of an
86exact copy. The resulting work is called a "modified version" of the
87earlier work or a work "based on" the earlier work.
88
89 A "covered work" means either the unmodified Program or a work based
90on the Program.
91
92 To "propagate" a work means to do anything with it that, without
93permission, would make you directly or secondarily liable for
94infringement under applicable copyright law, except executing it on a
95computer or modifying a private copy. Propagation includes copying,
96distribution (with or without modification), making available to the
97public, and in some countries other activities as well.
98
99 To "convey" a work means any kind of propagation that enables other
100parties to make or receive copies. Mere interaction with a user through
101a computer network, with no transfer of a copy, is not conveying.
102
103 An interactive user interface displays "Appropriate Legal Notices"
104to the extent that it includes a convenient and prominently visible
105feature that (1) displays an appropriate copyright notice, and (2)
106tells the user that there is no warranty for the work (except to the
107extent that warranties are provided), that licensees may convey the
108work under this License, and how to view a copy of this License. If
109the interface presents a list of user commands or options, such as a
110menu, a prominent item in the list meets this criterion.
111
112 1. Source Code.
113
114 The "source code" for a work means the preferred form of the work
115for making modifications to it. "Object code" means any non-source
116form of a work.
117
118 A "Standard Interface" means an interface that either is an official
119standard defined by a recognized standards body, or, in the case of
120interfaces specified for a particular programming language, one that
121is widely used among developers working in that language.
122
123 The "System Libraries" of an executable work include anything, other
124than the work as a whole, that (a) is included in the normal form of
125packaging a Major Component, but which is not part of that Major
126Component, and (b) serves only to enable use of the work with that
127Major Component, or to implement a Standard Interface for which an
128implementation is available to the public in source code form. A
129"Major Component", in this context, means a major essential component
130(kernel, window system, and so on) of the specific operating system
131(if any) on which the executable work runs, or a compiler used to
132produce the work, or an object code interpreter used to run it.
133
134 The "Corresponding Source" for a work in object code form means all
135the source code needed to generate, install, and (for an executable
136work) run the object code and to modify the work, including scripts to
137control those activities. However, it does not include the work's
138System Libraries, or general-purpose tools or generally available free
139programs which are used unmodified in performing those activities but
140which are not part of the work. For example, Corresponding Source
141includes interface definition files associated with source files for
142the work, and the source code for shared libraries and dynamically
143linked subprograms that the work is specifically designed to require,
144such as by intimate data communication or control flow between those
145subprograms and other parts of the work.
146
147 The Corresponding Source need not include anything that users
148can regenerate automatically from other parts of the Corresponding
149Source.
150
151 The Corresponding Source for a work in source code form is that
152same work.
153
154 2. Basic Permissions.
155
156 All rights granted under this License are granted for the term of
157copyright on the Program, and are irrevocable provided the stated
158conditions are met. This License explicitly affirms your unlimited
159permission to run the unmodified Program. The output from running a
160covered work is covered by this License only if the output, given its
161content, constitutes a covered work. This License acknowledges your
162rights of fair use or other equivalent, as provided by copyright law.
163
164 You may make, run and propagate covered works that you do not
165convey, without conditions so long as your license otherwise remains
166in force. You may convey covered works to others for the sole purpose
167of having them make modifications exclusively for you, or provide you
168with facilities for running those works, provided that you comply with
169the terms of this License in conveying all material for which you do
170not control copyright. Those thus making or running the covered works
171for you must do so exclusively on your behalf, under your direction
172and control, on terms that prohibit them from making any copies of
173your copyrighted material outside their relationship with you.
174
175 Conveying under any other circumstances is permitted solely under
176the conditions stated below. Sublicensing is not allowed; section 10
177makes it unnecessary.
178
179 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
181 No covered work shall be deemed part of an effective technological
182measure under any applicable law fulfilling obligations under article
18311 of the WIPO copyright treaty adopted on 20 December 1996, or
184similar laws prohibiting or restricting circumvention of such
185measures.
186
187 When you convey a covered work, you waive any legal power to forbid
188circumvention of technological measures to the extent such circumvention
189is effected by exercising rights under this License with respect to
190the covered work, and you disclaim any intention to limit operation or
191modification of the work as a means of enforcing, against the work's
192users, your or third parties' legal rights to forbid circumvention of
193technological measures.
194
195 4. Conveying Verbatim Copies.
196
197 You may convey verbatim copies of the Program's source code as you
198receive it, in any medium, provided that you conspicuously and
199appropriately publish on each copy an appropriate copyright notice;
200keep intact all notices stating that this License and any
201non-permissive terms added in accord with section 7 apply to the code;
202keep intact all notices of the absence of any warranty; and give all
203recipients a copy of this License along with the Program.
204
205 You may charge any price or no price for each copy that you convey,
206and you may offer support or warranty protection for a fee.
207
208 5. Conveying Modified Source Versions.
209
210 You may convey a work based on the Program, or the modifications to
211produce it from the Program, in the form of source code under the
212terms of section 4, provided that you also meet all of these conditions:
213
214 a) The work must carry prominent notices stating that you modified
215 it, and giving a relevant date.
216
217 b) The work must carry prominent notices stating that it is
218 released under this License and any conditions added under section
219 7. This requirement modifies the requirement in section 4 to
220 "keep intact all notices".
221
222 c) You must license the entire work, as a whole, under this
223 License to anyone who comes into possession of a copy. This
224 License will therefore apply, along with any applicable section 7
225 additional terms, to the whole of the work, and all its parts,
226 regardless of how they are packaged. This License gives no
227 permission to license the work in any other way, but it does not
228 invalidate such permission if you have separately received it.
229
230 d) If the work has interactive user interfaces, each must display
231 Appropriate Legal Notices; however, if the Program has interactive
232 interfaces that do not display Appropriate Legal Notices, your
233 work need not make them do so.
234
235 A compilation of a covered work with other separate and independent
236works, which are not by their nature extensions of the covered work,
237and which are not combined with it such as to form a larger program,
238in or on a volume of a storage or distribution medium, is called an
239"aggregate" if the compilation and its resulting copyright are not
240used to limit the access or legal rights of the compilation's users
241beyond what the individual works permit. Inclusion of a covered work
242in an aggregate does not cause this License to apply to the other
243parts of the aggregate.
244
245 6. Conveying Non-Source Forms.
246
247 You may convey a covered work in object code form under the terms
248of sections 4 and 5, provided that you also convey the
249machine-readable Corresponding Source under the terms of this License,
250in one of these ways:
251
252 a) Convey the object code in, or embodied in, a physical product
253 (including a physical distribution medium), accompanied by the
254 Corresponding Source fixed on a durable physical medium
255 customarily used for software interchange.
256
257 b) Convey the object code in, or embodied in, a physical product
258 (including a physical distribution medium), accompanied by a
259 written offer, valid for at least three years and valid for as
260 long as you offer spare parts or customer support for that product
261 model, to give anyone who possesses the object code either (1) a
262 copy of the Corresponding Source for all the software in the
263 product that is covered by this License, on a durable physical
264 medium customarily used for software interchange, for a price no
265 more than your reasonable cost of physically performing this
266 conveying of source, or (2) access to copy the
267 Corresponding Source from a network server at no charge.
268
269 c) Convey individual copies of the object code with a copy of the
270 written offer to provide the Corresponding Source. This
271 alternative is allowed only occasionally and noncommercially, and
272 only if you received the object code with such an offer, in accord
273 with subsection 6b.
274
275 d) Convey the object code by offering access from a designated
276 place (gratis or for a charge), and offer equivalent access to the
277 Corresponding Source in the same way through the same place at no
278 further charge. You need not require recipients to copy the
279 Corresponding Source along with the object code. If the place to
280 copy the object code is a network server, the Corresponding Source
281 may be on a different server (operated by you or a third party)
282 that supports equivalent copying facilities, provided you maintain
283 clear directions next to the object code saying where to find the
284 Corresponding Source. Regardless of what server hosts the
285 Corresponding Source, you remain obligated to ensure that it is
286 available for as long as needed to satisfy these requirements.
287
288 e) Convey the object code using peer-to-peer transmission, provided
289 you inform other peers where the object code and Corresponding
290 Source of the work are being offered to the general public at no
291 charge under subsection 6d.
292
293 A separable portion of the object code, whose source code is excluded
294from the Corresponding Source as a System Library, need not be
295included in conveying the object code work.
296
297 A "User Product" is either (1) a "consumer product", which means any
298tangible personal property which is normally used for personal, family,
299or household purposes, or (2) anything designed or sold for incorporation
300into a dwelling. In determining whether a product is a consumer product,
301doubtful cases shall be resolved in favor of coverage. For a particular
302product received by a particular user, "normally used" refers to a
303typical or common use of that class of product, regardless of the status
304of the particular user or of the way in which the particular user
305actually uses, or expects or is expected to use, the product. A product
306is a consumer product regardless of whether the product has substantial
307commercial, industrial or non-consumer uses, unless such uses represent
308the only significant mode of use of the product.
309
310 "Installation Information" for a User Product means any methods,
311procedures, authorization keys, or other information required to install
312and execute modified versions of a covered work in that User Product from
313a modified version of its Corresponding Source. The information must
314suffice to ensure that the continued functioning of the modified object
315code is in no case prevented or interfered with solely because
316modification has been made.
317
318 If you convey an object code work under this section in, or with, or
319specifically for use in, a User Product, and the conveying occurs as
320part of a transaction in which the right of possession and use of the
321User Product is transferred to the recipient in perpetuity or for a
322fixed term (regardless of how the transaction is characterized), the
323Corresponding Source conveyed under this section must be accompanied
324by the Installation Information. But this requirement does not apply
325if neither you nor any third party retains the ability to install
326modified object code on the User Product (for example, the work has
327been installed in ROM).
328
329 The requirement to provide Installation Information does not include a
330requirement to continue to provide support service, warranty, or updates
331for a work that has been modified or installed by the recipient, or for
332the User Product in which it has been modified or installed. Access to a
333network may be denied when the modification itself materially and
334adversely affects the operation of the network or violates the rules and
335protocols for communication across the network.
336
337 Corresponding Source conveyed, and Installation Information provided,
338in accord with this section must be in a format that is publicly
339documented (and with an implementation available to the public in
340source code form), and must require no special password or key for
341unpacking, reading or copying.
342
343 7. Additional Terms.
344
345 "Additional permissions" are terms that supplement the terms of this
346License by making exceptions from one or more of its conditions.
347Additional permissions that are applicable to the entire Program shall
348be treated as though they were included in this License, to the extent
349that they are valid under applicable law. If additional permissions
350apply only to part of the Program, that part may be used separately
351under those permissions, but the entire Program remains governed by
352this License without regard to the additional permissions.
353
354 When you convey a copy of a covered work, you may at your option
355remove any additional permissions from that copy, or from any part of
356it. (Additional permissions may be written to require their own
357removal in certain cases when you modify the work.) You may place
358additional permissions on material, added by you to a covered work,
359for which you have or can give appropriate copyright permission.
360
361 Notwithstanding any other provision of this License, for material you
362add to a covered work, you may (if authorized by the copyright holders of
363that material) supplement the terms of this License with terms:
364
365 a) Disclaiming warranty or limiting liability differently from the
366 terms of sections 15 and 16 of this License; or
367
368 b) Requiring preservation of specified reasonable legal notices or
369 author attributions in that material or in the Appropriate Legal
370 Notices displayed by works containing it; or
371
372 c) Prohibiting misrepresentation of the origin of that material, or
373 requiring that modified versions of such material be marked in
374 reasonable ways as different from the original version; or
375
376 d) Limiting the use for publicity purposes of names of licensors or
377 authors of the material; or
378
379 e) Declining to grant rights under trademark law for use of some
380 trade names, trademarks, or service marks; or
381
382 f) Requiring indemnification of licensors and authors of that
383 material by anyone who conveys the material (or modified versions of
384 it) with contractual assumptions of liability to the recipient, for
385 any liability that these contractual assumptions directly impose on
386 those licensors and authors.
387
388 All other non-permissive additional terms are considered "further
389restrictions" within the meaning of section 10. If the Program as you
390received it, or any part of it, contains a notice stating that it is
391governed by this License along with a term that is a further
392restriction, you may remove that term. If a license document contains
393a further restriction but permits relicensing or conveying under this
394License, you may add to a covered work material governed by the terms
395of that license document, provided that the further restriction does
396not survive such relicensing or conveying.
397
398 If you add terms to a covered work in accord with this section, you
399must place, in the relevant source files, a statement of the
400additional terms that apply to those files, or a notice indicating
401where to find the applicable terms.
402
403 Additional terms, permissive or non-permissive, may be stated in the
404form of a separately written license, or stated as exceptions;
405the above requirements apply either way.
406
407 8. Termination.
408
409 You may not propagate or modify a covered work except as expressly
410provided under this License. Any attempt otherwise to propagate or
411modify it is void, and will automatically terminate your rights under
412this License (including any patent licenses granted under the third
413paragraph of section 11).
414
415 However, if you cease all violation of this License, then your
416license from a particular copyright holder is reinstated (a)
417provisionally, unless and until the copyright holder explicitly and
418finally terminates your license, and (b) permanently, if the copyright
419holder fails to notify you of the violation by some reasonable means
420prior to 60 days after the cessation.
421
422 Moreover, your license from a particular copyright holder is
423reinstated permanently if the copyright holder notifies you of the
424violation by some reasonable means, this is the first time you have
425received notice of violation of this License (for any work) from that
426copyright holder, and you cure the violation prior to 30 days after
427your receipt of the notice.
428
429 Termination of your rights under this section does not terminate the
430licenses of parties who have received copies or rights from you under
431this License. If your rights have been terminated and not permanently
432reinstated, you do not qualify to receive new licenses for the same
433material under section 10.
434
435 9. Acceptance Not Required for Having Copies.
436
437 You are not required to accept this License in order to receive or
438run a copy of the Program. Ancillary propagation of a covered work
439occurring solely as a consequence of using peer-to-peer transmission
440to receive a copy likewise does not require acceptance. However,
441nothing other than this License grants you permission to propagate or
442modify any covered work. These actions infringe copyright if you do
443not accept this License. Therefore, by modifying or propagating a
444covered work, you indicate your acceptance of this License to do so.
445
446 10. Automatic Licensing of Downstream Recipients.
447
448 Each time you convey a covered work, the recipient automatically
449receives a license from the original licensors, to run, modify and
450propagate that work, subject to this License. You are not responsible
451for enforcing compliance by third parties with this License.
452
453 An "entity transaction" is a transaction transferring control of an
454organization, or substantially all assets of one, or subdividing an
455organization, or merging organizations. If propagation of a covered
456work results from an entity transaction, each party to that
457transaction who receives a copy of the work also receives whatever
458licenses to the work the party's predecessor in interest had or could
459give under the previous paragraph, plus a right to possession of the
460Corresponding Source of the work from the predecessor in interest, if
461the predecessor has it or can get it with reasonable efforts.
462
463 You may not impose any further restrictions on the exercise of the
464rights granted or affirmed under this License. For example, you may
465not impose a license fee, royalty, or other charge for exercise of
466rights granted under this License, and you may not initiate litigation
467(including a cross-claim or counterclaim in a lawsuit) alleging that
468any patent claim is infringed by making, using, selling, offering for
469sale, or importing the Program or any portion of it.
470
471 11. Patents.
472
473 A "contributor" is a copyright holder who authorizes use under this
474License of the Program or a work on which the Program is based. The
475work thus licensed is called the contributor's "contributor version".
476
477 A contributor's "essential patent claims" are all patent claims
478owned or controlled by the contributor, whether already acquired or
479hereafter acquired, that would be infringed by some manner, permitted
480by this License, of making, using, or selling its contributor version,
481but do not include claims that would be infringed only as a
482consequence of further modification of the contributor version. For
483purposes of this definition, "control" includes the right to grant
484patent sublicenses in a manner consistent with the requirements of
485this License.
486
487 Each contributor grants you a non-exclusive, worldwide, royalty-free
488patent license under the contributor's essential patent claims, to
489make, use, sell, offer for sale, import and otherwise run, modify and
490propagate the contents of its contributor version.
491
492 In the following three paragraphs, a "patent license" is any express
493agreement or commitment, however denominated, not to enforce a patent
494(such as an express permission to practice a patent or covenant not to
495sue for patent infringement). To "grant" such a patent license to a
496party means to make such an agreement or commitment not to enforce a
497patent against the party.
498
499 If you convey a covered work, knowingly relying on a patent license,
500and the Corresponding Source of the work is not available for anyone
501to copy, free of charge and under the terms of this License, through a
502publicly available network server or other readily accessible means,
503then you must either (1) cause the Corresponding Source to be so
504available, or (2) arrange to deprive yourself of the benefit of the
505patent license for this particular work, or (3) arrange, in a manner
506consistent with the requirements of this License, to extend the patent
507license to downstream recipients. "Knowingly relying" means you have
508actual knowledge that, but for the patent license, your conveying the
509covered work in a country, or your recipient's use of the covered work
510in a country, would infringe one or more identifiable patents in that
511country that you have reason to believe are valid.
512
513 If, pursuant to or in connection with a single transaction or
514arrangement, you convey, or propagate by procuring conveyance of, a
515covered work, and grant a patent license to some of the parties
516receiving the covered work authorizing them to use, propagate, modify
517or convey a specific copy of the covered work, then the patent license
518you grant is automatically extended to all recipients of the covered
519work and works based on it.
520
521 A patent license is "discriminatory" if it does not include within
522the scope of its coverage, prohibits the exercise of, or is
523conditioned on the non-exercise of one or more of the rights that are
524specifically granted under this License. You may not convey a covered
525work if you are a party to an arrangement with a third party that is
526in the business of distributing software, under which you make payment
527to the third party based on the extent of your activity of conveying
528the work, and under which the third party grants, to any of the
529parties who would receive the covered work from you, a discriminatory
530patent license (a) in connection with copies of the covered work
531conveyed by you (or copies made from those copies), or (b) primarily
532for and in connection with specific products or compilations that
533contain the covered work, unless you entered into that arrangement,
534or that patent license was granted, prior to 28 March 2007.
535
536 Nothing in this License shall be construed as excluding or limiting
537any implied license or other defenses to infringement that may
538otherwise be available to you under applicable patent law.
539
540 12. No Surrender of Others' Freedom.
541
542 If conditions are imposed on you (whether by court order, agreement or
543otherwise) that contradict the conditions of this License, they do not
544excuse you from the conditions of this License. If you cannot convey a
545covered work so as to satisfy simultaneously your obligations under this
546License and any other pertinent obligations, then as a consequence you may
547not convey it at all. For example, if you agree to terms that obligate you
548to collect a royalty for further conveying from those to whom you convey
549the Program, the only way you could satisfy both those terms and this
550License would be to refrain entirely from conveying the Program.
551
552 13. Use with the GNU Affero General Public License.
553
554 Notwithstanding any other provision of this License, you have
555permission to link or combine any covered work with a work licensed
556under version 3 of the GNU Affero General Public License into a single
557combined work, and to convey the resulting work. The terms of this
558License will continue to apply to the part which is the covered work,
559but the special requirements of the GNU Affero General Public License,
560section 13, concerning interaction through a network will apply to the
561combination as such.
562
563 14. Revised Versions of this License.
564
565 The Free Software Foundation may publish revised and/or new versions of
566the GNU General Public License from time to time. Such new versions will
567be similar in spirit to the present version, but may differ in detail to
568address new problems or concerns.
569
570 Each version is given a distinguishing version number. If the
571Program specifies that a certain numbered version of the GNU General
572Public License "or any later version" applies to it, you have the
573option of following the terms and conditions either of that numbered
574version or of any later version published by the Free Software
575Foundation. If the Program does not specify a version number of the
576GNU General Public License, you may choose any version ever published
577by the Free Software Foundation.
578
579 If the Program specifies that a proxy can decide which future
580versions of the GNU General Public License can be used, that proxy's
581public statement of acceptance of a version permanently authorizes you
582to choose that version for the Program.
583
584 Later license versions may give you additional or different
585permissions. However, no additional obligations are imposed on any
586author or copyright holder as a result of your choosing to follow a
587later version.
588
589 15. Disclaimer of Warranty.
590
591 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
600 16. Limitation of Liability.
601
602 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610SUCH DAMAGES.
611
612 17. Interpretation of Sections 15 and 16.
613
614 If the disclaimer of warranty and limitation of liability provided
615above cannot be given local legal effect according to their terms,
616reviewing courts shall apply local law that most closely approximates
617an absolute waiver of all civil liability in connection with the
618Program, unless a warranty or assumption of liability accompanies a
619copy of the Program in return for a fee.
620
621 END OF TERMS AND CONDITIONS
622
623 How to Apply These Terms to Your New Programs
624
625 If you develop a new program, and you want it to be of the greatest
626possible use to the public, the best way to achieve this is to make it
627free software which everyone can redistribute and change under these terms.
628
629 To do so, attach the following notices to the program. It is safest
630to attach them to the start of each source file to most effectively
631state the exclusion of warranty; and each file should have at least
632the "copyright" line and a pointer to where the full notice is found.
633
634 <one line to give the program's name and a brief idea of what it does.>
635 Copyright (C) <year> <name of author>
636
637 This program is free software: you can redistribute it and/or modify
638 it under the terms of the GNU General Public License as published by
639 the Free Software Foundation, either version 3 of the License, or
640 (at your option) any later version.
641
642 This program is distributed in the hope that it will be useful,
643 but WITHOUT ANY WARRANTY; without even the implied warranty of
644 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 GNU General Public License for more details.
646
647 You should have received a copy of the GNU General Public License
648 along with this program. If not, see <http://www.gnu.org/licenses/>.
649
650Also add information on how to contact you by electronic and paper mail.
651
652 If the program does terminal interaction, make it output a short
653notice like this when it starts in an interactive mode:
654
655 <program> Copyright (C) <year> <name of author>
656 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 This is free software, and you are welcome to redistribute it
658 under certain conditions; type `show c' for details.
659
660The hypothetical commands `show w' and `show c' should show the appropriate
661parts of the General Public License. Of course, your program's commands
662might be different; for a GUI interface, you would use an "about box".
663
664 You should also get your employer (if you work as a programmer) or school,
665if any, to sign a "copyright disclaimer" for the program, if necessary.
666For more information on this, and how to apply and follow the GNU GPL, see
667<http://www.gnu.org/licenses/>.
668
669 The GNU General Public License does not permit incorporating your program
670into proprietary programs. If your program is a subroutine library, you
671may consider it more useful to permit linking proprietary applications with
672the library. If this is what you want to do, use the GNU Lesser General
673Public License instead of this License. But first, please read
674<http://www.gnu.org/philosophy/why-not-lgpl.html>.
6750
=== removed file 'MANIFEST.in'
--- MANIFEST.in 2015-01-21 20:14:24 +0000
+++ MANIFEST.in 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1include *.py MANIFEST.in ChangeLog
2global-include *.txt *.rst *.ini *.in *.conf *.cfg *.sh
3graft tools
4prune build
5prune dist
6prune .tox
7prune .bzr
8exclude .bzrignore
90
=== removed file 'Makefile'
--- Makefile 2016-03-04 06:45:58 +0000
+++ Makefile 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
1CWD=$(shell pwd)
2PYVER ?= 3
3noseopts ?= -v
4
5YAML_FILES=$(shell find cloudinit bin tests tools -name "*.yaml" -type f )
6YAML_FILES+=$(shell find doc/examples -name "cloud-config*.txt" -type f )
7
8CHANGELOG_VERSION=$(shell $(CWD)/tools/read-version)
9CODE_VERSION=$(shell python -c "from cloudinit import version; print version.version_string()")
10
11PIP_INSTALL := pip install
12
13ifeq ($(PYVER),3)
14 pyflakes = pyflakes3
15 unittests = unittest3
16 yaml = yaml
17else
18ifeq ($(PYVER),2)
19 pyflakes = pyflakes
20 unittests = unittest
21else
22 pyflakes = pyflakes pyflakes3
23 unittests = unittest unittest3
24endif
25endif
26
27ifeq ($(distro),)
28 distro = redhat
29endif
30
31all: check
32
33check: check_version pep8 $(pyflakes) test $(yaml)
34
35pep8:
36 @$(CWD)/tools/run-pep8
37
38pyflakes:
39 @$(CWD)/tools/run-pyflakes
40
41pyflakes3:
42 @$(CWD)/tools/run-pyflakes3
43
44unittest: clean_pyc
45 nosetests $(noseopts) tests/unittests
46
47unittest3: clean_pyc
48 nosetests3 $(noseopts) tests/unittests
49
50pip-requirements:
51 @echo "Installing cloud-init dependencies..."
52 $(PIP_INSTALL) -r "$@.txt" -q
53
54pip-test-requirements:
55 @echo "Installing cloud-init test dependencies..."
56 $(PIP_INSTALL) -r "$@.txt" -q
57
58test: $(unittests)
59
60check_version:
61 @if [ "$(CHANGELOG_VERSION)" != "$(CODE_VERSION)" ]; then \
62 echo "Error: ChangeLog version $(CHANGELOG_VERSION)" \
63 "not equal to code version $(CODE_VERSION)"; exit 2; \
64 else true; fi
65
66clean_pyc:
67 @find . -type f -name "*.pyc" -delete
68
69clean: clean_pyc
70 rm -rf /var/log/cloud-init.log /var/lib/cloud/
71
72yaml:
73 @$(CWD)/tools/validate-yaml.py $(YAML_FILES)
74
75rpm:
76 ./packages/brpm --distro $(distro)
77
78deb:
79 ./packages/bddeb
80
81.PHONY: test pyflakes pyflakes3 clean pep8 rpm deb yaml check_version
82.PHONY: pip-test-requirements pip-requirements clean_pyc unittest unittest3
830
=== added file 'README'
--- README 1970-01-01 00:00:00 +0000
+++ README 2016-08-10 14:35:36 +0000
@@ -0,0 +1,11 @@
1cloud-init development has moved its revision control to git.
2It is available at
3 https://code.launchpad.net/cloud-init
4
5Clone with
6 git clone https://git.launchpad.net/cloud-init
7or
8 git clone git+ssh://git.launchpad.net/cloud-ini
9
10For more information see
11 https://git.launchpad.net/cloud-init/tree/HACKING.rst
012
=== removed file 'TODO.rst'
--- TODO.rst 2014-07-07 20:03:32 +0000
+++ TODO.rst 1970-01-01 00:00:00 +0000
@@ -1,43 +0,0 @@
1==============================================
2Things that cloud-init may do (better) someday
3==============================================
4
5- Consider making ``failsafe`` ``DataSource``
6 - sets the user password, writing it to console
7
8- Consider a ``previous`` ``DataSource``, if no other data source is
9 found, fall back to the ``previous`` one that worked.
10- Rewrite ``cloud-init-query`` (currently not implemented)
11- Possibly have a ``DataSource`` expose explicit fields:
12
13 - instance-id
14 - hostname
15 - mirror
16 - release
17 - ssh public keys
18
19- Remove the conversion of the ubuntu network interface format conversion
20 to a RH/fedora format and replace it with a top level format that uses
21 the netcf libraries format instead (which itself knows how to translate
22 into the specific formats). See for example `netcf`_ which seems to be
23 an active project that has this capability.
24- Replace the ``apt*`` modules with variants that now use the distro classes
25 to perform distro independent packaging commands (wherever possible).
26- Replace some the LOG.debug calls with a LOG.info where appropriate instead
27 of how right now there is really only 2 levels (``WARN`` and ``DEBUG``)
28- Remove the ``cc_`` prefix for config modules, either have them fully
29 specified (ie ``cloudinit.config.resizefs``) or by default only look in
30 the ``cloudinit.config`` namespace for these modules (or have a combination
31 of the above), this avoids having to understand where your modules are
32 coming from (which can be altered by the current python inclusion path)
33- Instead of just warning when a module is being ran on a ``unknown``
34 distribution perhaps we should not run that module in that case? Or we might
35 want to start reworking those modules so they will run on all
36 distributions? Or if that is not the case, then maybe we want to allow
37 fully specified python paths for modules and start encouraging
38 packages of ``ubuntu`` modules, packages of ``rhel`` specific modules that
39 people can add instead of having them all under the cloud-init ``root``
40 tree? This might encourage more development of other modules instead of
41 having to go edit the cloud-init code to accomplish this.
42
43.. _netcf: https://fedorahosted.org/netcf/
440
=== removed directory 'bin'
=== removed file 'bin/cloud-init'
--- bin/cloud-init 2016-04-15 17:54:05 +0000
+++ bin/cloud-init 1970-01-01 00:00:00 +0000
@@ -1,673 +0,0 @@
1#!/usr/bin/python
2# vi: ts=4 expandtab
3#
4# Copyright (C) 2012 Canonical Ltd.
5# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
6# Copyright (C) 2012 Yahoo! Inc.
7#
8# Author: Scott Moser <scott.moser@canonical.com>
9# Author: Juerg Haefliger <juerg.haefliger@hp.com>
10# Author: Joshua Harlow <harlowja@yahoo-inc.com>
11#
12# This program is free software: you can redistribute it and/or modify
13# it under the terms of the GNU General Public License version 3, as
14# published by the Free Software Foundation.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24import argparse
25import json
26import os
27import sys
28import time
29import tempfile
30import traceback
31
32# This is more just for running from the bin folder so that
33# cloud-init binary can find the cloudinit module
34possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
35 sys.argv[0]), os.pardir, os.pardir))
36if os.path.exists(os.path.join(possible_topdir, "cloudinit", "__init__.py")):
37 sys.path.insert(0, possible_topdir)
38
39from cloudinit import patcher
40patcher.patch()
41
42from cloudinit import log as logging
43from cloudinit import netinfo
44from cloudinit import signal_handler
45from cloudinit import sources
46from cloudinit import stages
47from cloudinit import templater
48from cloudinit import util
49from cloudinit import reporting
50from cloudinit.reporting import events
51from cloudinit import version
52
53from cloudinit.settings import (PER_INSTANCE, PER_ALWAYS, PER_ONCE,
54 CLOUD_CONFIG)
55
56
57# Pretty little cheetah formatted welcome message template
58WELCOME_MSG_TPL = ("Cloud-init v. ${version} running '${action}' at "
59 "${timestamp}. Up ${uptime} seconds.")
60
61# Module section template
62MOD_SECTION_TPL = "cloud_%s_modules"
63
64# Things u can query on
65QUERY_DATA_TYPES = [
66 'data',
67 'data_raw',
68 'instance_id',
69]
70
71# Frequency shortname to full name
72# (so users don't have to remember the full name...)
73FREQ_SHORT_NAMES = {
74 'instance': PER_INSTANCE,
75 'always': PER_ALWAYS,
76 'once': PER_ONCE,
77}
78
79LOG = logging.getLogger()
80
81
82# Used for when a logger may not be active
83# and we still want to print exceptions...
84def print_exc(msg=''):
85 if msg:
86 sys.stderr.write("%s\n" % (msg))
87 sys.stderr.write('-' * 60)
88 sys.stderr.write("\n")
89 traceback.print_exc(file=sys.stderr)
90 sys.stderr.write('-' * 60)
91 sys.stderr.write("\n")
92
93
94def welcome(action, msg=None):
95 if not msg:
96 msg = welcome_format(action)
97 util.multi_log("%s\n" % (msg),
98 console=False, stderr=True, log=LOG)
99 return msg
100
101
102def welcome_format(action):
103 tpl_params = {
104 'version': version.version_string(),
105 'uptime': util.uptime(),
106 'timestamp': util.time_rfc2822(),
107 'action': action,
108 }
109 return templater.render_string(WELCOME_MSG_TPL, tpl_params)
110
111
112def extract_fns(args):
113 # Files are already opened so lets just pass that along
114 # since it would of broke if it couldn't have
115 # read that file already...
116 fn_cfgs = []
117 if args.files:
118 for fh in args.files:
119 # The realpath is more useful in logging
120 # so lets resolve to that...
121 fn_cfgs.append(os.path.realpath(fh.name))
122 return fn_cfgs
123
124
125def run_module_section(mods, action_name, section):
126 full_section_name = MOD_SECTION_TPL % (section)
127 (which_ran, failures) = mods.run_section(full_section_name)
128 total_attempted = len(which_ran) + len(failures)
129 if total_attempted == 0:
130 msg = ("No '%s' modules to run"
131 " under section '%s'") % (action_name, full_section_name)
132 sys.stderr.write("%s\n" % (msg))
133 LOG.debug(msg)
134 return []
135 else:
136 LOG.debug("Ran %s modules with %s failures",
137 len(which_ran), len(failures))
138 return failures
139
140
141def apply_reporting_cfg(cfg):
142 if cfg.get('reporting'):
143 reporting.update_configuration(cfg.get('reporting'))
144
145
146def main_init(name, args):
147 deps = [sources.DEP_FILESYSTEM, sources.DEP_NETWORK]
148 if args.local:
149 deps = [sources.DEP_FILESYSTEM]
150
151 if not args.local:
152 # See doc/kernel-cmdline.txt
153 #
154 # This is used in maas datasource, in "ephemeral" (read-only root)
155 # environment where the instance netboots to iscsi ro root.
156 # and the entity that controls the pxe config has to configure
157 # the maas datasource.
158 #
159 # Could be used elsewhere, only works on network based (not local).
160 root_name = "%s.d" % (CLOUD_CONFIG)
161 target_fn = os.path.join(root_name, "91_kernel_cmdline_url.cfg")
162 util.read_write_cmdline_url(target_fn)
163
164 # Cloud-init 'init' stage is broken up into the following sub-stages
165 # 1. Ensure that the init object fetches its config without errors
166 # 2. Setup logging/output redirections with resultant config (if any)
167 # 3. Initialize the cloud-init filesystem
168 # 4. Check if we can stop early by looking for various files
169 # 5. Fetch the datasource
170 # 6. Connect to the current instance location + update the cache
171 # 7. Consume the userdata (handlers get activated here)
172 # 8. Construct the modules object
173 # 9. Adjust any subsequent logging/output redirections using the modules
174 # objects config as it may be different from init object
175 # 10. Run the modules for the 'init' stage
176 # 11. Done!
177 if not args.local:
178 w_msg = welcome_format(name)
179 else:
180 w_msg = welcome_format("%s-local" % (name))
181 init = stages.Init(ds_deps=deps, reporter=args.reporter)
182 # Stage 1
183 init.read_cfg(extract_fns(args))
184 # Stage 2
185 outfmt = None
186 errfmt = None
187 try:
188 LOG.debug("Closing stdin")
189 util.close_stdin()
190 (outfmt, errfmt) = util.fixup_output(init.cfg, name)
191 except:
192 util.logexc(LOG, "Failed to setup output redirection!")
193 print_exc("Failed to setup output redirection!")
194 if args.debug:
195 # Reset so that all the debug handlers are closed out
196 LOG.debug(("Logging being reset, this logger may no"
197 " longer be active shortly"))
198 logging.resetLogging()
199 logging.setupLogging(init.cfg)
200 apply_reporting_cfg(init.cfg)
201
202 # Any log usage prior to setupLogging above did not have local user log
203 # config applied. We send the welcome message now, as stderr/out have
204 # been redirected and log now configured.
205 welcome(name, msg=w_msg)
206
207 # Stage 3
208 try:
209 init.initialize()
210 except Exception:
211 util.logexc(LOG, "Failed to initialize, likely bad things to come!")
212 # Stage 4
213 path_helper = init.paths
214 if not args.local:
215 existing = "trust"
216 sys.stderr.write("%s\n" % (netinfo.debug_info()))
217 LOG.debug(("Checking to see if files that we need already"
218 " exist from a previous run that would allow us"
219 " to stop early."))
220 stop_files = [
221 os.path.join(path_helper.get_cpath("data"), "no-net"),
222 path_helper.get_ipath_cur("obj_pkl"),
223 ]
224 existing_files = []
225 for fn in stop_files:
226 try:
227 c = util.load_file(fn)
228 if len(c):
229 existing_files.append((fn, len(c)))
230 except Exception:
231 pass
232 if existing_files:
233 LOG.debug("Exiting early due to the existence of %s files",
234 existing_files)
235 return (None, [])
236 else:
237 LOG.debug("Execution continuing, no previous run detected that"
238 " would allow us to stop early.")
239 else:
240 existing = "check"
241 if util.get_cfg_option_bool(init.cfg, 'manual_cache_clean', False):
242 existing = "trust"
243
244 init.purge_cache()
245 # Delete the non-net file as well
246 util.del_file(os.path.join(path_helper.get_cpath("data"), "no-net"))
247
248 # Stage 5
249 try:
250 init.fetch(existing=existing)
251 except sources.DataSourceNotFoundException:
252 # In the case of 'cloud-init init' without '--local' it is a bit
253 # more likely that the user would consider it failure if nothing was
254 # found. When using upstart it will also mentions job failure
255 # in console log if exit code is != 0.
256 if args.local:
257 LOG.debug("No local datasource found")
258 else:
259 util.logexc(LOG, ("No instance datasource found!"
260 " Likely bad things to come!"))
261 if not args.force:
262 init.apply_network_config()
263 if args.local:
264 return (None, [])
265 else:
266 return (None, ["No instance datasource found."])
267
268 if args.local:
269 if not init.ds_restored:
270 # if local mode and the datasource was not restored from cache
271 # (this is not first boot) then apply networking.
272 init.apply_network_config()
273 else:
274 LOG.debug("skipping networking config from restored datasource.")
275
276 # Stage 6
277 iid = init.instancify()
278 LOG.debug("%s will now be targeting instance id: %s", name, iid)
279 init.update()
280 # Stage 7
281 try:
282 # Attempt to consume the data per instance.
283 # This may run user-data handlers and/or perform
284 # url downloads and such as needed.
285 (ran, _results) = init.cloudify().run('consume_data',
286 init.consume_data,
287 args=[PER_INSTANCE],
288 freq=PER_INSTANCE)
289 if not ran:
290 # Just consume anything that is set to run per-always
291 # if nothing ran in the per-instance code
292 #
293 # See: https://bugs.launchpad.net/bugs/819507 for a little
294 # reason behind this...
295 init.consume_data(PER_ALWAYS)
296 except Exception:
297 util.logexc(LOG, "Consuming user data failed!")
298 return (init.datasource, ["Consuming user data failed!"])
299
300 apply_reporting_cfg(init.cfg)
301
302 # Stage 8 - re-read and apply relevant cloud-config to include user-data
303 mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
304 # Stage 9
305 try:
306 outfmt_orig = outfmt
307 errfmt_orig = errfmt
308 (outfmt, errfmt) = util.get_output_cfg(mods.cfg, name)
309 if outfmt_orig != outfmt or errfmt_orig != errfmt:
310 LOG.warn("Stdout, stderr changing to (%s, %s)", outfmt, errfmt)
311 (outfmt, errfmt) = util.fixup_output(mods.cfg, name)
312 except:
313 util.logexc(LOG, "Failed to re-adjust output redirection!")
314 logging.setupLogging(mods.cfg)
315
316 # Stage 10
317 return (init.datasource, run_module_section(mods, name, name))
318
319
320def main_modules(action_name, args):
321 name = args.mode
322 # Cloud-init 'modules' stages are broken up into the following sub-stages
323 # 1. Ensure that the init object fetches its config without errors
324 # 2. Get the datasource from the init object, if it does
325 # not exist then that means the main_init stage never
326 # worked, and thus this stage can not run.
327 # 3. Construct the modules object
328 # 4. Adjust any subsequent logging/output redirections using
329 # the modules objects configuration
330 # 5. Run the modules for the given stage name
331 # 6. Done!
332 w_msg = welcome_format("%s:%s" % (action_name, name))
333 init = stages.Init(ds_deps=[], reporter=args.reporter)
334 # Stage 1
335 init.read_cfg(extract_fns(args))
336 # Stage 2
337 try:
338 init.fetch(existing="trust")
339 except sources.DataSourceNotFoundException:
340 # There was no datasource found, theres nothing to do
341 msg = ('Can not apply stage %s, no datasource found! Likely bad '
342 'things to come!' % name)
343 util.logexc(LOG, msg)
344 print_exc(msg)
345 if not args.force:
346 return [(msg)]
347 # Stage 3
348 mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
349 # Stage 4
350 try:
351 LOG.debug("Closing stdin")
352 util.close_stdin()
353 util.fixup_output(mods.cfg, name)
354 except:
355 util.logexc(LOG, "Failed to setup output redirection!")
356 if args.debug:
357 # Reset so that all the debug handlers are closed out
358 LOG.debug(("Logging being reset, this logger may no"
359 " longer be active shortly"))
360 logging.resetLogging()
361 logging.setupLogging(mods.cfg)
362 apply_reporting_cfg(init.cfg)
363
364 # now that logging is setup and stdout redirected, send welcome
365 welcome(name, msg=w_msg)
366
367 # Stage 5
368 return run_module_section(mods, name, name)
369
370
371def main_query(name, _args):
372 raise NotImplementedError(("Action '%s' is not"
373 " currently implemented") % (name))
374
375
376def main_single(name, args):
377 # Cloud-init single stage is broken up into the following sub-stages
378 # 1. Ensure that the init object fetches its config without errors
379 # 2. Attempt to fetch the datasource (warn if it doesn't work)
380 # 3. Construct the modules object
381 # 4. Adjust any subsequent logging/output redirections using
382 # the modules objects configuration
383 # 5. Run the single module
384 # 6. Done!
385 mod_name = args.name
386 w_msg = welcome_format(name)
387 init = stages.Init(ds_deps=[], reporter=args.reporter)
388 # Stage 1
389 init.read_cfg(extract_fns(args))
390 # Stage 2
391 try:
392 init.fetch(existing="trust")
393 except sources.DataSourceNotFoundException:
394 # There was no datasource found,
395 # that might be bad (or ok) depending on
396 # the module being ran (so continue on)
397 util.logexc(LOG, ("Failed to fetch your datasource,"
398 " likely bad things to come!"))
399 print_exc(("Failed to fetch your datasource,"
400 " likely bad things to come!"))
401 if not args.force:
402 return 1
403 # Stage 3
404 mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
405 mod_args = args.module_args
406 if mod_args:
407 LOG.debug("Using passed in arguments %s", mod_args)
408 mod_freq = args.frequency
409 if mod_freq:
410 LOG.debug("Using passed in frequency %s", mod_freq)
411 mod_freq = FREQ_SHORT_NAMES.get(mod_freq)
412 # Stage 4
413 try:
414 LOG.debug("Closing stdin")
415 util.close_stdin()
416 util.fixup_output(mods.cfg, None)
417 except:
418 util.logexc(LOG, "Failed to setup output redirection!")
419 if args.debug:
420 # Reset so that all the debug handlers are closed out
421 LOG.debug(("Logging being reset, this logger may no"
422 " longer be active shortly"))
423 logging.resetLogging()
424 logging.setupLogging(mods.cfg)
425 apply_reporting_cfg(init.cfg)
426
427 # now that logging is setup and stdout redirected, send welcome
428 welcome(name, msg=w_msg)
429
430 # Stage 5
431 (which_ran, failures) = mods.run_single(mod_name,
432 mod_args,
433 mod_freq)
434 if failures:
435 LOG.warn("Ran %s but it failed!", mod_name)
436 return 1
437 elif not which_ran:
438 LOG.warn("Did not run %s, does it exist?", mod_name)
439 return 1
440 else:
441 # Guess it worked
442 return 0
443
444
445def atomic_write_file(path, content, mode='w'):
446 tf = None
447 try:
448 tf = tempfile.NamedTemporaryFile(dir=os.path.dirname(path),
449 delete=False, mode=mode)
450 tf.write(content)
451 tf.close()
452 os.rename(tf.name, path)
453 except Exception as e:
454 if tf is not None:
455 os.unlink(tf.name)
456 raise e
457
458
459def atomic_write_json(path, data):
460 return atomic_write_file(path, json.dumps(data, indent=1) + "\n")
461
462
463def status_wrapper(name, args, data_d=None, link_d=None):
464 if data_d is None:
465 data_d = os.path.normpath("/var/lib/cloud/data")
466 if link_d is None:
467 link_d = os.path.normpath("/run/cloud-init")
468
469 status_path = os.path.join(data_d, "status.json")
470 status_link = os.path.join(link_d, "status.json")
471 result_path = os.path.join(data_d, "result.json")
472 result_link = os.path.join(link_d, "result.json")
473
474 util.ensure_dirs((data_d, link_d,))
475
476 (_name, functor) = args.action
477
478 if name == "init":
479 if args.local:
480 mode = "init-local"
481 else:
482 mode = "init"
483 elif name == "modules":
484 mode = "modules-%s" % args.mode
485 else:
486 raise ValueError("unknown name: %s" % name)
487
488 modes = ('init', 'init-local', 'modules-config', 'modules-final')
489
490 status = None
491 if mode == 'init-local':
492 for f in (status_link, result_link, status_path, result_path):
493 util.del_file(f)
494 else:
495 try:
496 status = json.loads(util.load_file(status_path))
497 except:
498 pass
499
500 if status is None:
501 nullstatus = {
502 'errors': [],
503 'start': None,
504 'finished': None,
505 }
506 status = {'v1': {}}
507 for m in modes:
508 status['v1'][m] = nullstatus.copy()
509 status['v1']['datasource'] = None
510
511 v1 = status['v1']
512 v1['stage'] = mode
513 v1[mode]['start'] = time.time()
514
515 atomic_write_json(status_path, status)
516 util.sym_link(os.path.relpath(status_path, link_d), status_link,
517 force=True)
518
519 try:
520 ret = functor(name, args)
521 if mode in ('init', 'init-local'):
522 (datasource, errors) = ret
523 if datasource is not None:
524 v1['datasource'] = str(datasource)
525 else:
526 errors = ret
527
528 v1[mode]['errors'] = [str(e) for e in errors]
529
530 except Exception as e:
531 util.logexc(LOG, "failed of stage %s", mode)
532 print_exc("failed run of stage %s" % mode)
533 v1[mode]['errors'] = [str(e)]
534
535 v1[mode]['finished'] = time.time()
536 v1['stage'] = None
537
538 atomic_write_json(status_path, status)
539
540 if mode == "modules-final":
541 # write the 'finished' file
542 errors = []
543 for m in modes:
544 if v1[m]['errors']:
545 errors.extend(v1[m].get('errors', []))
546
547 atomic_write_json(result_path,
548 {'v1': {'datasource': v1['datasource'],
549 'errors': errors}})
550 util.sym_link(os.path.relpath(result_path, link_d), result_link,
551 force=True)
552
553 return len(v1[mode]['errors'])
554
555
556def main():
557 parser = argparse.ArgumentParser()
558
559 # Top level args
560 parser.add_argument('--version', '-v', action='version',
561 version='%(prog)s ' + (version.version_string()))
562 parser.add_argument('--file', '-f', action='append',
563 dest='files',
564 help=('additional yaml configuration'
565 ' files to use'),
566 type=argparse.FileType('rb'))
567 parser.add_argument('--debug', '-d', action='store_true',
568 help=('show additional pre-action'
569 ' logging (default: %(default)s)'),
570 default=False)
571 parser.add_argument('--force', action='store_true',
572 help=('force running even if no datasource is'
573 ' found (use at your own risk)'),
574 dest='force',
575 default=False)
576
577 parser.set_defaults(reporter=None)
578 subparsers = parser.add_subparsers()
579
580 # Each action and its sub-options (if any)
581 parser_init = subparsers.add_parser('init',
582 help=('initializes cloud-init and'
583 ' performs initial modules'))
584 parser_init.add_argument("--local", '-l', action='store_true',
585 help="start in local mode (default: %(default)s)",
586 default=False)
587 # This is used so that we can know which action is selected +
588 # the functor to use to run this subcommand
589 parser_init.set_defaults(action=('init', main_init))
590
591 # These settings are used for the 'config' and 'final' stages
592 parser_mod = subparsers.add_parser('modules',
593 help=('activates modules using '
594 'a given configuration key'))
595 parser_mod.add_argument("--mode", '-m', action='store',
596 help=("module configuration name "
597 "to use (default: %(default)s)"),
598 default='config',
599 choices=('init', 'config', 'final'))
600 parser_mod.set_defaults(action=('modules', main_modules))
601
602 # These settings are used when you want to query information
603 # stored in the cloud-init data objects/directories/files
604 parser_query = subparsers.add_parser('query',
605 help=('query information stored '
606 'in cloud-init'))
607 parser_query.add_argument("--name", '-n', action="store",
608 help="item name to query on",
609 required=True,
610 choices=QUERY_DATA_TYPES)
611 parser_query.set_defaults(action=('query', main_query))
612
613 # This subcommand allows you to run a single module
614 parser_single = subparsers.add_parser('single',
615 help=('run a single module '))
616 parser_single.set_defaults(action=('single', main_single))
617 parser_single.add_argument("--name", '-n', action="store",
618 help="module name to run",
619 required=True)
620 parser_single.add_argument("--frequency", action="store",
621 help=("frequency of the module"),
622 required=False,
623 choices=list(FREQ_SHORT_NAMES.keys()))
624 parser_single.add_argument("--report", action="store_true",
625 help="enable reporting",
626 required=False)
627 parser_single.add_argument("module_args", nargs="*",
628 metavar='argument',
629 help=('any additional arguments to'
630 ' pass to this module'))
631 parser_single.set_defaults(action=('single', main_single))
632
633 args = parser.parse_args()
634
635 # Setup basic logging to start (until reinitialized)
636 # iff in debug mode...
637 if args.debug:
638 logging.setupBasicLogging()
639
640 # Setup signal handlers before running
641 signal_handler.attach_handlers()
642
643 if not hasattr(args, 'action'):
644 parser.error('too few arguments')
645 (name, functor) = args.action
646 if name in ("modules", "init"):
647 functor = status_wrapper
648
649 report_on = True
650 if name == "init":
651 if args.local:
652 rname, rdesc = ("init-local", "searching for local datasources")
653 else:
654 rname, rdesc = ("init-network",
655 "searching for network datasources")
656 elif name == "modules":
657 rname, rdesc = ("modules-%s" % args.mode,
658 "running modules for %s" % args.mode)
659 elif name == "single":
660 rname, rdesc = ("single/%s" % args.name,
661 "running single module %s" % args.name)
662 report_on = args.report
663
664 args.reporter = events.ReportEventStack(
665 rname, rdesc, reporting_enabled=report_on)
666 with args.reporter:
667 return util.log_time(
668 logfunc=LOG.debug, msg="cloud-init mode '%s'" % name,
669 get_uptime=True, func=functor, args=(name, args))
670
671
672if __name__ == '__main__':
673 sys.exit(main())
6740
=== removed file 'cloudinit/__init__.py'
--- cloudinit/__init__.py 2012-06-29 18:29:37 +0000
+++ cloudinit/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,21 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2012 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5# Copyright (C) 2012 Yahoo! Inc.
6#
7# Author: Scott Moser <scott.moser@canonical.com>
8# Author: Juerg Haefliger <juerg.haefliger@hp.com>
9# Author: Joshua Harlow <harlowja@yahoo-inc.com>
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 3, as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
220
=== removed file 'cloudinit/cloud.py'
--- cloudinit/cloud.py 2015-08-31 17:33:30 +0000
+++ cloudinit/cloud.py 1970-01-01 00:00:00 +0000
@@ -1,109 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2012 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5# Copyright (C) 2012 Yahoo! Inc.
6#
7# Author: Scott Moser <scott.moser@canonical.com>
8# Author: Juerg Haefliger <juerg.haefliger@hp.com>
9# Author: Joshua Harlow <harlowja@yahoo-inc.com>
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 3, as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23import copy
24import os
25
26from cloudinit import log as logging
27from cloudinit.reporting import events
28
29LOG = logging.getLogger(__name__)
30
31# This class is the high level wrapper that provides
32# access to cloud-init objects without exposing the stage objects
33# to handler and or module manipulation. It allows for cloud
34# init to restrict what those types of user facing code may see
35# and or adjust (which helps avoid code messing with each other)
36#
37# It also provides util functions that avoid having to know
38# how to get a certain member from this submembers as well
39# as providing a backwards compatible object that can be maintained
40# while the stages/other objects can be worked on independently...
41
42
43class Cloud(object):
44 def __init__(self, datasource, paths, cfg, distro, runners, reporter=None):
45 self.datasource = datasource
46 self.paths = paths
47 self.distro = distro
48 self._cfg = cfg
49 self._runners = runners
50 if reporter is None:
51 reporter = events.ReportEventStack(
52 name="unnamed-cloud-reporter",
53 description="unnamed-cloud-reporter",
54 reporting_enabled=False)
55 self.reporter = reporter
56
57 # If a 'user' manipulates logging or logging services
58 # it is typically useful to cause the logging to be
59 # setup again.
60 def cycle_logging(self):
61 logging.resetLogging()
62 logging.setupLogging(self.cfg)
63
64 @property
65 def cfg(self):
66 # Ensure that not indirectly modified
67 return copy.deepcopy(self._cfg)
68
69 def run(self, name, functor, args, freq=None, clear_on_fail=False):
70 return self._runners.run(name, functor, args, freq, clear_on_fail)
71
72 def get_template_filename(self, name):
73 fn = self.paths.template_tpl % (name)
74 if not os.path.isfile(fn):
75 LOG.warn("No template found at %s for template named %s", fn, name)
76 return None
77 return fn
78
79 # The rest of thes are just useful proxies
80 def get_userdata(self, apply_filter=True):
81 return self.datasource.get_userdata(apply_filter)
82
83 def get_instance_id(self):
84 return self.datasource.get_instance_id()
85
86 @property
87 def launch_index(self):
88 return self.datasource.launch_index
89
90 def get_public_ssh_keys(self):
91 return self.datasource.get_public_ssh_keys()
92
93 def get_locale(self):
94 return self.datasource.get_locale()
95
96 def get_hostname(self, fqdn=False):
97 return self.datasource.get_hostname(fqdn=fqdn)
98
99 def device_name_to_device(self, name):
100 return self.datasource.device_name_to_device(name)
101
102 def get_ipath_cur(self, name=None):
103 return self.paths.get_ipath_cur(name)
104
105 def get_cpath(self, name=None):
106 return self.paths.get_cpath(name)
107
108 def get_ipath(self, name=None):
109 return self.paths.get_ipath(name)
1100
=== removed file 'cloudinit/config/__init__.py'
--- cloudinit/config/__init__.py 2013-01-15 21:08:43 +0000
+++ cloudinit/config/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2008-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Chuck Short <chuck.short@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21
22from cloudinit.settings import (PER_INSTANCE, FREQUENCIES)
23
24from cloudinit import log as logging
25
26LOG = logging.getLogger(__name__)
27
28# This prefix is used to make it less
29# of a chance that when importing
30# we will not find something else with the same
31# name in the lookup path...
32MOD_PREFIX = "cc_"
33
34
35def form_module_name(name):
36 canon_name = name.replace("-", "_")
37 if canon_name.lower().endswith(".py"):
38 canon_name = canon_name[0:(len(canon_name) - 3)]
39 canon_name = canon_name.strip()
40 if not canon_name:
41 return None
42 if not canon_name.startswith(MOD_PREFIX):
43 canon_name = '%s%s' % (MOD_PREFIX, canon_name)
44 return canon_name
45
46
47def fixup_module(mod, def_freq=PER_INSTANCE):
48 if not hasattr(mod, 'frequency'):
49 setattr(mod, 'frequency', def_freq)
50 else:
51 freq = mod.frequency
52 if freq and freq not in FREQUENCIES:
53 LOG.warn("Module %s has an unknown frequency %s", mod, freq)
54 if not hasattr(mod, 'distros'):
55 setattr(mod, 'distros', [])
56 if not hasattr(mod, 'osfamilies'):
57 setattr(mod, 'osfamilies', [])
58 return mod
590
=== removed file 'cloudinit/config/cc_apt_configure.py'
--- cloudinit/config/cc_apt_configure.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_apt_configure.py 1970-01-01 00:00:00 +0000
@@ -1,292 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import glob
22import os
23import re
24
25from cloudinit import templater
26from cloudinit import util
27
28distros = ['ubuntu', 'debian']
29
30PROXY_TPL = "Acquire::HTTP::Proxy \"%s\";\n"
31APT_CONFIG_FN = "/etc/apt/apt.conf.d/94cloud-init-config"
32APT_PROXY_FN = "/etc/apt/apt.conf.d/95cloud-init-proxy"
33
34# this will match 'XXX:YYY' (ie, 'cloud-archive:foo' or 'ppa:bar')
35ADD_APT_REPO_MATCH = r"^[\w-]+:\w"
36
37# A temporary shell program to get a given gpg key
38# from a given keyserver
39EXPORT_GPG_KEYID = """
40 k=${1} ks=${2};
41 exec 2>/dev/null
42 [ -n "$k" ] || exit 1;
43 armour=$(gpg --list-keys --armour "${k}")
44 if [ -z "${armour}" ]; then
45 gpg --keyserver ${ks} --recv $k >/dev/null &&
46 armour=$(gpg --export --armour "${k}") &&
47 gpg --batch --yes --delete-keys "${k}"
48 fi
49 [ -n "${armour}" ] && echo "${armour}"
50"""
51
52
53def handle(name, cfg, cloud, log, _args):
54 if util.is_false(cfg.get('apt_configure_enabled', True)):
55 log.debug("Skipping module named %s, disabled by config.", name)
56 return
57
58 release = get_release()
59 mirrors = find_apt_mirror_info(cloud, cfg)
60 if not mirrors or "primary" not in mirrors:
61 log.debug(("Skipping module named %s,"
62 " no package 'mirror' located"), name)
63 return
64
65 # backwards compatibility
66 mirror = mirrors["primary"]
67 mirrors["mirror"] = mirror
68
69 log.debug("Mirror info: %s" % mirrors)
70
71 if not util.get_cfg_option_bool(cfg,
72 'apt_preserve_sources_list', False):
73 generate_sources_list(release, mirrors, cloud, log)
74 old_mirrors = cfg.get('apt_old_mirrors',
75 {"primary": "archive.ubuntu.com/ubuntu",
76 "security": "security.ubuntu.com/ubuntu"})
77 rename_apt_lists(old_mirrors, mirrors)
78
79 try:
80 apply_apt_config(cfg, APT_PROXY_FN, APT_CONFIG_FN)
81 except Exception as e:
82 log.warn("failed to proxy or apt config info: %s", e)
83
84 # Process 'apt_sources'
85 if 'apt_sources' in cfg:
86 params = mirrors
87 params['RELEASE'] = release
88 params['MIRROR'] = mirror
89
90 matchcfg = cfg.get('add_apt_repo_match', ADD_APT_REPO_MATCH)
91 if matchcfg:
92 matcher = re.compile(matchcfg).search
93 else:
94 def matcher(x):
95 return False
96
97 errors = add_sources(cfg['apt_sources'], params,
98 aa_repo_match=matcher)
99 for e in errors:
100 log.warn("Add source error: %s", ':'.join(e))
101
102 dconf_sel = util.get_cfg_option_str(cfg, 'debconf_selections', False)
103 if dconf_sel:
104 log.debug("Setting debconf selections per cloud config")
105 try:
106 util.subp(('debconf-set-selections', '-'), dconf_sel)
107 except Exception:
108 util.logexc(log, "Failed to run debconf-set-selections")
109
110
111# get gpg keyid from keyserver
112def getkeybyid(keyid, keyserver):
113 with util.ExtendedTemporaryFile(suffix='.sh', mode="w+", ) as fh:
114 fh.write(EXPORT_GPG_KEYID)
115 fh.flush()
116 cmd = ['/bin/sh', fh.name, keyid, keyserver]
117 (stdout, _stderr) = util.subp(cmd)
118 return stdout.strip()
119
120
121def mirror2lists_fileprefix(mirror):
122 string = mirror
123 # take off http:// or ftp://
124 if string.endswith("/"):
125 string = string[0:-1]
126 pos = string.find("://")
127 if pos >= 0:
128 string = string[pos + 3:]
129 string = string.replace("/", "_")
130 return string
131
132
133def rename_apt_lists(old_mirrors, new_mirrors, lists_d="/var/lib/apt/lists"):
134 for (name, omirror) in old_mirrors.items():
135 nmirror = new_mirrors.get(name)
136 if not nmirror:
137 continue
138 oprefix = os.path.join(lists_d, mirror2lists_fileprefix(omirror))
139 nprefix = os.path.join(lists_d, mirror2lists_fileprefix(nmirror))
140 if oprefix == nprefix:
141 continue
142 olen = len(oprefix)
143 for filename in glob.glob("%s_*" % oprefix):
144 util.rename(filename, "%s%s" % (nprefix, filename[olen:]))
145
146
147def get_release():
148 (stdout, _stderr) = util.subp(['lsb_release', '-cs'])
149 return stdout.strip()
150
151
152def generate_sources_list(codename, mirrors, cloud, log):
153 template_fn = cloud.get_template_filename('sources.list.%s' %
154 (cloud.distro.name))
155 if not template_fn:
156 template_fn = cloud.get_template_filename('sources.list')
157 if not template_fn:
158 log.warn("No template found, not rendering /etc/apt/sources.list")
159 return
160
161 params = {'codename': codename}
162 for k in mirrors:
163 params[k] = mirrors[k]
164 templater.render_to_file(template_fn, '/etc/apt/sources.list', params)
165
166
167def add_sources(srclist, template_params=None, aa_repo_match=None):
168 """
169 add entries in /etc/apt/sources.list.d for each abbreviated
170 sources.list entry in 'srclist'. When rendering template, also
171 include the values in dictionary searchList
172 """
173 if template_params is None:
174 template_params = {}
175
176 if aa_repo_match is None:
177 def aa_repo_match(x):
178 return False
179
180 errorlist = []
181 for ent in srclist:
182 if 'source' not in ent:
183 errorlist.append(["", "missing source"])
184 continue
185
186 source = ent['source']
187 source = templater.render_string(source, template_params)
188
189 if aa_repo_match(source):
190 try:
191 util.subp(["add-apt-repository", source])
192 except util.ProcessExecutionError as e:
193 errorlist.append([source,
194 ("add-apt-repository failed. " + str(e))])
195 continue
196
197 if 'filename' not in ent:
198 ent['filename'] = 'cloud_config_sources.list'
199
200 if not ent['filename'].startswith("/"):
201 ent['filename'] = os.path.join("/etc/apt/sources.list.d/",
202 ent['filename'])
203
204 if ('keyid' in ent and 'key' not in ent):
205 ks = "keyserver.ubuntu.com"
206 if 'keyserver' in ent:
207 ks = ent['keyserver']
208 try:
209 ent['key'] = getkeybyid(ent['keyid'], ks)
210 except Exception:
211 errorlist.append([source, "failed to get key from %s" % ks])
212 continue
213
214 if 'key' in ent:
215 try:
216 util.subp(('apt-key', 'add', '-'), ent['key'])
217 except Exception:
218 errorlist.append([source, "failed add key"])
219
220 try:
221 contents = "%s\n" % (source)
222 util.write_file(ent['filename'], contents, omode="ab")
223 except Exception:
224 errorlist.append([source,
225 "failed write to file %s" % ent['filename']])
226
227 return errorlist
228
229
230def find_apt_mirror_info(cloud, cfg):
231 """find an apt_mirror given the cloud and cfg provided."""
232
233 mirror = None
234
235 # this is less preferred way of specifying mirror preferred would be to
236 # use the distro's search or package_mirror.
237 mirror = cfg.get("apt_mirror", None)
238
239 search = cfg.get("apt_mirror_search", None)
240 if not mirror and search:
241 mirror = util.search_for_mirror(search)
242
243 if (not mirror and
244 util.get_cfg_option_bool(cfg, "apt_mirror_search_dns", False)):
245 mydom = ""
246 doms = []
247
248 # if we have a fqdn, then search its domain portion first
249 (_hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
250 mydom = ".".join(fqdn.split(".")[1:])
251 if mydom:
252 doms.append(".%s" % mydom)
253
254 doms.extend((".localdomain", "",))
255
256 mirror_list = []
257 distro = cloud.distro.name
258 mirrorfmt = "http://%s-mirror%s/%s" % (distro, "%s", distro)
259 for post in doms:
260 mirror_list.append(mirrorfmt % (post))
261
262 mirror = util.search_for_mirror(mirror_list)
263
264 mirror_info = cloud.datasource.get_package_mirror_info()
265
266 # this is a bit strange.
267 # if mirror is set, then one of the legacy options above set it
268 # but they do not cover security. so we need to get that from
269 # get_package_mirror_info
270 if mirror:
271 mirror_info.update({'primary': mirror})
272
273 return mirror_info
274
275
276def apply_apt_config(cfg, proxy_fname, config_fname):
277 # Set up any apt proxy
278 cfgs = (('apt_proxy', 'Acquire::HTTP::Proxy "%s";'),
279 ('apt_http_proxy', 'Acquire::HTTP::Proxy "%s";'),
280 ('apt_ftp_proxy', 'Acquire::FTP::Proxy "%s";'),
281 ('apt_https_proxy', 'Acquire::HTTPS::Proxy "%s";'))
282
283 proxies = [fmt % cfg.get(name) for (name, fmt) in cfgs if cfg.get(name)]
284 if len(proxies):
285 util.write_file(proxy_fname, '\n'.join(proxies) + '\n')
286 elif os.path.isfile(proxy_fname):
287 util.del_file(proxy_fname)
288
289 if cfg.get('apt_config', None):
290 util.write_file(config_fname, cfg.get('apt_config'))
291 elif os.path.isfile(config_fname):
292 util.del_file(config_fname)
2930
=== removed file 'cloudinit/config/cc_apt_pipelining.py'
--- cloudinit/config/cc_apt_pipelining.py 2015-05-01 09:38:56 +0000
+++ cloudinit/config/cc_apt_pipelining.py 1970-01-01 00:00:00 +0000
@@ -1,57 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4#
5# Author: Ben Howard <ben.howard@canonical.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3, as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19from cloudinit.settings import PER_INSTANCE
20from cloudinit import util
21
22frequency = PER_INSTANCE
23
24distros = ['ubuntu', 'debian']
25
26DEFAULT_FILE = "/etc/apt/apt.conf.d/90cloud-init-pipelining"
27
28APT_PIPE_TPL = ("//Written by cloud-init per 'apt_pipelining'\n"
29 'Acquire::http::Pipeline-Depth "%s";\n')
30
31# Acquire::http::Pipeline-Depth can be a value
32# from 0 to 5 indicating how many outstanding requests APT should send.
33# A value of zero MUST be specified if the remote host does not properly linger
34# on TCP connections - otherwise data corruption will occur.
35
36
37def handle(_name, cfg, _cloud, log, _args):
38
39 apt_pipe_value = util.get_cfg_option_str(cfg, "apt_pipelining", False)
40 apt_pipe_value_s = str(apt_pipe_value).lower().strip()
41
42 if apt_pipe_value_s == "false":
43 write_apt_snippet("0", log, DEFAULT_FILE)
44 elif apt_pipe_value_s in ("none", "unchanged", "os"):
45 return
46 elif apt_pipe_value_s in [str(b) for b in range(0, 6)]:
47 write_apt_snippet(apt_pipe_value_s, log, DEFAULT_FILE)
48 else:
49 log.warn("Invalid option for apt_pipeling: %s", apt_pipe_value)
50
51
52def write_apt_snippet(setting, log, f_name):
53 """Writes f_name with apt pipeline depth 'setting'."""
54
55 file_contents = APT_PIPE_TPL % (setting)
56 util.write_file(f_name, file_contents)
57 log.debug("Wrote %s with apt pipeline depth setting %s", f_name, setting)
580
=== removed file 'cloudinit/config/cc_bootcmd.py'
--- cloudinit/config/cc_bootcmd.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_bootcmd.py 1970-01-01 00:00:00 +0000
@@ -1,54 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2011 Canonical Ltd.
4# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from cloudinit.settings import PER_ALWAYS
24from cloudinit import util
25
26frequency = PER_ALWAYS
27
28
29def handle(name, cfg, cloud, log, _args):
30
31 if "bootcmd" not in cfg:
32 log.debug(("Skipping module named %s,"
33 " no 'bootcmd' key in configuration"), name)
34 return
35
36 with util.ExtendedTemporaryFile(suffix=".sh") as tmpf:
37 try:
38 content = util.shellify(cfg["bootcmd"])
39 tmpf.write(util.encode_text(content))
40 tmpf.flush()
41 except Exception:
42 util.logexc(log, "Failed to shellify bootcmd")
43 raise
44
45 try:
46 env = os.environ.copy()
47 iid = cloud.get_instance_id()
48 if iid:
49 env['INSTANCE_ID'] = str(iid)
50 cmd = ['/bin/sh', tmpf.name]
51 util.subp(cmd, env=env, capture=False)
52 except Exception:
53 util.logexc(log, "Failed to run bootcmd module %s", name)
54 raise
550
=== removed file 'cloudinit/config/cc_byobu.py'
--- cloudinit/config/cc_byobu.py 2014-08-26 18:50:11 +0000
+++ cloudinit/config/cc_byobu.py 1970-01-01 00:00:00 +0000
@@ -1,80 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21# Ensure this is aliased to a name not 'distros'
22# since the module attribute 'distros'
23# is a list of distros that are supported, not a sub-module
24from cloudinit import distros as ds
25
26from cloudinit import util
27
28distros = ['ubuntu', 'debian']
29
30
31def handle(name, cfg, cloud, log, args):
32 if len(args) != 0:
33 value = args[0]
34 else:
35 value = util.get_cfg_option_str(cfg, "byobu_by_default", "")
36
37 if not value:
38 log.debug("Skipping module named %s, no 'byobu' values found", name)
39 return
40
41 if value == "user" or value == "system":
42 value = "enable-%s" % value
43
44 valid = ("enable-user", "enable-system", "enable",
45 "disable-user", "disable-system", "disable")
46 if value not in valid:
47 log.warn("Unknown value %s for byobu_by_default", value)
48
49 mod_user = value.endswith("-user")
50 mod_sys = value.endswith("-system")
51 if value.startswith("enable"):
52 bl_inst = "install"
53 dc_val = "byobu byobu/launch-by-default boolean true"
54 mod_sys = True
55 else:
56 if value == "disable":
57 mod_user = True
58 mod_sys = True
59 bl_inst = "uninstall"
60 dc_val = "byobu byobu/launch-by-default boolean false"
61
62 shcmd = ""
63 if mod_user:
64 (users, _groups) = ds.normalize_users_groups(cfg, cloud.distro)
65 (user, _user_config) = ds.extract_default(users)
66 if not user:
67 log.warn(("No default byobu user provided, "
68 "can not launch %s for the default user"), bl_inst)
69 else:
70 shcmd += " sudo -Hu \"%s\" byobu-launcher-%s" % (user, bl_inst)
71 shcmd += " || X=$(($X+1)); "
72 if mod_sys:
73 shcmd += "echo \"%s\" | debconf-set-selections" % dc_val
74 shcmd += " && dpkg-reconfigure byobu --frontend=noninteractive"
75 shcmd += " || X=$(($X+1)); "
76
77 if len(shcmd):
78 cmd = ["/bin/sh", "-c", "%s %s %s" % ("X=0;", shcmd, "exit $X")]
79 log.debug("Setting byobu to %s", value)
80 util.subp(cmd, capture=False)
810
=== removed file 'cloudinit/config/cc_ca_certs.py'
--- cloudinit/config/cc_ca_certs.py 2015-01-23 02:21:04 +0000
+++ cloudinit/config/cc_ca_certs.py 1970-01-01 00:00:00 +0000
@@ -1,104 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Author: Mike Milner <mike.milner@canonical.com>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3, as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os
18
19from cloudinit import util
20
21CA_CERT_PATH = "/usr/share/ca-certificates/"
22CA_CERT_FILENAME = "cloud-init-ca-certs.crt"
23CA_CERT_CONFIG = "/etc/ca-certificates.conf"
24CA_CERT_SYSTEM_PATH = "/etc/ssl/certs/"
25CA_CERT_FULL_PATH = os.path.join(CA_CERT_PATH, CA_CERT_FILENAME)
26
27distros = ['ubuntu', 'debian']
28
29
30def update_ca_certs():
31 """
32 Updates the CA certificate cache on the current machine.
33 """
34 util.subp(["update-ca-certificates"], capture=False)
35
36
37def add_ca_certs(certs):
38 """
39 Adds certificates to the system. To actually apply the new certificates
40 you must also call L{update_ca_certs}.
41
42 @param certs: A list of certificate strings.
43 """
44 if certs:
45 # First ensure they are strings...
46 cert_file_contents = "\n".join([str(c) for c in certs])
47 util.write_file(CA_CERT_FULL_PATH, cert_file_contents, mode=0o644)
48
49 # Append cert filename to CA_CERT_CONFIG file.
50 # We have to strip the content because blank lines in the file
51 # causes subsequent entries to be ignored. (LP: #1077020)
52 orig = util.load_file(CA_CERT_CONFIG)
53 cur_cont = '\n'.join([l for l in orig.splitlines()
54 if l != CA_CERT_FILENAME])
55 out = "%s\n%s\n" % (cur_cont.rstrip(), CA_CERT_FILENAME)
56 util.write_file(CA_CERT_CONFIG, out, omode="wb")
57
58
59def remove_default_ca_certs():
60 """
61 Removes all default trusted CA certificates from the system. To actually
62 apply the change you must also call L{update_ca_certs}.
63 """
64 util.delete_dir_contents(CA_CERT_PATH)
65 util.delete_dir_contents(CA_CERT_SYSTEM_PATH)
66 util.write_file(CA_CERT_CONFIG, "", mode=0o644)
67 debconf_sel = "ca-certificates ca-certificates/trust_new_crts select no"
68 util.subp(('debconf-set-selections', '-'), debconf_sel)
69
70
71def handle(name, cfg, _cloud, log, _args):
72 """
73 Call to handle ca-cert sections in cloud-config file.
74
75 @param name: The module name "ca-cert" from cloud.cfg
76 @param cfg: A nested dict containing the entire cloud config contents.
77 @param cloud: The L{CloudInit} object in use.
78 @param log: Pre-initialized Python logger object to use for logging.
79 @param args: Any module arguments from cloud.cfg
80 """
81 # If there isn't a ca-certs section in the configuration don't do anything
82 if "ca-certs" not in cfg:
83 log.debug(("Skipping module named %s,"
84 " no 'ca-certs' key in configuration"), name)
85 return
86
87 ca_cert_cfg = cfg['ca-certs']
88
89 # If there is a remove-defaults option set to true, remove the system
90 # default trusted CA certs first.
91 if ca_cert_cfg.get("remove-defaults", False):
92 log.debug("Removing default certificates")
93 remove_default_ca_certs()
94
95 # If we are given any new trusted CA certs to add, add them.
96 if "trusted" in ca_cert_cfg:
97 trusted_certs = util.get_cfg_option_list(ca_cert_cfg, "trusted")
98 if trusted_certs:
99 log.debug("Adding %d certificates" % len(trusted_certs))
100 add_ca_certs(trusted_certs)
101
102 # Update the system with the new cert configuration.
103 log.debug("Updating certificates")
104 update_ca_certs()
1050
=== removed file 'cloudinit/config/cc_chef.py'
--- cloudinit/config/cc_chef.py 2016-04-13 16:24:46 +0000
+++ cloudinit/config/cc_chef.py 1970-01-01 00:00:00 +0000
@@ -1,342 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
4#
5# Author: Avishai Ish-Shalom <avishai@fewbytes.com>
6# Author: Mike Moulton <mike@meltmedia.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21"""
22**Summary:** module that configures, starts and installs chef.
23
24**Description:** This module enables chef to be installed (from packages or
25from gems, or from omnibus). Before this occurs chef configurations are
26written to disk (validation.pem, client.pem, firstboot.json, client.rb),
27and needed chef folders/directories are created (/etc/chef and /var/log/chef
28and so-on). Then once installing proceeds correctly if configured chef will
29be started (in daemon mode or in non-daemon mode) and then once that has
30finished (if ran in non-daemon mode this will be when chef finishes
31converging, if ran in daemon mode then no further actions are possible since
32chef will have forked into its own process) then a post run function can
33run that can do finishing activities (such as removing the validation pem
34file).
35
36It can be configured with the following option structure::
37
38 chef:
39 directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef,
40 /var/cache/chef, /var/backups/chef, /var/run/chef)
41 validation_cert: (optional string to be written to file validation_key)
42 special value 'system' means set use existing file
43 validation_key: (optional the path for validation_cert. default
44 /etc/chef/validation.pem)
45 firstboot_path: (path to write run_list and initial_attributes keys that
46 should also be present in this configuration, defaults
47 to /etc/chef/firstboot.json)
48 exec: boolean to run or not run chef (defaults to false, unless
49 a gem installed is requested
50 where this will then default
51 to true)
52
53 chef.rb template keys (if falsey, then will be skipped and not
54 written to /etc/chef/client.rb)
55
56 chef:
57 client_key:
58 environment:
59 file_backup_path:
60 file_cache_path:
61 json_attribs:
62 log_level:
63 log_location:
64 node_name:
65 pid_file:
66 server_url:
67 show_time:
68 ssl_verify_mode:
69 validation_cert:
70 validation_key:
71 validation_name:
72"""
73
74import itertools
75import json
76import os
77
78from cloudinit import templater
79from cloudinit import url_helper
80from cloudinit import util
81
82import six
83
84RUBY_VERSION_DEFAULT = "1.8"
85
86CHEF_DIRS = tuple([
87 '/etc/chef',
88 '/var/log/chef',
89 '/var/lib/chef',
90 '/var/cache/chef',
91 '/var/backups/chef',
92 '/var/run/chef',
93])
94REQUIRED_CHEF_DIRS = tuple([
95 '/etc/chef',
96])
97
98# Used if fetching chef from a omnibus style package
99OMNIBUS_URL = "https://www.getchef.com/chef/install.sh"
100OMNIBUS_URL_RETRIES = 5
101
102CHEF_VALIDATION_PEM_PATH = '/etc/chef/validation.pem'
103CHEF_FB_PATH = '/etc/chef/firstboot.json'
104CHEF_RB_TPL_DEFAULTS = {
105 # These are ruby symbols...
106 'ssl_verify_mode': ':verify_none',
107 'log_level': ':info',
108 # These are not symbols...
109 'log_location': '/var/log/chef/client.log',
110 'validation_key': CHEF_VALIDATION_PEM_PATH,
111 'validation_cert': None,
112 'client_key': "/etc/chef/client.pem",
113 'json_attribs': CHEF_FB_PATH,
114 'file_cache_path': "/var/cache/chef",
115 'file_backup_path': "/var/backups/chef",
116 'pid_file': "/var/run/chef/client.pid",
117 'show_time': True,
118}
119CHEF_RB_TPL_BOOL_KEYS = frozenset(['show_time'])
120CHEF_RB_TPL_PATH_KEYS = frozenset([
121 'log_location',
122 'validation_key',
123 'client_key',
124 'file_cache_path',
125 'json_attribs',
126 'file_cache_path',
127 'pid_file',
128])
129CHEF_RB_TPL_KEYS = list(CHEF_RB_TPL_DEFAULTS.keys())
130CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_BOOL_KEYS)
131CHEF_RB_TPL_KEYS.extend(CHEF_RB_TPL_PATH_KEYS)
132CHEF_RB_TPL_KEYS.extend([
133 'server_url',
134 'node_name',
135 'environment',
136 'validation_name',
137])
138CHEF_RB_TPL_KEYS = frozenset(CHEF_RB_TPL_KEYS)
139CHEF_RB_PATH = '/etc/chef/client.rb'
140CHEF_EXEC_PATH = '/usr/bin/chef-client'
141CHEF_EXEC_DEF_ARGS = tuple(['-d', '-i', '1800', '-s', '20'])
142
143
144def is_installed():
145 if not os.path.isfile(CHEF_EXEC_PATH):
146 return False
147 if not os.access(CHEF_EXEC_PATH, os.X_OK):
148 return False
149 return True
150
151
152def post_run_chef(chef_cfg, log):
153 delete_pem = util.get_cfg_option_bool(chef_cfg,
154 'delete_validation_post_exec',
155 default=False)
156 if delete_pem and os.path.isfile(CHEF_VALIDATION_PEM_PATH):
157 os.unlink(CHEF_VALIDATION_PEM_PATH)
158
159
160def get_template_params(iid, chef_cfg, log):
161 params = CHEF_RB_TPL_DEFAULTS.copy()
162 # Allow users to overwrite any of the keys they want (if they so choose),
163 # when a value is None, then the value will be set to None and no boolean
164 # or string version will be populated...
165 for (k, v) in chef_cfg.items():
166 if k not in CHEF_RB_TPL_KEYS:
167 log.debug("Skipping unknown chef template key '%s'", k)
168 continue
169 if v is None:
170 params[k] = None
171 else:
172 # This will make the value a boolean or string...
173 if k in CHEF_RB_TPL_BOOL_KEYS:
174 params[k] = util.get_cfg_option_bool(chef_cfg, k)
175 else:
176 params[k] = util.get_cfg_option_str(chef_cfg, k)
177 # These ones are overwritten to be exact values...
178 params.update({
179 'generated_by': util.make_header(),
180 'node_name': util.get_cfg_option_str(chef_cfg, 'node_name',
181 default=iid),
182 'environment': util.get_cfg_option_str(chef_cfg, 'environment',
183 default='_default'),
184 # These two are mandatory...
185 'server_url': chef_cfg['server_url'],
186 'validation_name': chef_cfg['validation_name'],
187 })
188 return params
189
190
191def handle(name, cfg, cloud, log, _args):
192 """Handler method activated by cloud-init."""
193
194 # If there isn't a chef key in the configuration don't do anything
195 if 'chef' not in cfg:
196 log.debug(("Skipping module named %s,"
197 " no 'chef' key in configuration"), name)
198 return
199 chef_cfg = cfg['chef']
200
201 # Ensure the chef directories we use exist
202 chef_dirs = util.get_cfg_option_list(chef_cfg, 'directories')
203 if not chef_dirs:
204 chef_dirs = list(CHEF_DIRS)
205 for d in itertools.chain(chef_dirs, REQUIRED_CHEF_DIRS):
206 util.ensure_dir(d)
207
208 vkey_path = chef_cfg.get('validation_key', CHEF_VALIDATION_PEM_PATH)
209 vcert = chef_cfg.get('validation_cert')
210 # special value 'system' means do not overwrite the file
211 # but still render the template to contain 'validation_key'
212 if vcert:
213 if vcert != "system":
214 util.write_file(vkey_path, vcert)
215 elif not os.path.isfile(vkey_path):
216 log.warn("chef validation_cert provided as 'system', but "
217 "validation_key path '%s' does not exist.",
218 vkey_path)
219
220 # Create the chef config from template
221 template_fn = cloud.get_template_filename('chef_client.rb')
222 if template_fn:
223 iid = str(cloud.datasource.get_instance_id())
224 params = get_template_params(iid, chef_cfg, log)
225 # Do a best effort attempt to ensure that the template values that
226 # are associated with paths have there parent directory created
227 # before they are used by the chef-client itself.
228 param_paths = set()
229 for (k, v) in params.items():
230 if k in CHEF_RB_TPL_PATH_KEYS and v:
231 param_paths.add(os.path.dirname(v))
232 util.ensure_dirs(param_paths)
233 templater.render_to_file(template_fn, CHEF_RB_PATH, params)
234 else:
235 log.warn("No template found, not rendering to %s",
236 CHEF_RB_PATH)
237
238 # Set the firstboot json
239 fb_filename = util.get_cfg_option_str(chef_cfg, 'firstboot_path',
240 default=CHEF_FB_PATH)
241 if not fb_filename:
242 log.info("First boot path empty, not writing first boot json file")
243 else:
244 initial_json = {}
245 if 'run_list' in chef_cfg:
246 initial_json['run_list'] = chef_cfg['run_list']
247 if 'initial_attributes' in chef_cfg:
248 initial_attributes = chef_cfg['initial_attributes']
249 for k in list(initial_attributes.keys()):
250 initial_json[k] = initial_attributes[k]
251 util.write_file(fb_filename, json.dumps(initial_json))
252
253 # Try to install chef, if its not already installed...
254 force_install = util.get_cfg_option_bool(chef_cfg,
255 'force_install', default=False)
256 if not is_installed() or force_install:
257 run = install_chef(cloud, chef_cfg, log)
258 elif is_installed():
259 run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
260 else:
261 run = False
262 if run:
263 run_chef(chef_cfg, log)
264 post_run_chef(chef_cfg, log)
265
266
267def run_chef(chef_cfg, log):
268 log.debug('Running chef-client')
269 cmd = [CHEF_EXEC_PATH]
270 if 'exec_arguments' in chef_cfg:
271 cmd_args = chef_cfg['exec_arguments']
272 if isinstance(cmd_args, (list, tuple)):
273 cmd.extend(cmd_args)
274 elif isinstance(cmd_args, six.string_types):
275 cmd.append(cmd_args)
276 else:
277 log.warn("Unknown type %s provided for chef"
278 " 'exec_arguments' expected list, tuple,"
279 " or string", type(cmd_args))
280 cmd.extend(CHEF_EXEC_DEF_ARGS)
281 else:
282 cmd.extend(CHEF_EXEC_DEF_ARGS)
283 util.subp(cmd, capture=False)
284
285
286def install_chef(cloud, chef_cfg, log):
287 # If chef is not installed, we install chef based on 'install_type'
288 install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
289 'packages')
290 run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
291 if install_type == "gems":
292 # This will install and run the chef-client from gems
293 chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
294 ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
295 RUBY_VERSION_DEFAULT)
296 install_chef_from_gems(ruby_version, chef_version, cloud.distro)
297 # Retain backwards compat, by preferring True instead of False
298 # when not provided/overriden...
299 run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True)
300 elif install_type == 'packages':
301 # This will install and run the chef-client from packages
302 cloud.distro.install_packages(('chef',))
303 elif install_type == 'omnibus':
304 # This will install as a omnibus unified package
305 url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL)
306 retries = max(0, util.get_cfg_option_int(chef_cfg,
307 "omnibus_url_retries",
308 default=OMNIBUS_URL_RETRIES))
309 content = url_helper.readurl(url=url, retries=retries)
310 with util.tempdir() as tmpd:
311 # Use tmpdir over tmpfile to avoid 'text file busy' on execute
312 tmpf = "%s/chef-omnibus-install" % tmpd
313 util.write_file(tmpf, content, mode=0o700)
314 util.subp([tmpf], capture=False)
315 else:
316 log.warn("Unknown chef install type '%s'", install_type)
317 run = False
318 return run
319
320
321def get_ruby_packages(version):
322 # return a list of packages needed to install ruby at version
323 pkgs = ['ruby%s' % version, 'ruby%s-dev' % version]
324 if version == "1.8":
325 pkgs.extend(('libopenssl-ruby1.8', 'rubygems1.8'))
326 return pkgs
327
328
329def install_chef_from_gems(ruby_version, chef_version, distro):
330 distro.install_packages(get_ruby_packages(ruby_version))
331 if not os.path.exists('/usr/bin/gem'):
332 util.sym_link('/usr/bin/gem%s' % ruby_version, '/usr/bin/gem')
333 if not os.path.exists('/usr/bin/ruby'):
334 util.sym_link('/usr/bin/ruby%s' % ruby_version, '/usr/bin/ruby')
335 if chef_version:
336 util.subp(['/usr/bin/gem', 'install', 'chef',
337 '-v %s' % chef_version, '--no-ri',
338 '--no-rdoc', '--bindir', '/usr/bin', '-q'], capture=False)
339 else:
340 util.subp(['/usr/bin/gem', 'install', 'chef',
341 '--no-ri', '--no-rdoc', '--bindir',
342 '/usr/bin', '-q'], capture=False)
3430
=== removed file 'cloudinit/config/cc_debug.py'
--- cloudinit/config/cc_debug.py 2015-01-21 22:56:53 +0000
+++ cloudinit/config/cc_debug.py 1970-01-01 00:00:00 +0000
@@ -1,109 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2013 Yahoo! Inc.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3, as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17"""
18**Summary:** helper to debug cloud-init *internal* datastructures.
19
20**Description:** This module will enable for outputting various internal
21information that cloud-init sources provide to either a file or to the output
22console/log location that this cloud-init has been configured with when
23running.
24
25It can be configured with the following option structure::
26
27 debug:
28 verbose: (defaulting to true)
29 output: (location to write output, defaulting to console + log)
30
31.. note::
32
33 Log configurations are not output.
34"""
35
36import copy
37
38from six import StringIO
39
40from cloudinit import type_utils
41from cloudinit import util
42
43SKIP_KEYS = frozenset(['log_cfgs'])
44
45
46def _make_header(text):
47 header = StringIO()
48 header.write("-" * 80)
49 header.write("\n")
50 header.write(text.center(80, ' '))
51 header.write("\n")
52 header.write("-" * 80)
53 header.write("\n")
54 return header.getvalue()
55
56
57def _dumps(obj):
58 text = util.yaml_dumps(obj, explicit_start=False, explicit_end=False)
59 return text.rstrip()
60
61
62def handle(name, cfg, cloud, log, args):
63 """Handler method activated by cloud-init."""
64
65 verbose = util.get_cfg_by_path(cfg, ('debug', 'verbose'), default=True)
66 if args:
67 # if args are provided (from cmdline) then explicitly set verbose
68 out_file = args[0]
69 verbose = True
70 else:
71 out_file = util.get_cfg_by_path(cfg, ('debug', 'output'))
72
73 if not verbose:
74 log.debug(("Skipping module named %s,"
75 " verbose printing disabled"), name)
76 return
77 # Clean out some keys that we just don't care about showing...
78 dump_cfg = copy.deepcopy(cfg)
79 for k in SKIP_KEYS:
80 dump_cfg.pop(k, None)
81 all_keys = list(dump_cfg)
82 for k in all_keys:
83 if k.startswith("_"):
84 dump_cfg.pop(k, None)
85 # Now dump it...
86 to_print = StringIO()
87 to_print.write(_make_header("Config"))
88 to_print.write(_dumps(dump_cfg))
89 to_print.write("\n")
90 to_print.write(_make_header("MetaData"))
91 to_print.write(_dumps(cloud.datasource.metadata))
92 to_print.write("\n")
93 to_print.write(_make_header("Misc"))
94 to_print.write("Datasource: %s\n" %
95 (type_utils.obj_name(cloud.datasource)))
96 to_print.write("Distro: %s\n" % (type_utils.obj_name(cloud.distro)))
97 to_print.write("Hostname: %s\n" % (cloud.get_hostname(True)))
98 to_print.write("Instance ID: %s\n" % (cloud.get_instance_id()))
99 to_print.write("Locale: %s\n" % (cloud.get_locale()))
100 to_print.write("Launch IDX: %s\n" % (cloud.launch_index))
101 contents = to_print.getvalue()
102 content_to_file = []
103 for line in contents.splitlines():
104 line = "ci-info: %s\n" % (line)
105 content_to_file.append(line)
106 if out_file:
107 util.write_file(out_file, "".join(content_to_file), 0o644, "w")
108 else:
109 util.multi_log("".join(content_to_file), console=True, stderr=False)
1100
=== removed file 'cloudinit/config/cc_disable_ec2_metadata.py'
--- cloudinit/config/cc_disable_ec2_metadata.py 2012-06-23 04:02:04 +0000
+++ cloudinit/config/cc_disable_ec2_metadata.py 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21from cloudinit import util
22
23from cloudinit.settings import PER_ALWAYS
24
25frequency = PER_ALWAYS
26
27REJECT_CMD = ['route', 'add', '-host', '169.254.169.254', 'reject']
28
29
30def handle(name, cfg, _cloud, log, _args):
31 disabled = util.get_cfg_option_bool(cfg, "disable_ec2_metadata", False)
32 if disabled:
33 util.subp(REJECT_CMD, capture=False)
34 else:
35 log.debug(("Skipping module named %s,"
36 " disabling the ec2 route not enabled"), name)
370
=== renamed file 'cloudinit/config/cc_disk_setup.py' => 'cloudinit/config/cc_disk_setup.py.THIS'
=== removed file 'cloudinit/config/cc_emit_upstart.py'
--- cloudinit/config/cc_emit_upstart.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_emit_upstart.py 1970-01-01 00:00:00 +0000
@@ -1,69 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from cloudinit import log as logging
24from cloudinit.settings import PER_ALWAYS
25from cloudinit import util
26
27frequency = PER_ALWAYS
28
29distros = ['ubuntu', 'debian']
30LOG = logging.getLogger(__name__)
31
32
33def is_upstart_system():
34 if not os.path.isfile("/sbin/initctl"):
35 LOG.debug("no /sbin/initctl located")
36 return False
37
38 myenv = os.environ.copy()
39 if 'UPSTART_SESSION' in myenv:
40 del myenv['UPSTART_SESSION']
41 check_cmd = ['initctl', 'version']
42 try:
43 (out, err) = util.subp(check_cmd, env=myenv)
44 return 'upstart' in out
45 except util.ProcessExecutionError as e:
46 LOG.debug("'%s' returned '%s', not using upstart",
47 ' '.join(check_cmd), e.exit_code)
48 return False
49
50
51def handle(name, _cfg, cloud, log, args):
52 event_names = args
53 if not event_names:
54 # Default to the 'cloud-config'
55 # event for backwards compat.
56 event_names = ['cloud-config']
57
58 if not is_upstart_system():
59 log.debug("not upstart system, '%s' disabled")
60 return
61
62 cfgpath = cloud.paths.get_ipath_cur("cloud_config")
63 for n in event_names:
64 cmd = ['initctl', 'emit', str(n), 'CLOUD_CFG=%s' % cfgpath]
65 try:
66 util.subp(cmd)
67 except Exception as e:
68 # TODO(harlowja), use log exception from utils??
69 log.warn("Emission of upstart event %s failed due to: %s", n, e)
700
=== removed file 'cloudinit/config/cc_fan.py'
--- cloudinit/config/cc_fan.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_fan.py 1970-01-01 00:00:00 +0000
@@ -1,101 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2015 Canonical Ltd.
4#
5# Author: Scott Moser <scott.moser@canonical.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3, as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18"""
19fan module allows configuration of Ubuntu Fan
20 https://wiki.ubuntu.com/FanNetworking
21
22Example config:
23 #cloud-config
24 fan:
25 config: |
26 # fan 240
27 10.0.0.0/8 eth0/16 dhcp
28 10.0.0.0/8 eth1/16 dhcp off
29 # fan 241
30 241.0.0.0/8 eth0/16 dhcp
31 config_path: /etc/network/fan
32
33If cloud-init sees a 'fan' entry in cloud-config it will
34 a.) write 'config_path' with the contents
35 b.) install the package 'ubuntu-fan' if it is not installed
36 c.) ensure the service is started (or restarted if was previously running)
37"""
38
39from cloudinit import log as logging
40from cloudinit.settings import PER_INSTANCE
41from cloudinit import util
42
43LOG = logging.getLogger(__name__)
44
45frequency = PER_INSTANCE
46
47BUILTIN_CFG = {
48 'config': None,
49 'config_path': '/etc/network/fan',
50}
51
52
53def stop_update_start(service, config_file, content, systemd=False):
54 if systemd:
55 cmds = {'stop': ['systemctl', 'stop', service],
56 'start': ['systemctl', 'start', service],
57 'enable': ['systemctl', 'enable', service]}
58 else:
59 cmds = {'stop': ['service', 'stop'],
60 'start': ['service', 'start']}
61
62 def run(cmd, msg):
63 try:
64 return util.subp(cmd, capture=True)
65 except util.ProcessExecutionError as e:
66 LOG.warn("failed: %s (%s): %s", service, cmd, e)
67 return False
68
69 stop_failed = not run(cmds['stop'], msg='stop %s' % service)
70 if not content.endswith('\n'):
71 content += '\n'
72 util.write_file(config_file, content, omode="w")
73
74 ret = run(cmds['start'], msg='start %s' % service)
75 if ret and stop_failed:
76 LOG.warn("success: %s started", service)
77
78 if 'enable' in cmds:
79 ret = run(cmds['enable'], msg='enable %s' % service)
80
81 return ret
82
83
84def handle(name, cfg, cloud, log, args):
85 cfgin = cfg.get('fan')
86 if not cfgin:
87 cfgin = {}
88 mycfg = util.mergemanydict([cfgin, BUILTIN_CFG])
89
90 if not mycfg.get('config'):
91 LOG.debug("%s: no 'fan' config entry. disabling", name)
92 return
93
94 util.write_file(mycfg.get('config_path'), mycfg.get('config'), omode="w")
95 distro = cloud.distro
96 if not util.which('fanctl'):
97 distro.install_packages(['ubuntu-fan'])
98
99 stop_update_start(
100 service='ubuntu-fan', config_file=mycfg.get('config_path'),
101 content=mycfg.get('config'), systemd=distro.uses_systemd())
1020
=== removed file 'cloudinit/config/cc_final_message.py'
--- cloudinit/config/cc_final_message.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_final_message.py 1970-01-01 00:00:00 +0000
@@ -1,73 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21from cloudinit import templater
22from cloudinit import util
23from cloudinit import version
24
25from cloudinit.settings import PER_ALWAYS
26
27frequency = PER_ALWAYS
28
29# Jinja formated default message
30FINAL_MESSAGE_DEF = (
31 "## template: jinja\n"
32 "Cloud-init v. {{version}} finished at {{timestamp}}."
33 " Datasource {{datasource}}. Up {{uptime}} seconds"
34)
35
36
37def handle(_name, cfg, cloud, log, args):
38
39 msg_in = ''
40 if len(args) != 0:
41 msg_in = str(args[0])
42 else:
43 msg_in = util.get_cfg_option_str(cfg, "final_message", "")
44
45 msg_in = msg_in.strip()
46 if not msg_in:
47 msg_in = FINAL_MESSAGE_DEF
48
49 uptime = util.uptime()
50 ts = util.time_rfc2822()
51 cver = version.version_string()
52 try:
53 subs = {
54 'uptime': uptime,
55 'timestamp': ts,
56 'version': cver,
57 'datasource': str(cloud.datasource),
58 }
59 subs.update(dict([(k.upper(), v) for k, v in subs.items()]))
60 util.multi_log("%s\n" % (templater.render_string(msg_in, subs)),
61 console=False, stderr=True, log=log)
62 except Exception:
63 util.logexc(log, "Failed to render final message template")
64
65 boot_fin_fn = cloud.paths.boot_finished
66 try:
67 contents = "%s - %s - v. %s\n" % (uptime, ts, cver)
68 util.write_file(boot_fin_fn, contents)
69 except Exception:
70 util.logexc(log, "Failed to write boot finished file %s", boot_fin_fn)
71
72 if cloud.datasource.is_disconnected:
73 log.warn("Used fallback datasource")
740
=== removed file 'cloudinit/config/cc_foo.py'
--- cloudinit/config/cc_foo.py 2012-06-21 16:12:16 +0000
+++ cloudinit/config/cc_foo.py 1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21from cloudinit.settings import PER_INSTANCE
22
23# Modules are expected to have the following attributes.
24# 1. A required 'handle' method which takes the following params.
25# a) The name will not be this files name, but instead
26# the name specified in configuration (which is the name
27# which will be used to find this module).
28# b) A configuration object that is the result of the merging
29# of cloud configs configuration with legacy configuration
30# as well as any datasource provided configuration
31# c) A cloud object that can be used to access various
32# datasource and paths for the given distro and data provided
33# by the various datasource instance types.
34# d) A argument list that may or may not be empty to this module.
35# Typically those are from module configuration where the module
36# is defined with some extra configuration that will eventually
37# be translated from yaml into arguments to this module.
38# 2. A optional 'frequency' that defines how often this module should be ran.
39# Typically one of PER_INSTANCE, PER_ALWAYS, PER_ONCE. If not
40# provided PER_INSTANCE will be assumed.
41# See settings.py for these constants.
42# 3. A optional 'distros' array/set/tuple that defines the known distros
43# this module will work with (if not all of them). This is used to write
44# a warning out if a module is being ran on a untested distribution for
45# informational purposes. If non existent all distros are assumed and
46# no warning occurs.
47
48frequency = PER_INSTANCE
49
50
51def handle(name, _cfg, _cloud, log, _args):
52 log.debug("Hi from module %s", name)
530
=== removed file 'cloudinit/config/cc_growpart.py'
--- cloudinit/config/cc_growpart.py 2015-06-16 15:18:33 +0000
+++ cloudinit/config/cc_growpart.py 1970-01-01 00:00:00 +0000
@@ -1,300 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22import os.path
23import re
24import stat
25
26from cloudinit import log as logging
27from cloudinit.settings import PER_ALWAYS
28from cloudinit import util
29
30frequency = PER_ALWAYS
31
32DEFAULT_CONFIG = {
33 'mode': 'auto',
34 'devices': ['/'],
35 'ignore_growroot_disabled': False,
36}
37
38
39def enum(**enums):
40 return type('Enum', (), enums)
41
42
43RESIZE = enum(SKIPPED="SKIPPED", CHANGED="CHANGED", NOCHANGE="NOCHANGE",
44 FAILED="FAILED")
45
46LOG = logging.getLogger(__name__)
47
48
49def resizer_factory(mode):
50 resize_class = None
51 if mode == "auto":
52 for (_name, resizer) in RESIZERS:
53 cur = resizer()
54 if cur.available():
55 resize_class = cur
56 break
57
58 if not resize_class:
59 raise ValueError("No resizers available")
60
61 else:
62 mmap = {}
63 for (k, v) in RESIZERS:
64 mmap[k] = v
65
66 if mode not in mmap:
67 raise TypeError("unknown resize mode %s" % mode)
68
69 mclass = mmap[mode]()
70 if mclass.available():
71 resize_class = mclass
72
73 if not resize_class:
74 raise ValueError("mode %s not available" % mode)
75
76 return resize_class
77
78
79class ResizeFailedException(Exception):
80 pass
81
82
83class ResizeGrowPart(object):
84 def available(self):
85 myenv = os.environ.copy()
86 myenv['LANG'] = 'C'
87
88 try:
89 (out, _err) = util.subp(["growpart", "--help"], env=myenv)
90 if re.search(r"--update\s+", out, re.DOTALL):
91 return True
92
93 except util.ProcessExecutionError:
94 pass
95 return False
96
97 def resize(self, diskdev, partnum, partdev):
98 before = get_size(partdev)
99 try:
100 util.subp(["growpart", '--dry-run', diskdev, partnum])
101 except util.ProcessExecutionError as e:
102 if e.exit_code != 1:
103 util.logexc(LOG, "Failed growpart --dry-run for (%s, %s)",
104 diskdev, partnum)
105 raise ResizeFailedException(e)
106 return (before, before)
107
108 try:
109 util.subp(["growpart", diskdev, partnum])
110 except util.ProcessExecutionError as e:
111 util.logexc(LOG, "Failed: growpart %s %s", diskdev, partnum)
112 raise ResizeFailedException(e)
113
114 return (before, get_size(partdev))
115
116
117class ResizeGpart(object):
118 def available(self):
119 if not util.which('gpart'):
120 return False
121 return True
122
123 def resize(self, diskdev, partnum, partdev):
124 """
125 GPT disks store metadata at the beginning (primary) and at the
126 end (secondary) of the disk. When launching an image with a
127 larger disk compared to the original image, the secondary copy
128 is lost. Thus, the metadata will be marked CORRUPT, and need to
129 be recovered.
130 """
131 try:
132 util.subp(["gpart", "recover", diskdev])
133 except util.ProcessExecutionError as e:
134 if e.exit_code != 0:
135 util.logexc(LOG, "Failed: gpart recover %s", diskdev)
136 raise ResizeFailedException(e)
137
138 before = get_size(partdev)
139 try:
140 util.subp(["gpart", "resize", "-i", partnum, diskdev])
141 except util.ProcessExecutionError as e:
142 util.logexc(LOG, "Failed: gpart resize -i %s %s", partnum, diskdev)
143 raise ResizeFailedException(e)
144
145 # Since growing the FS requires a reboot, make sure we reboot
146 # first when this module has finished.
147 open('/var/run/reboot-required', 'a').close()
148
149 return (before, get_size(partdev))
150
151
152def get_size(filename):
153 fd = os.open(filename, os.O_RDONLY)
154 try:
155 return os.lseek(fd, 0, os.SEEK_END)
156 finally:
157 os.close(fd)
158
159
160def device_part_info(devpath):
161 # convert an entry in /dev/ to parent disk and partition number
162
163 # input of /dev/vdb or /dev/disk/by-label/foo
164 # rpath is hopefully a real-ish path in /dev (vda, sdb..)
165 rpath = os.path.realpath(devpath)
166
167 bname = os.path.basename(rpath)
168 syspath = "/sys/class/block/%s" % bname
169
170 # FreeBSD doesn't know of sysfs so just get everything we need from
171 # the device, like /dev/vtbd0p2.
172 if util.system_info()["platform"].startswith('FreeBSD'):
173 m = re.search('^(/dev/.+)p([0-9])$', devpath)
174 return (m.group(1), m.group(2))
175
176 if not os.path.exists(syspath):
177 raise ValueError("%s had no syspath (%s)" % (devpath, syspath))
178
179 ptpath = os.path.join(syspath, "partition")
180 if not os.path.exists(ptpath):
181 raise TypeError("%s not a partition" % devpath)
182
183 ptnum = util.load_file(ptpath).rstrip()
184
185 # for a partition, real syspath is something like:
186 # /sys/devices/pci0000:00/0000:00:04.0/virtio1/block/vda/vda1
187 rsyspath = os.path.realpath(syspath)
188 disksyspath = os.path.dirname(rsyspath)
189
190 diskmajmin = util.load_file(os.path.join(disksyspath, "dev")).rstrip()
191 diskdevpath = os.path.realpath("/dev/block/%s" % diskmajmin)
192
193 # diskdevpath has something like 253:0
194 # and udev has put links in /dev/block/253:0 to the device name in /dev/
195 return (diskdevpath, ptnum)
196
197
198def devent2dev(devent):
199 if devent.startswith("/dev/"):
200 return devent
201 else:
202 result = util.get_mount_info(devent)
203 if not result:
204 raise ValueError("Could not determine device of '%s' % dev_ent")
205 return result[0]
206
207
208def resize_devices(resizer, devices):
209 # returns a tuple of tuples containing (entry-in-devices, action, message)
210 info = []
211 for devent in devices:
212 try:
213 blockdev = devent2dev(devent)
214 except ValueError as e:
215 info.append((devent, RESIZE.SKIPPED,
216 "unable to convert to device: %s" % e,))
217 continue
218
219 try:
220 statret = os.stat(blockdev)
221 except OSError as e:
222 info.append((devent, RESIZE.SKIPPED,
223 "stat of '%s' failed: %s" % (blockdev, e),))
224 continue
225
226 if (not stat.S_ISBLK(statret.st_mode) and
227 not stat.S_ISCHR(statret.st_mode)):
228 info.append((devent, RESIZE.SKIPPED,
229 "device '%s' not a block device" % blockdev,))
230 continue
231
232 try:
233 (disk, ptnum) = device_part_info(blockdev)
234 except (TypeError, ValueError) as e:
235 info.append((devent, RESIZE.SKIPPED,
236 "device_part_info(%s) failed: %s" % (blockdev, e),))
237 continue
238
239 try:
240 (old, new) = resizer.resize(disk, ptnum, blockdev)
241 if old == new:
242 info.append((devent, RESIZE.NOCHANGE,
243 "no change necessary (%s, %s)" % (disk, ptnum),))
244 else:
245 info.append((devent, RESIZE.CHANGED,
246 "changed (%s, %s) from %s to %s" %
247 (disk, ptnum, old, new),))
248
249 except ResizeFailedException as e:
250 info.append((devent, RESIZE.FAILED,
251 "failed to resize: disk=%s, ptnum=%s: %s" %
252 (disk, ptnum, e),))
253
254 return info
255
256
257def handle(_name, cfg, _cloud, log, _args):
258 if 'growpart' not in cfg:
259 log.debug("No 'growpart' entry in cfg. Using default: %s" %
260 DEFAULT_CONFIG)
261 cfg['growpart'] = DEFAULT_CONFIG
262
263 mycfg = cfg.get('growpart')
264 if not isinstance(mycfg, dict):
265 log.warn("'growpart' in config was not a dict")
266 return
267
268 mode = mycfg.get('mode', "auto")
269 if util.is_false(mode):
270 log.debug("growpart disabled: mode=%s" % mode)
271 return
272
273 if util.is_false(mycfg.get('ignore_growroot_disabled', False)):
274 if os.path.isfile("/etc/growroot-disabled"):
275 log.debug("growpart disabled: /etc/growroot-disabled exists")
276 log.debug("use ignore_growroot_disabled to ignore")
277 return
278
279 devices = util.get_cfg_option_list(mycfg, "devices", ["/"])
280 if not len(devices):
281 log.debug("growpart: empty device list")
282 return
283
284 try:
285 resizer = resizer_factory(mode)
286 except (ValueError, TypeError) as e:
287 log.debug("growpart unable to find resizer for '%s': %s" % (mode, e))
288 if mode != "auto":
289 raise e
290 return
291
292 resized = util.log_time(logfunc=log.debug, msg="resize_devices",
293 func=resize_devices, args=(resizer, devices))
294 for (entry, action, msg) in resized:
295 if action == RESIZE.CHANGED:
296 log.info("'%s' resized: %s" % (entry, msg))
297 else:
298 log.debug("'%s' %s: %s" % (entry, action, msg))
299
300RESIZERS = (('growpart', ResizeGrowPart), ('gpart', ResizeGpart))
3010
=== removed file 'cloudinit/config/cc_grub_dpkg.py'
--- cloudinit/config/cc_grub_dpkg.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_grub_dpkg.py 1970-01-01 00:00:00 +0000
@@ -1,73 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from cloudinit import util
24
25distros = ['ubuntu', 'debian']
26
27
28def handle(name, cfg, _cloud, log, _args):
29
30 mycfg = cfg.get("grub_dpkg", cfg.get("grub-dpkg", {}))
31 if not mycfg:
32 mycfg = {}
33
34 enabled = mycfg.get('enabled', True)
35 if util.is_false(enabled):
36 log.debug("%s disabled by config grub_dpkg/enabled=%s", name, enabled)
37 return
38
39 idevs = util.get_cfg_option_str(mycfg, "grub-pc/install_devices", None)
40 idevs_empty = util.get_cfg_option_str(
41 mycfg, "grub-pc/install_devices_empty", None)
42
43 if ((os.path.exists("/dev/sda1") and not os.path.exists("/dev/sda")) or
44 (os.path.exists("/dev/xvda1") and not os.path.exists("/dev/xvda"))):
45 if idevs is None:
46 idevs = ""
47 if idevs_empty is None:
48 idevs_empty = "true"
49 else:
50 if idevs_empty is None:
51 idevs_empty = "false"
52 if idevs is None:
53 idevs = "/dev/sda"
54 for dev in ("/dev/sda", "/dev/vda", "/dev/xvda",
55 "/dev/sda1", "/dev/vda1", "/dev/xvda1"):
56 if os.path.exists(dev):
57 idevs = dev
58 break
59
60 # now idevs and idevs_empty are set to determined values
61 # or, those set by user
62
63 dconf_sel = (("grub-pc grub-pc/install_devices string %s\n"
64 "grub-pc grub-pc/install_devices_empty boolean %s\n") %
65 (idevs, idevs_empty))
66
67 log.debug("Setting grub debconf-set-selections with '%s','%s'" %
68 (idevs, idevs_empty))
69
70 try:
71 util.subp(['debconf-set-selections'], dconf_sel)
72 except Exception:
73 util.logexc(log, "Failed to run debconf-set-selections for grub-dpkg")
740
=== removed file 'cloudinit/config/cc_keys_to_console.py'
--- cloudinit/config/cc_keys_to_console.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_keys_to_console.py 1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from cloudinit.settings import PER_INSTANCE
24from cloudinit import util
25
26frequency = PER_INSTANCE
27
28# This is a tool that cloud init provides
29HELPER_TOOL_TPL = '%s/cloud-init/write-ssh-key-fingerprints'
30
31
32def _get_helper_tool_path(distro):
33 try:
34 base_lib = distro.usr_lib_exec
35 except AttributeError:
36 base_lib = '/usr/lib'
37 return HELPER_TOOL_TPL % base_lib
38
39
40def handle(name, cfg, cloud, log, _args):
41 helper_path = _get_helper_tool_path(cloud.distro)
42 if not os.path.exists(helper_path):
43 log.warn(("Unable to activate module %s,"
44 " helper tool not found at %s"), name, helper_path)
45 return
46
47 fp_blacklist = util.get_cfg_option_list(cfg,
48 "ssh_fp_console_blacklist", [])
49 key_blacklist = util.get_cfg_option_list(cfg,
50 "ssh_key_console_blacklist",
51 ["ssh-dss"])
52
53 try:
54 cmd = [helper_path]
55 cmd.append(','.join(fp_blacklist))
56 cmd.append(','.join(key_blacklist))
57 (stdout, _stderr) = util.subp(cmd)
58 util.multi_log("%s\n" % (stdout.strip()),
59 stderr=False, console=True)
60 except Exception:
61 log.warn("Writing keys to the system console failed!")
62 raise
630
=== removed file 'cloudinit/config/cc_landscape.py'
--- cloudinit/config/cc_landscape.py 2016-03-04 06:45:58 +0000
+++ cloudinit/config/cc_landscape.py 1970-01-01 00:00:00 +0000
@@ -1,99 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from six import StringIO
24
25from configobj import ConfigObj
26
27from cloudinit import type_utils
28from cloudinit import util
29
30from cloudinit.settings import PER_INSTANCE
31
32frequency = PER_INSTANCE
33
34LSC_CLIENT_CFG_FILE = "/etc/landscape/client.conf"
35LS_DEFAULT_FILE = "/etc/default/landscape-client"
36
37distros = ['ubuntu']
38
39# defaults taken from stock client.conf in landscape-client 11.07.1.1-0ubuntu2
40LSC_BUILTIN_CFG = {
41 'client': {
42 'log_level': "info",
43 'url': "https://landscape.canonical.com/message-system",
44 'ping_url': "http://landscape.canonical.com/ping",
45 'data_path': "/var/lib/landscape/client",
46 }
47}
48
49
50def handle(_name, cfg, cloud, log, _args):
51 """
52 Basically turn a top level 'landscape' entry with a 'client' dict
53 and render it to ConfigObj format under '[client]' section in
54 /etc/landscape/client.conf
55 """
56
57 ls_cloudcfg = cfg.get("landscape", {})
58
59 if not isinstance(ls_cloudcfg, (dict)):
60 raise RuntimeError(("'landscape' key existed in config,"
61 " but not a dictionary type,"
62 " is a %s instead"),
63 type_utils.obj_name(ls_cloudcfg))
64 if not ls_cloudcfg:
65 return
66
67 cloud.distro.install_packages(('landscape-client',))
68
69 merge_data = [
70 LSC_BUILTIN_CFG,
71 LSC_CLIENT_CFG_FILE,
72 ls_cloudcfg,
73 ]
74 merged = merge_together(merge_data)
75 contents = StringIO()
76 merged.write(contents)
77
78 util.ensure_dir(os.path.dirname(LSC_CLIENT_CFG_FILE))
79 util.write_file(LSC_CLIENT_CFG_FILE, contents.getvalue())
80 log.debug("Wrote landscape config file to %s", LSC_CLIENT_CFG_FILE)
81
82 util.write_file(LS_DEFAULT_FILE, "RUN=1\n")
83 util.subp(["service", "landscape-client", "restart"])
84
85
86def merge_together(objs):
87 """
88 merge together ConfigObj objects or things that ConfigObj() will take in
89 later entries override earlier
90 """
91 cfg = ConfigObj({})
92 for obj in objs:
93 if not obj:
94 continue
95 if isinstance(obj, ConfigObj):
96 cfg.merge(obj)
97 else:
98 cfg.merge(ConfigObj(obj))
99 return cfg
1000
=== removed file 'cloudinit/config/cc_locale.py'
--- cloudinit/config/cc_locale.py 2015-03-04 19:49:44 +0000
+++ cloudinit/config/cc_locale.py 1970-01-01 00:00:00 +0000
@@ -1,37 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21from cloudinit import util
22
23
24def handle(name, cfg, cloud, log, args):
25 if len(args) != 0:
26 locale = args[0]
27 else:
28 locale = util.get_cfg_option_str(cfg, "locale", cloud.get_locale())
29
30 if util.is_false(locale):
31 log.debug("Skipping module named %s, disabled by config: %s",
32 name, locale)
33 return
34
35 log.debug("Setting locale to %s", locale)
36 locale_cfgfile = util.get_cfg_option_str(cfg, "locale_configfile")
37 cloud.distro.apply_locale(locale, locale_cfgfile)
380
=== removed file 'cloudinit/config/cc_lxd.py'
--- cloudinit/config/cc_lxd.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_lxd.py 1970-01-01 00:00:00 +0000
@@ -1,176 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2016 Canonical Ltd.
4#
5# Author: Wesley Wiedenmeier <wesley.wiedenmeier@canonical.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3, as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""
20This module initializes lxd using 'lxd init'
21
22Example config:
23 #cloud-config
24 lxd:
25 init:
26 network_address: <ip addr>
27 network_port: <port>
28 storage_backend: <zfs/dir>
29 storage_create_device: <dev>
30 storage_create_loop: <size>
31 storage_pool: <name>
32 trust_password: <password>
33 bridge:
34 mode: <new, existing or none>
35 name: <name>
36 ipv4_address: <ip addr>
37 ipv4_netmask: <cidr>
38 ipv4_dhcp_first: <ip addr>
39 ipv4_dhcp_last: <ip addr>
40 ipv4_dhcp_leases: <size>
41 ipv4_nat: <bool>
42 ipv6_address: <ip addr>
43 ipv6_netmask: <cidr>
44 ipv6_nat: <bool>
45 domain: <domain>
46"""
47
48from cloudinit import util
49
50
51def handle(name, cfg, cloud, log, args):
52 # Get config
53 lxd_cfg = cfg.get('lxd')
54 if not lxd_cfg:
55 log.debug("Skipping module named %s, not present or disabled by cfg")
56 return
57 if not isinstance(lxd_cfg, dict):
58 log.warn("lxd config must be a dictionary. found a '%s'",
59 type(lxd_cfg))
60 return
61
62 # Grab the configuration
63 init_cfg = lxd_cfg.get('init')
64 if not isinstance(init_cfg, dict):
65 log.warn("lxd/init config must be a dictionary. found a '%s'",
66 type(init_cfg))
67 init_cfg = {}
68
69 bridge_cfg = lxd_cfg.get('bridge')
70 if not isinstance(bridge_cfg, dict):
71 log.warn("lxd/bridge config must be a dictionary. found a '%s'",
72 type(bridge_cfg))
73 bridge_cfg = {}
74
75 # Install the needed packages
76 packages = []
77 if not util.which("lxd"):
78 packages.append('lxd')
79
80 if init_cfg.get("storage_backend") == "zfs" and not util.which('zfs'):
81 packages.append('zfs')
82
83 if len(packages):
84 try:
85 cloud.distro.install_packages(packages)
86 except util.ProcessExecutionError as exc:
87 log.warn("failed to install packages %s: %s", packages, exc)
88 return
89
90 # Set up lxd if init config is given
91 if init_cfg:
92 init_keys = (
93 'network_address', 'network_port', 'storage_backend',
94 'storage_create_device', 'storage_create_loop',
95 'storage_pool', 'trust_password')
96 cmd = ['lxd', 'init', '--auto']
97 for k in init_keys:
98 if init_cfg.get(k):
99 cmd.extend(["--%s=%s" %
100 (k.replace('_', '-'), str(init_cfg[k]))])
101 util.subp(cmd)
102
103 # Set up lxd-bridge if bridge config is given
104 dconf_comm = "debconf-communicate"
105 if bridge_cfg and util.which(dconf_comm):
106 debconf = bridge_to_debconf(bridge_cfg)
107
108 # Update debconf database
109 try:
110 log.debug("Setting lxd debconf via " + dconf_comm)
111 data = "\n".join(["set %s %s" % (k, v)
112 for k, v in debconf.items()]) + "\n"
113 util.subp(['debconf-communicate'], data)
114 except Exception:
115 util.logexc(log, "Failed to run '%s' for lxd with" % dconf_comm)
116
117 # Remove the existing configuration file (forces re-generation)
118 util.del_file("/etc/default/lxd-bridge")
119
120 # Run reconfigure
121 log.debug("Running dpkg-reconfigure for lxd")
122 util.subp(['dpkg-reconfigure', 'lxd',
123 '--frontend=noninteractive'])
124 elif bridge_cfg:
125 raise RuntimeError(
126 "Unable to configure lxd bridge without %s." + dconf_comm)
127
128
129def bridge_to_debconf(bridge_cfg):
130 debconf = {}
131
132 if bridge_cfg.get("mode") == "none":
133 debconf["lxd/setup-bridge"] = "false"
134 debconf["lxd/bridge-name"] = ""
135
136 elif bridge_cfg.get("mode") == "existing":
137 debconf["lxd/setup-bridge"] = "false"
138 debconf["lxd/use-existing-bridge"] = "true"
139 debconf["lxd/bridge-name"] = bridge_cfg.get("name")
140
141 elif bridge_cfg.get("mode") == "new":
142 debconf["lxd/setup-bridge"] = "true"
143 if bridge_cfg.get("name"):
144 debconf["lxd/bridge-name"] = bridge_cfg.get("name")
145
146 if bridge_cfg.get("ipv4_address"):
147 debconf["lxd/bridge-ipv4"] = "true"
148 debconf["lxd/bridge-ipv4-address"] = \
149 bridge_cfg.get("ipv4_address")
150 debconf["lxd/bridge-ipv4-netmask"] = \
151 bridge_cfg.get("ipv4_netmask")
152 debconf["lxd/bridge-ipv4-dhcp-first"] = \
153 bridge_cfg.get("ipv4_dhcp_first")
154 debconf["lxd/bridge-ipv4-dhcp-last"] = \
155 bridge_cfg.get("ipv4_dhcp_last")
156 debconf["lxd/bridge-ipv4-dhcp-leases"] = \
157 bridge_cfg.get("ipv4_dhcp_leases")
158 debconf["lxd/bridge-ipv4-nat"] = \
159 bridge_cfg.get("ipv4_nat", "true")
160
161 if bridge_cfg.get("ipv6_address"):
162 debconf["lxd/bridge-ipv6"] = "true"
163 debconf["lxd/bridge-ipv6-address"] = \
164 bridge_cfg.get("ipv6_address")
165 debconf["lxd/bridge-ipv6-netmask"] = \
166 bridge_cfg.get("ipv6_netmask")
167 debconf["lxd/bridge-ipv6-nat"] = \
168 bridge_cfg.get("ipv6_nat", "false")
169
170 if bridge_cfg.get("domain"):
171 debconf["lxd/bridge-domain"] = bridge_cfg.get("domain")
172
173 else:
174 raise Exception("invalid bridge mode \"%s\"" % bridge_cfg.get("mode"))
175
176 return debconf
1770
=== removed file 'cloudinit/config/cc_mcollective.py'
--- cloudinit/config/cc_mcollective.py 2015-01-21 22:56:53 +0000
+++ cloudinit/config/cc_mcollective.py 1970-01-01 00:00:00 +0000
@@ -1,88 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2011 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Marc Cluet <marc.cluet@canonical.com>
7# Based on code by Scott Moser <scott.moser@canonical.com>
8# Author: Juerg Haefliger <juerg.haefliger@hp.com>
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 3, as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22import six
23from six import StringIO
24
25# Used since this can maintain comments
26# and doesn't need a top level section
27from configobj import ConfigObj
28
29from cloudinit import util
30
31PUBCERT_FILE = "/etc/mcollective/ssl/server-public.pem"
32PRICERT_FILE = "/etc/mcollective/ssl/server-private.pem"
33SERVER_CFG = '/etc/mcollective/server.cfg'
34
35
36def handle(name, cfg, cloud, log, _args):
37
38 # If there isn't a mcollective key in the configuration don't do anything
39 if 'mcollective' not in cfg:
40 log.debug(("Skipping module named %s, "
41 "no 'mcollective' key in configuration"), name)
42 return
43
44 mcollective_cfg = cfg['mcollective']
45
46 # Start by installing the mcollective package ...
47 cloud.distro.install_packages(("mcollective",))
48
49 # ... and then update the mcollective configuration
50 if 'conf' in mcollective_cfg:
51 # Read server.cfg values from the
52 # original file in order to be able to mix the rest up
53 mcollective_config = ConfigObj(SERVER_CFG)
54 # See: http://tiny.cc/jh9agw
55 for (cfg_name, cfg) in mcollective_cfg['conf'].items():
56 if cfg_name == 'public-cert':
57 util.write_file(PUBCERT_FILE, cfg, mode=0o644)
58 mcollective_config['plugin.ssl_server_public'] = PUBCERT_FILE
59 mcollective_config['securityprovider'] = 'ssl'
60 elif cfg_name == 'private-cert':
61 util.write_file(PRICERT_FILE, cfg, mode=0o600)
62 mcollective_config['plugin.ssl_server_private'] = PRICERT_FILE
63 mcollective_config['securityprovider'] = 'ssl'
64 else:
65 if isinstance(cfg, six.string_types):
66 # Just set it in the 'main' section
67 mcollective_config[cfg_name] = cfg
68 elif isinstance(cfg, (dict)):
69 # Iterate through the config items, create a section
70 # if it is needed and then add/or create items as needed
71 if cfg_name not in mcollective_config.sections:
72 mcollective_config[cfg_name] = {}
73 for (o, v) in cfg.items():
74 mcollective_config[cfg_name][o] = v
75 else:
76 # Otherwise just try to convert it to a string
77 mcollective_config[cfg_name] = str(cfg)
78 # We got all our config as wanted we'll rename
79 # the previous server.cfg and create our new one
80 util.rename(SERVER_CFG, "%s.old" % (SERVER_CFG))
81 # Now we got the whole file, write to disk...
82 contents = StringIO()
83 mcollective_config.write(contents)
84 contents = contents.getvalue()
85 util.write_file(SERVER_CFG, contents, mode=0o644)
86
87 # Start mcollective
88 util.subp(['service', 'mcollective', 'start'], capture=False)
890
=== removed file 'cloudinit/config/cc_migrator.py'
--- cloudinit/config/cc_migrator.py 2014-02-05 15:36:47 +0000
+++ cloudinit/config/cc_migrator.py 1970-01-01 00:00:00 +0000
@@ -1,85 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2012 Yahoo! Inc.
4#
5# Author: Joshua Harlow <harlowja@yahoo-inc.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3, as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19import os
20import shutil
21
22from cloudinit import helpers
23from cloudinit import util
24
25from cloudinit.settings import PER_ALWAYS
26
27frequency = PER_ALWAYS
28
29
30def _migrate_canon_sems(cloud):
31 paths = (cloud.paths.get_ipath('sem'), cloud.paths.get_cpath('sem'))
32 am_adjusted = 0
33 for sem_path in paths:
34 if not sem_path or not os.path.exists(sem_path):
35 continue
36 for p in os.listdir(sem_path):
37 full_path = os.path.join(sem_path, p)
38 if os.path.isfile(full_path):
39 (name, ext) = os.path.splitext(p)
40 canon_name = helpers.canon_sem_name(name)
41 if canon_name != name:
42 new_path = os.path.join(sem_path, canon_name + ext)
43 shutil.move(full_path, new_path)
44 am_adjusted += 1
45 return am_adjusted
46
47
48def _migrate_legacy_sems(cloud, log):
49 legacy_adjust = {
50 'apt-update-upgrade': [
51 'apt-configure',
52 'package-update-upgrade-install',
53 ],
54 }
55 paths = (cloud.paths.get_ipath('sem'), cloud.paths.get_cpath('sem'))
56 for sem_path in paths:
57 if not sem_path or not os.path.exists(sem_path):
58 continue
59 sem_helper = helpers.FileSemaphores(sem_path)
60 for (mod_name, migrate_to) in legacy_adjust.items():
61 possibles = [mod_name, helpers.canon_sem_name(mod_name)]
62 old_exists = []
63 for p in os.listdir(sem_path):
64 (name, _ext) = os.path.splitext(p)
65 if name in possibles and os.path.isfile(p):
66 old_exists.append(p)
67 for p in old_exists:
68 util.del_file(os.path.join(sem_path, p))
69 (_name, freq) = os.path.splitext(p)
70 for m in migrate_to:
71 log.debug("Migrating %s => %s with the same frequency",
72 p, m)
73 with sem_helper.lock(m, freq):
74 pass
75
76
77def handle(name, cfg, cloud, log, _args):
78 do_migrate = util.get_cfg_option_str(cfg, "migrate", True)
79 if not util.translate_bool(do_migrate):
80 log.debug("Skipping module named %s, migration disabled", name)
81 return
82 sems_moved = _migrate_canon_sems(cloud)
83 log.debug("Migrated %s semaphore files to there canonicalized names",
84 sems_moved)
85 _migrate_legacy_sems(cloud, log)
860
=== removed file 'cloudinit/config/cc_mounts.py'
--- cloudinit/config/cc_mounts.py 2016-05-12 17:56:26 +0000
+++ cloudinit/config/cc_mounts.py 1970-01-01 00:00:00 +0000
@@ -1,405 +0,0 @@
1# vi: ts=4 expandtab
2#
3# Copyright (C) 2009-2010 Canonical Ltd.
4# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 3, as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21from string import whitespace
22
23import logging
24import os.path
25import re
26
27from cloudinit import type_utils
28from cloudinit import util
29
30# Shortname matches 'sda', 'sda1', 'xvda', 'hda', 'sdb', xvdb, vda, vdd1, sr0
31DEVICE_NAME_FILTER = r"^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$"
32DEVICE_NAME_RE = re.compile(DEVICE_NAME_FILTER)
33WS = re.compile("[%s]+" % (whitespace))
34FSTAB_PATH = "/etc/fstab"
35
36LOG = logging.getLogger(__name__)
37
38
39def is_meta_device_name(name):
40 # return true if this is a metadata service name
41 if name in ["ami", "root", "swap"]:
42 return True
43 # names 'ephemeral0' or 'ephemeral1'
44 # 'ebs[0-9]' appears when '--block-device-mapping sdf=snap-d4d90bbc'
45 for enumname in ("ephemeral", "ebs"):
46 if name.startswith(enumname) and name.find(":") == -1:
47 return True
48 return False
49
50
51def _get_nth_partition_for_device(device_path, partition_number):
52 potential_suffixes = [str(partition_number), 'p%s' % (partition_number,),
53 '-part%s' % (partition_number,)]
The diff has been truncated for viewing.