diff options
-rw-r--r-- | morphlib/app.py | 3 | ||||
-rw-r--r-- | morphlib/exts/initramfs.write.help | 6 | ||||
-rwxr-xr-x | morphlib/exts/openstack.check | 15 | ||||
-rwxr-xr-x | morphlib/exts/openstack.write | 35 | ||||
-rw-r--r-- | morphlib/exts/openstack.write.help | 37 | ||||
-rwxr-xr-x | morphlib/exts/rawdisk.write | 12 | ||||
-rw-r--r-- | morphlib/exts/rawdisk.write.help | 43 | ||||
-rwxr-xr-x | morphlib/exts/ssh-rsync.write | 10 | ||||
-rw-r--r-- | morphlib/exts/ssh-rsync.write.help | 36 | ||||
-rw-r--r-- | morphlib/plugins/deploy_plugin.py | 31 | ||||
-rw-r--r-- | morphlib/util.py | 6 |
11 files changed, 167 insertions, 67 deletions
diff --git a/morphlib/app.py b/morphlib/app.py index 6964be56..eb0ff3b7 100644 --- a/morphlib/app.py +++ b/morphlib/app.py @@ -17,6 +17,7 @@ import cliapp import logging import os +import pipes import sys import time import urlparse @@ -365,7 +366,7 @@ class Morph(cliapp.Application): if isinstance(command, list): for i in xrange(0, len(command)): command[i] = str(command[i]) - commands = [' '.join(command) for command in commands] + commands = ' '.join(map(pipes.quote, command)) self.status(msg='# %(cmdline)s', cmdline=' | '.join(commands), diff --git a/morphlib/exts/initramfs.write.help b/morphlib/exts/initramfs.write.help index 29a9d266..a4a89f9d 100644 --- a/morphlib/exts/initramfs.write.help +++ b/morphlib/exts/initramfs.write.help @@ -1,4 +1,5 @@ help: | + Create an initramfs for a system by taking an existing system and converting it to the appropriate format. @@ -33,3 +34,8 @@ help: | initramfs: type: initramfs location: boot/initramfs.gz + + Parameters: + + * location: the path where the initramfs will be installed (e.g. + `boot/initramfs.gz`) in the above example diff --git a/morphlib/exts/openstack.check b/morphlib/exts/openstack.check index edc37cc1..3850d481 100755 --- a/morphlib/exts/openstack.check +++ b/morphlib/exts/openstack.check @@ -77,9 +77,16 @@ class OpenStackCheckExtension(morphlib.writeexts.WriteExtension): '--os-password', password, '--os-auth-url', auth_url, 'image-list'] - try: - cliapp.runcmd(cmdline) - except cliapp.AppException: - raise cliapp.AppException('Wrong OpenStack credentals.') + + exit, out, err = cliapp.runcmd_unchecked(cmdline) + + if exit != 0: + if err.startswith('The request you have made requires ' + 'authentication. (HTTP 401)'): + raise cliapp.AppException('Invalid OpenStack credentials.') + else: + raise cliapp.AppException( + 'Failed to connect to OpenStack instance at %s: %s' % + (auth_url, err)) OpenStackCheckExtension().run() diff --git a/morphlib/exts/openstack.write b/morphlib/exts/openstack.write index b1941d3c..d29d2661 100755 --- a/morphlib/exts/openstack.write +++ b/morphlib/exts/openstack.write @@ -28,40 +28,12 @@ import morphlib.writeexts class OpenStackWriteExtension(morphlib.writeexts.WriteExtension): - '''Configure a raw disk image into an OpenStack host. - - The raw disk image is created during Morph's deployment and the - image is deployed in OpenStack using python-glanceclient. - - The location command line argument is the authentification url - of the OpenStack server using the following syntax: - - http://HOST:PORT/VERSION - - where - - * HOST is the host running OpenStack - * PORT is the port which is using OpenStack for authentifications. - * VERSION is the authentification version of OpenStack (Only v2.0 - supported) - - This extension needs in the environment the following variables: - - * OPENSTACK_USER is the username to use in the deployment. - * OPENSTACK_TENANT is the project name to use in the deployment. - * OPENSTACK_IMAGENAME is the name of the image to create. - * OPENSTACK_PASSWORD is the password of the user. - - - The extension will connect to OpenStack using python-glanceclient - to configure a raw image. - - ''' + '''See openstack.write.help for documentation''' def process_args(self, args): if len(args) != 2: raise cliapp.AppException('Wrong number of command line args') - + temp_root, location = args os_params = self.get_openstack_parameters() @@ -69,7 +41,7 @@ class OpenStackWriteExtension(morphlib.writeexts.WriteExtension): fd, raw_disk = tempfile.mkstemp() os.close(fd) self.create_local_system(temp_root, raw_disk) - self.status(msg='Temporary disk image has been created at %s' + self.status(msg='Temporary disk image has been created at %s' % raw_disk) self.set_extlinux_root_to_virtio(raw_disk) @@ -120,4 +92,3 @@ class OpenStackWriteExtension(morphlib.writeexts.WriteExtension): self.status(msg='Image configured.') OpenStackWriteExtension().run() - diff --git a/morphlib/exts/openstack.write.help b/morphlib/exts/openstack.write.help new file mode 100644 index 00000000..75ad9f0c --- /dev/null +++ b/morphlib/exts/openstack.write.help @@ -0,0 +1,37 @@ +help: | + + Deploy a Baserock system as a *new* OpenStack virtual machine. + (Use the `ssh-rsync` write extension to deploy upgrades to an *existing* + VM) + + Deploys the system to the OpenStack host using python-glanceclient. + + Parameters: + + * location: the authentication url of the OpenStack server using the + following syntax: + + http://HOST:PORT/VERSION + + where + + * HOST is the host running OpenStack + * PORT is the port which is using OpenStack for authentications. + * VERSION is the authentication version of OpenStack (Only v2.0 + supported) + + * OPENSTACK_USER=username: the username to use in the `--os-username` + argument to `glance`. + + * OPENSTACK_TENANT=tenant: the project name to use in the + `--os-tenant-name` argument to `glance`. + + * OPENSTACK_IMAGENAME=imagename: the name of the image to use in the + `--name` argument to `glance`. + + * OPENSTACK_PASSWORD=password: the password of the OpenStack user. (We + recommend passing this on the command-line, rather than setting an + environment variable or storing it in a cluster cluster definition file.) + + (See `morph help deploy` for details of how to pass parameters to write + extensions) diff --git a/morphlib/exts/rawdisk.write b/morphlib/exts/rawdisk.write index b17f8aa7..d91a4d5f 100755 --- a/morphlib/exts/rawdisk.write +++ b/morphlib/exts/rawdisk.write @@ -29,19 +29,12 @@ import morphlib.writeexts class RawDiskWriteExtension(morphlib.writeexts.WriteExtension): - '''Create a raw disk image during Morph's deployment. - - If the image already exists, it is upgraded. - - The location command line argument is the pathname of the disk image - to be created/upgraded. - - ''' + '''See rawdisk.write.help for documentation''' def process_args(self, args): if len(args) != 2: raise cliapp.AppException('Wrong number of command line args') - + temp_root, location = args upgrade = self.get_environment_boolean('UPGRADE') @@ -114,4 +107,3 @@ class RawDiskWriteExtension(morphlib.writeexts.WriteExtension): RawDiskWriteExtension().run() - diff --git a/morphlib/exts/rawdisk.write.help b/morphlib/exts/rawdisk.write.help index 298d441c..81f35024 100644 --- a/morphlib/exts/rawdisk.write.help +++ b/morphlib/exts/rawdisk.write.help @@ -1,11 +1,38 @@ help: | - Create a raw disk image during Morph's deployment. - - If the image already exists, it is upgraded. - The `location` argument is a pathname to the image to be - created or upgraded. + Write a system produced by Morph to a physical disk, or to a file that can + be used as a virtual disk. The target will be formatted as a single Btrfs + partition, with the system image written to a subvolume in /systems, and + other subvolumes created for /home, /opt, /root, /srv and /var. - The INITRAMFS_PATH option can be used to specify the location of an - initramfs for syslinux to tell Linux to use, rather than booting - the rootfs directly. + When written to a physical drive, the drive can be used as the boot device + for a 'real' machine. + + When written to a file, the file can be used independently of `morph` to + create virtual machines with KVM / libvirt, OpenStack or, after converting + it to VDI format, VirtualBox. + + `morph deploy` will fail if the file specified by `location` already + exists. + + If used in `morph upgrade`, the rootfs produced by 'morph build' is added + to the existing raw disk image or device as an additional btrfs sub-volume. + `morph upgrade` will fail if the file specified by `location` does not + exist, or is not a Baserock raw disk image. (Most users are unlikely to + need or use this functionality: it is useful mainly for developers working + on the Baserock tools.) + + Parameters: + + * location: the pathname of the disk image to be created/upgraded, or the + path to the physical device. + + * VERSION_LABEL=label - should contain only alpha-numeric + characters and the '-' (hyphen) character. Mandatory if being used with + `morph update` + + * INITRAMFS_PATH=path: the location of an initramfs for the bootloader to + tell Linux to use, rather than booting the rootfs directly. + + (See `morph help deploy` for details of how to pass parameters to write + extensions) diff --git a/morphlib/exts/ssh-rsync.write b/morphlib/exts/ssh-rsync.write index 2d7258ba..c4577026 100755 --- a/morphlib/exts/ssh-rsync.write +++ b/morphlib/exts/ssh-rsync.write @@ -37,14 +37,8 @@ def ssh_runcmd_ignore_failure(location, command, **kwargs): class SshRsyncWriteExtension(morphlib.writeexts.WriteExtension): - '''Upgrade a running baserock system with ssh and rsync. - - It assumes the system is baserock-based and has a btrfs partition. - - The location command line argument is the 'user@hostname' string - that will be passed to ssh and rsync - - ''' + '''See ssh-rsync.write.help for documentation''' + def find_root_disk(self, location): '''Read /proc/mounts on location to find which device contains "/"''' diff --git a/morphlib/exts/ssh-rsync.write.help b/morphlib/exts/ssh-rsync.write.help new file mode 100644 index 00000000..d03508c0 --- /dev/null +++ b/morphlib/exts/ssh-rsync.write.help @@ -0,0 +1,36 @@ +help: | + + Upgrade a Baserock system which is already deployed: + - as a KVM/LibVirt, OpenStack or vbox-ssh virtual machine; + - on a Jetson board. + + Copies a binary delta over to the target system and arranges for it + to be bootable. + + The recommended way to use this extension is by calling `morph upgrade`. + Using `morph deploy --upgrade` is deprecated. + + The upgrade will fail if: + - no VM is deployed and running at `location`; + - the target system is not a Baserock system; + - the target's filesystem and its layout are not compatible with that + created by `morph deploy`." + + See also the 'Upgrading a Baserock installation' section of the 'Using + Baserock` page at wiki.baserock.org + http://wiki.baserock.org/devel-with/#index8h2 + + Parameters: + + * location: the 'user@hostname' string that will be used by ssh and rsync. + 'user' will always be `root` and `hostname` the hostname or address of + the system being upgraded. + + * VERSION_LABEL=label - **(MANDATORY)** should contain only alpha-numeric + characters and the '-' (hyphen) character. + + * AUTOSTART=<VALUE>` - boolean. If it is set, the VM will be started when + it has been deployed. + + (See `morph help deploy` for details of how to pass parameters to write + extensions) diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py index 87e129e5..0121c110 100644 --- a/morphlib/plugins/deploy_plugin.py +++ b/morphlib/plugins/deploy_plugin.py @@ -124,7 +124,7 @@ class DeployPlugin(cliapp.Plugin): Each system defined in a cluster morphology can be deployed in multiple ways (`type` in a cluster morphology). Morph provides - five types of deployment: + the following types of deployment: * `tar` where Morph builds a tar archive of the root file system. @@ -144,6 +144,35 @@ class DeployPlugin(cliapp.Plugin): * `nfsboot` where Morph creates a system to be booted over a network. + * `ssh-rsync` where Morph copies a binary delta over to the target + system and arranges for it to be bootable. This requires + `system-version-manager` from the tbdiff chunk + + * `initramfs`, where Morph turns the system into an initramfs image, + suitable for being used as the early userland environment for a + system to be able to locate more complicated storage for its root + file-system, or on its own for diskless deployments. + + There are additional extensions that currently live in the Baserock + definitions repo (baserock:baserock/definitions). These include: + + * `image-package` where Morph creates a tarball that includes scripts + that can be used to make disk images outside of a Baserock + environment. The example in definitions.git will create scripts for + generating disk images and installing to existing disks. + + * `sdk` where Morph generates something resembing a BitBake SDK, which + provides a toolchain for building software to target a system built + by Baserock, from outside of a Baserock environment. This creates a + self-extracting shell archive which you pass a directory to extract + to, and inside that has a shell snippet called + environment-setup-$TARGET which can be used to set environment + variables to use the toolchain. + + * `pxeboot` where Morph temporarily network-boots the system you are + deploying, so it can install a more permanent system onto local + storage. + In addition to the deployment type, the user must also give a value for `location`. Its syntax depends on the deployment types. The deployment types provided by Morph use the diff --git a/morphlib/util.py b/morphlib/util.py index 9b284d6e..e7a8a50e 100644 --- a/morphlib/util.py +++ b/morphlib/util.py @@ -15,13 +15,12 @@ import contextlib import itertools -import logging import os +import pipes import re import subprocess import textwrap -import cliapp import fs.osfs import morphlib @@ -637,7 +636,8 @@ def error_message_for_containerised_commandline( # rather than just dumping it in the error message, but that is better than # nothing. + argv_string = ' '.join(map(pipes.quote, argv)) return 'Command failed: %s:\n' \ 'Containerisation settings: %s\n' \ 'Error output:\n%s' \ - % (' '.join(argv), container_kwargs, err) + % (argv_string, container_kwargs, err) |