From 16fd813d8543dd629346e81c4043411c32b7d9d1 Mon Sep 17 00:00:00 2001 From: Jeff Bauer Date: Sat, 11 Feb 2012 09:27:14 -0600 Subject: add support for salt minions --- doc/examples/cloud-config-salt-minion.txt | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 doc/examples/cloud-config-salt-minion.txt (limited to 'doc') diff --git a/doc/examples/cloud-config-salt-minion.txt b/doc/examples/cloud-config-salt-minion.txt new file mode 100644 index 00000000..939fdc8b --- /dev/null +++ b/doc/examples/cloud-config-salt-minion.txt @@ -0,0 +1,53 @@ +#cloud-config +# +# This is an example file to automatically setup and run a salt +# minion when the instance boots for the first time. +# Make sure that this file is valid yaml before starting instances. +# It should be passed as user-data when starting the instance. + +salt_minion: + # conf contains all the directives to be assigned in /etc/salt/minion. + + conf: + # Set the location of the salt master server, if the master server cannot be + # resolved, then the minion will fail to start. + + master: salt.example.com + + # Salt keys are manually generated by: salt-key --gen-keys=GEN_KEYS, + # where GEN_KEYS is the name of the keypair, e.g. 'minion'. The keypair + # will be copied to /etc/salt/pki on the minion instance. + + public_key: | + -----BEGIN PUBLIC KEY----- + MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAwI4yqk1Y12zVmu9Ejlua + h2FD6kjrt+N9XfGqZUUVNeRb7CA0Sj5Q6NtgoaiXuIrSea2sLda6ivqAGmtxMMrP + zpf3FwsYWxBUNF7D4YeLmYjvcTbfr3bCOIRnPNXZ+4isuvvEiM02u2cO0okZSgeb + dofNa1NbTLYAQr9jZZb7GPKrTO4CKy0xzBih/A+sl6dL9PNDmqXQEjyJS6PXG1Vj + PvD5jpSrxuIl5Ms/+2Ro3ALgvC8dgoY/3m3csnd06afumGKv5YOGtf+bnWLhc0bf + 6Sk8Q6i5t0Bl+HAULSPr+B9x/I0rN76ZnPvTj1+hJ0zTof4d0hOLx/K5OQyt7AKo + 4wIBAQ== + -----END PUBLIC KEY----- + + private_key: | + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: AES-128-CBC,ECE30DBBA56E2DF06B7BC415F8870994 + + YQOE5HIsghqjRsxPQqiWMH/VHmyFH6xIpBcmzxzispEHwBojlvLXviwvR66YhgNw + 7smwE10Ik4/cwwiHTZqCk++jPATPygBiqQkUijCWzcT9kfaxmqdP4PL+hu9g7kGC + KrD2Bm8/oO08s957aThuHC1sABRcJ1V3FRzJT6Za4fwweyvHVYRnmgaDA6zH0qV8 + NqBSB2hnNXKEdh6UFz9QGcrQxnRjfdIaW64zoEX7jT7gYYL7FkGXBa3XdMOA4fnl + adRwLFMs0jfilisZv8oUbPdZ6J6x3o8p8LVecCF8tdZt1zkcLSIXKnoDFpHSISGs + BD9aqD+E4ejynM/tPaVFq4IHzT8viN6h6WcH8fbpClFZ66Iyy9XL3/CjAY7Jzhh9 + fnbc4Iq28cdbmO/vkR7JyVOgEMWe1BcSqtro70XoUNRY8uDJUPqohrhm/9AigFRA + Pwyf3LqojxRnwXjHsZtGltUtEAPZzgh3fKJnx9MyRR7DPXBRig7TAHU7n2BFRhHA + TYThy29bK6NkIc/cKc2kEQVo98Cr04PO8jVxZM332FlhiVlP0kpAp+tFj7aMzPTG + sJumb9kPbMsgpEuTCONm3yyoufGEBFMrIJ+Po48M2RlYOh50VkO09pI+Eu7FPtVB + H4gKzoJIpZZ/7vYXQ3djM8s9hc5gD5CVExTZV4drbsXt6ITiwHuxZ6CNHRBPL5AY + wmF8QZz4oivv1afdSe6E6OGC3uVmX3Psn5CVq2pE8VlRDKFy1WqfU2enRAijSS2B + rtJs263fOJ8ZntDzMVMPgiAlzzfA285KUletpAeUmz+peR1gNzkE0eKSG6THOCi0 + rfmR8SeEzyNvin0wQ3qgYiiHjHbbFhJIMAQxoX+0hDSooM7Wo5wkLREULpGuesTg + A6Fe3CiOivMDraNGA7H6Yg== + -----END RSA PRIVATE KEY----- + -- cgit v1.2.3 From 02aea2383e0ea020fd6c2e74ffcaad8983820a9d Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 17 Feb 2012 12:14:48 -0500 Subject: support reading network interface config from DataSourceNoCloud document usage of DataSourceNoCloud from vfat or iso disk. --- ChangeLog | 1 + cloudinit/DataSourceNoCloud.py | 41 +++++++++++++++++++++++++++++-- doc/nocloud/README | 55 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 doc/nocloud/README (limited to 'doc') diff --git a/ChangeLog b/ChangeLog index 52d170c8..cd92618d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,7 @@ - DataSourceOVF: only search for OVF data on ISO9660 filesystems (LP: #898373) - DataSourceConfigDrive: support getting data from openstack config drive (LP: #857378) - DataSourceNoCloud: support seed from external disk of ISO or vfat (LP: #857378) + - DataSourceNoCloud: support inserting /etc/network/interfaces 0.6.2: - fix bug where update was not done unless update was explicitly set. It would not be run if 'upgrade' or packages were set to be installed diff --git a/cloudinit/DataSourceNoCloud.py b/cloudinit/DataSourceNoCloud.py index 6c744b82..1e28edbd 100644 --- a/cloudinit/DataSourceNoCloud.py +++ b/cloudinit/DataSourceNoCloud.py @@ -24,6 +24,7 @@ from cloudinit import seeddir as base_seeddir from cloudinit import log import cloudinit.util as util import errno +import subprocess class DataSourceNoCloud(DataSource.DataSource): @@ -31,6 +32,7 @@ class DataSourceNoCloud(DataSource.DataSource): userdata = None userdata_raw = None supported_seed_starts = ("/", "file://") + dsmode = "local" seed = None cmdline_id = "ds=nocloud" seeddir = base_seeddir + '/nocloud' @@ -42,7 +44,7 @@ class DataSourceNoCloud(DataSource.DataSource): def get_data(self): defaults = { - "instance-id": "nocloud" + "instance-id": "nocloud", "dsmode": "net" } found = [] @@ -84,14 +86,20 @@ class DataSourceNoCloud(DataSource.DataSource): except OSError, e: if e.errno != errno.ENOENT: raise + except util.mountFailedError: + log.warn("Failed to mount %s when looking for seed" % dev) # there was no indication on kernel cmdline or data # in the seeddir suggesting this handler should be used. if len(found) == 0: return False + seeded_interfaces = None + # the special argument "seedfrom" indicates we should # attempt to seed the userdata / metadata from its value + # its primarily value is in allowing the user to type less + # on the command line, ie: ds=nocloud;s=http://bit.ly/abcdefg if "seedfrom" in md: seedfrom = md["seedfrom"] seedfound = False @@ -104,6 +112,9 @@ class DataSourceNoCloud(DataSource.DataSource): (seedfrom, self.__class__)) return False + if 'network-interfaces' in md: + seeded_interfaces = self.dsmode + # this could throw errors, but the user told us to do it # so if errors are raised, let them raise (md_seed, ud) = util.read_seeded(seedfrom, timeout=None) @@ -114,10 +125,35 @@ class DataSourceNoCloud(DataSource.DataSource): found.append(seedfrom) md = util.mergedict(md, defaults) + + # update the network-interfaces if metadata had 'network-interfaces' + # entry and this is the local datasource, or 'seedfrom' was used + # and the source of the seed was self.dsmode + # ('local' for NoCloud, 'net' for NoCloudNet') + if ('network-interfaces' in md and + (self.dsmode in ("local", seeded_interfaces))): + log.info("updating network interfaces from nocloud") + + util.write_file("/etc/network/interfaces", + md['network-interfaces']) + try: + (out, err) = util.subp(['ifup', '--all']) + if len(out) or len(err): + log.warn("ifup --all had stderr: %s" % err) + + except subprocess.CalledProcessError as exc: + log.warn("ifup --all failed: %s" % (exc.output[1])) + self.seed = ",".join(found) self.metadata = md self.userdata_raw = ud - return True + + if md['dsmode'] == self.dsmode: + return True + + log.debug("%s: not claiming datasource, dsmode=%s" % + (self, md['dsmode'])) + return False # returns true or false indicating if cmdline indicated @@ -166,6 +202,7 @@ class DataSourceNoCloudNet(DataSourceNoCloud): cmdline_id = "ds=nocloud-net" supported_seed_starts = ("http://", "https://", "ftp://") seeddir = base_seeddir + '/nocloud-net' + dsmode = "net" datasources = ( diff --git a/doc/nocloud/README b/doc/nocloud/README new file mode 100644 index 00000000..c94b206a --- /dev/null +++ b/doc/nocloud/README @@ -0,0 +1,55 @@ +The data source 'NoCloud' and 'NoCloudNet' allow the user to provide user-data +and meta-data to the instance without running a network service (or even without +having a network at all) + +You can provide meta-data and user-data to a local vm boot via files on a vfat +or iso9660 filesystem. These user-data and meta-data files are expected to be +in the format described in doc/example/seed/README . Basically, user-data is +simply user-data and meta-data is a yaml formated file representing what you'd +find in the EC2 metadata service. + +Given a disk 12.04 cloud image in 'disk.img', you can create a sufficient disk +by following the example below. + +## create user-data and meta-data files that will be used +## to modify image on first boot +$ { echo instance-id: iid-local01; echo local-hostname: cloudimg; } > meta-data + +$ printf "#cloud-config\npassword: passw0rd\nchpasswd: { expire: False }\nssh_pwauth: True\n" > user-data + +## create a disk to attach with some user-data and meta-data +$ genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data + +## alternatively, create a vfat filesystem with same files +## $ truncate --size 2M seed.img +## $ mkfs.vfat -n cidata seed.img +## $ mcopy -oi seed.img user-data meta-data :: + +## create a new qcow image to boot, backed by your original image +$ qemu-img create -f qcow2 -b disk.img boot-disk.img + +## boot the image and login as 'ubuntu' with password 'passw0rd' +## note, passw0rd was set as password through the user-data above, +## there is no password set on these images. +$ kvm -m 256 \ + -net nic -net user,hostfwd=tcp::2222-:22 \ + -drive file=boot-disk.img,if=virtio \ + -drive file=seed.iso,if=virtio + +Note, that the instance-id provided ('iid-local01' above) is what is used to +determine if this is "first boot". So if you are making updates to user-data +you will also have to change that, or start the disk fresh. + + +Also, you can inject an /etc/network/interfaces file by providing the content +for that file in the 'network-interfaces' field of metadata. Example metadata: + instance-id: iid-abcdefg + network-interfaces: | + iface eth0 inet static + address 192.168.1.10 + network 192.168.1.0 + netmask 255.255.255.0 + broadcast 192.168.1.255 + gateway 192.168.1.254 + hostname: myhost + -- cgit v1.2.3 From 1e0e6c6ced37a9c111b0f1aa26d308a7a0bf0d79 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 17 Feb 2012 14:33:57 -0500 Subject: add doc for configdrive --- doc/configdrive/README | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 doc/configdrive/README (limited to 'doc') diff --git a/doc/configdrive/README b/doc/configdrive/README new file mode 100644 index 00000000..1ad7b0d0 --- /dev/null +++ b/doc/configdrive/README @@ -0,0 +1,73 @@ +The 'ConfigDrive' DataSource supports the OpenStack configdrive disk. +See doc/source/api_ext/ext_config_drive.rst in the nova source code for +more information on config drive. + +The following criteria are required to be identified by +DataSourceConfigDrive as a config drive: + * must be formated with vfat filesystem + * must be a un-partitioned block device (/dev/vdb, not /dev/vdb1) + * must contain one of the following files: + * etc/network/interfaces + * root/.ssh/authorized_keys + * meta.js + +By default, cloud-init does not consider this source to be a full-fledged +datasource. Instead, the default behavior is to assume it is really only +present to provide networking information. Cloud-init will copy off the +network information, apply it to the system, and then continue on. The +"full" datasource would then be found in the EC2 metadata service. + +== Content of config-drive == + * etc/network/interfaces + This file is laid down by nova in order to pass static networking + information to the guest. Cloud-init will copy it off of the config-drive + and into /etc/network/interfaces as soon as it can, and then attempt to + bring up all network interfaces. + + * root/.ssh/authorized_keys + This file is laid down by nova, and contains the keys that were + provided to it on instance creation (nova-boot --key ....) + + Cloud-init will copy those keys and put them into the configured user + ('ubuntu') .ssh/authorized_keys. + + * meta.js + meta.js is populated on the config-drive in response to the user passing + "meta flags" (nova boot --meta key=value ...). It is expected to be json + formated. + +== Configuration == +Cloud-init's behavior can be modified by keys found in the meta.js file in +the following ways: + * dsmode: + values: local, net, pass + default: pass + + This is what indicates if configdrive is a final data source or not. + By default it is 'pass', meaning this datasource should not be read. + Set it to 'local' or 'net' to stop cloud-init from continuing on to + search for other data sources after network config. + + The difference between 'local' and 'net' is that local will not require + networking to be up before user-data actions (or boothooks) are run. + + * instance-id: + default: iid-dsconfigdrive + This is utilized as the metadata's instance-id. It should generally + be unique, as it is what is used to determine "is this a new instance". + + * public-keys: + default: None + if present, these keys will be used as the public keys for the + instance. This value overrides the content in authorized_keys. + Note: it is likely preferable to provide keys via user-data + + * user-data: + default: None + This provides cloud-init user-data. See other documentation for what + all can be present here. + +-- +[1] https://github.com/openstack/nova/blob/master/doc/source/api_ext/ext_config_drive.rst for more if + + -- cgit v1.2.3 From 316f9ee4bfb27375ae92027664a59b94922f11ec Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 17 Feb 2012 16:58:02 -0500 Subject: more documentation on configdrive --- doc/configdrive/README | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'doc') diff --git a/doc/configdrive/README b/doc/configdrive/README index 1ad7b0d0..ed9033c9 100644 --- a/doc/configdrive/README +++ b/doc/configdrive/README @@ -67,6 +67,51 @@ the following ways: This provides cloud-init user-data. See other documentation for what all can be present here. +== Example == +Here is an example using the nova client (python-novaclien) + +Assuming the following variables set up: + * img_id : set to the nova image id (uuid from image-list) + * flav_id : set to numeric flavor_id (nova flavor-list) + * keyname : set to name of key for this instance (nova keypair-list) + +$ cat my-user-data +#!/bin/sh +echo ==== USER_DATA FROM EC2 MD ==== | tee /ud.log + +$ ud_value=$(sed 's,EC2 MD,META KEY,') + +## Now, 'ud_value' has same content of my-user-data file, but +## with the string "USER_DATA FROM META KEY" + +## launch an instance with dsmode=pass +## This will really not use the configdrive for anything as the mode +## for the datasource is 'pass', meaning it will still expect some +## other data source (DataSourceEc2). + +$ nova boot --image=$img_id --config-drive=1 --flavor=$flav_id \ + --key_name=$keyname \ + --user_data=my-user-data \ + "--meta=instance-id=iid-001 \ + "--meta=user-data=${ud_keyval}" \ + "--meta=dsmode=pass" cfgdrive-dsmode-pass + +$ euca-get-console-output i-0000001 | grep USER_DATA +echo ==== USER_DATA FROM EC2 MD ==== | tee /ud.log + +## Now, launch an instance with dsmode=local +## This time, the only metadata and userdata available to cloud-init +## are on the config-drive +$ nova boot --image=$img_id --config-drive=1 --flavor=$flav_id \ + --key_name=$keyname \ + --user_data=my-user-data \ + "--meta=instance-id=iid-001 \ + "--meta=user-data=${ud_keyval}" \ + "--meta=dsmode=local" cfgdrive-dsmode-local + +$ euca-get-console-output i-0000002 | grep USER_DATA +echo ==== USER_DATA FROM META KEY ==== | tee /ud.log + -- [1] https://github.com/openstack/nova/blob/master/doc/source/api_ext/ext_config_drive.rst for more if -- cgit v1.2.3