summaryrefslogtreecommitdiff
path: root/tests/cloud_tests/images
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cloud_tests/images')
-rw-r--r--tests/cloud_tests/images/__init__.py10
-rw-r--r--tests/cloud_tests/images/base.py56
-rw-r--r--tests/cloud_tests/images/lxd.py194
-rw-r--r--tests/cloud_tests/images/nocloudkvm.py90
4 files changed, 0 insertions, 350 deletions
diff --git a/tests/cloud_tests/images/__init__.py b/tests/cloud_tests/images/__init__.py
deleted file mode 100644
index 106c59f3..00000000
--- a/tests/cloud_tests/images/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Main init."""
-
-
-def get_image(platform, config):
- """Get image from platform object using os_name."""
- return platform.get_image(config)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/images/base.py b/tests/cloud_tests/images/base.py
deleted file mode 100644
index d503108a..00000000
--- a/tests/cloud_tests/images/base.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base class for images."""
-
-from ..util import TargetBase
-
-
-class Image(TargetBase):
- """Base class for images."""
-
- platform_name = None
-
- def __init__(self, platform, config):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- """
- self.platform = platform
- self.config = config
-
- def __str__(self):
- """A brief description of the image."""
- return '-'.join((self.properties['os'], self.properties['release']))
-
- @property
- def properties(self):
- """{} containing: 'arch', 'os', 'version', 'release'."""
- raise NotImplementedError
-
- @property
- def features(self):
- """Feature flags supported by this image.
-
- @return_value: list of feature names
- """
- return [k for k, v in self.config.get('features', {}).items() if v]
-
- @property
- def setup_overrides(self):
- """Setup options that need to be overridden for the image.
-
- @return_value: dictionary to update args with
- """
- # NOTE: more sophisticated options may be requied at some point
- return self.config.get('setup_overrides', {})
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- raise NotImplementedError
-
- def destroy(self):
- """Clean up data associated with image."""
- pass
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/images/lxd.py b/tests/cloud_tests/images/lxd.py
deleted file mode 100644
index 5caeba41..00000000
--- a/tests/cloud_tests/images/lxd.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""LXD Image Base Class."""
-
-import os
-import shutil
-import tempfile
-
-from cloudinit import util as c_util
-from tests.cloud_tests.images import base
-from tests.cloud_tests.snapshots import lxd as lxd_snapshot
-from tests.cloud_tests import util
-
-
-class LXDImage(base.Image):
- """LXD backed image."""
-
- platform_name = "lxd"
-
- def __init__(self, platform, config, pylxd_image):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- """
- self.modified = False
- self._img_instance = None
- self._pylxd_image = None
- self.pylxd_image = pylxd_image
- super(LXDImage, self).__init__(platform, config)
-
- @property
- def pylxd_image(self):
- """Property function."""
- if self._pylxd_image:
- self._pylxd_image.sync()
- return self._pylxd_image
-
- @pylxd_image.setter
- def pylxd_image(self, pylxd_image):
- if self._img_instance:
- self._instance.destroy()
- self._img_instance = None
- if (self._pylxd_image and
- (self._pylxd_image is not pylxd_image) and
- (not self.config.get('cache_base_image') or self.modified)):
- self._pylxd_image.delete(wait=True)
- self.modified = False
- self._pylxd_image = pylxd_image
-
- @property
- def _instance(self):
- """Internal use only, returns a instance
-
- This starts an lxc instance from the image, so it is "dirty".
- Better would be some way to modify this "at rest".
- lxc-pstart would be an option."""
- if not self._img_instance:
- self._img_instance = self.platform.launch_container(
- self.properties, self.config, self.features,
- use_desc='image-modification', image_desc=str(self),
- image=self.pylxd_image.fingerprint)
- self._img_instance.start()
- return self._img_instance
-
- @property
- def properties(self):
- """{} containing: 'arch', 'os', 'version', 'release'."""
- properties = self.pylxd_image.properties
- return {
- 'arch': properties.get('architecture'),
- 'os': properties.get('os'),
- 'version': properties.get('version'),
- 'release': properties.get('release'),
- }
-
- def export_image(self, output_dir):
- """Export image from lxd image store to (split) tarball on disk.
-
- @param output_dir: dir to store tarballs in
- @return_value: tuple of path to metadata tarball and rootfs tarball
- """
- # pylxd's image export feature doesn't do split exports, so use cmdline
- c_util.subp(['lxc', 'image', 'export', self.pylxd_image.fingerprint,
- output_dir], capture=True)
- tarballs = [p for p in os.listdir(output_dir) if p.endswith('tar.xz')]
- metadata = os.path.join(
- output_dir, next(p for p in tarballs if p.startswith('meta-')))
- rootfs = os.path.join(
- output_dir, next(p for p in tarballs if not p.startswith('meta-')))
- return (metadata, rootfs)
-
- def import_image(self, metadata, rootfs):
- """Import image to lxd image store from (split) tarball on disk.
-
- Note, this will replace and delete the current pylxd_image
-
- @param metadata: metadata tarball
- @param rootfs: rootfs tarball
- @return_value: imported image fingerprint
- """
- alias = util.gen_instance_name(
- image_desc=str(self), use_desc='update-metadata')
- c_util.subp(['lxc', 'image', 'import', metadata, rootfs,
- '--alias', alias], capture=True)
- self.pylxd_image = self.platform.query_image_by_alias(alias)
- return self.pylxd_image.fingerprint
-
- def update_templates(self, template_config, template_data):
- """Update the image's template configuration.
-
- Note, this will replace and delete the current pylxd_image
-
- @param template_config: config overrides for template metadata
- @param template_data: template data to place into templates/
- """
- # set up tmp files
- export_dir = tempfile.mkdtemp(prefix='cloud_test_util_')
- extract_dir = tempfile.mkdtemp(prefix='cloud_test_util_')
- new_metadata = os.path.join(export_dir, 'new-meta.tar.xz')
- metadata_yaml = os.path.join(extract_dir, 'metadata.yaml')
- template_dir = os.path.join(extract_dir, 'templates')
-
- try:
- # extract old data
- (metadata, rootfs) = self.export_image(export_dir)
- shutil.unpack_archive(metadata, extract_dir)
-
- # update metadata
- metadata = c_util.read_conf(metadata_yaml)
- templates = metadata.get('templates', {})
- templates.update(template_config)
- metadata['templates'] = templates
- util.yaml_dump(metadata, metadata_yaml)
-
- # write out template files
- for name, content in template_data.items():
- path = os.path.join(template_dir, name)
- c_util.write_file(path, content)
-
- # store new data, mark new image as modified
- util.flat_tar(new_metadata, extract_dir)
- self.import_image(new_metadata, rootfs)
- self.modified = True
-
- finally:
- # remove tmpfiles
- shutil.rmtree(export_dir)
- shutil.rmtree(extract_dir)
-
- def _execute(self, *args, **kwargs):
- """Execute command in image, modifying image."""
- return self._instance._execute(*args, **kwargs)
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'."""
- return self._instance.push_file(local_path, remote_path)
-
- def run_script(self, *args, **kwargs):
- """Run script in image, modifying image.
-
- @return_value: script output
- """
- return self._instance.run_script(*args, **kwargs)
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- # get empty user data to pass in to instance
- # if overrides for user data provided, use them
- empty_userdata = util.update_user_data(
- {}, self.config.get('user_data_overrides', {}))
- conf = {'user.user-data': empty_userdata}
- # clone current instance
- instance = self.platform.launch_container(
- self.properties, self.config, self.features,
- container=self._instance.name, image_desc=str(self),
- use_desc='snapshot', container_config=conf)
- # wait for cloud-init before boot_clean_script is run to ensure
- # /var/lib/cloud is removed cleanly
- instance.start(wait=True, wait_for_cloud_init=True)
- if self.config.get('boot_clean_script'):
- instance.run_script(self.config.get('boot_clean_script'))
- # freeze current instance and return snapshot
- instance.freeze()
- return lxd_snapshot.LXDSnapshot(
- self.platform, self.properties, self.config,
- self.features, instance)
-
- def destroy(self):
- """Clean up data associated with image."""
- self.pylxd_image = None
- super(LXDImage, self).destroy()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/images/nocloudkvm.py b/tests/cloud_tests/images/nocloudkvm.py
deleted file mode 100644
index 8678b07f..00000000
--- a/tests/cloud_tests/images/nocloudkvm.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""NoCloud KVM Image Base Class."""
-
-from cloudinit import util as c_util
-
-import os
-import shutil
-import tempfile
-
-from tests.cloud_tests.images import base
-from tests.cloud_tests.snapshots import nocloudkvm as nocloud_kvm_snapshot
-
-
-class NoCloudKVMImage(base.Image):
- """NoCloud KVM backed image."""
-
- platform_name = "nocloud-kvm"
-
- def __init__(self, platform, config, orig_img_path):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- @param img_path: path to the image
- """
- self.modified = False
- self._workd = tempfile.mkdtemp(prefix='NoCloudKVMImage')
- self._orig_img_path = orig_img_path
- self._img_path = os.path.join(self._workd,
- os.path.basename(self._orig_img_path))
-
- c_util.subp(['qemu-img', 'create', '-f', 'qcow2',
- '-b', orig_img_path, self._img_path])
-
- super(NoCloudKVMImage, self).__init__(platform, config)
-
- @property
- def properties(self):
- """Dictionary containing: 'arch', 'os', 'version', 'release'."""
- return {
- 'arch': self.config['arch'],
- 'os': self.config['family'],
- 'release': self.config['release'],
- 'version': self.config['version'],
- }
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command in image, modifying image."""
- return self.mount_image_callback(command, stdin=stdin, env=env)
-
- def mount_image_callback(self, command, stdin=None, env=None):
- """Run mount-image-callback."""
-
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- mic_chroot = ['sudo', 'mount-image-callback', '--system-mounts',
- '--system-resolvconf', self._img_path,
- '--', 'chroot', '_MOUNTPOINT_']
- try:
- out, err = c_util.subp(mic_chroot + env_args + list(command),
- data=stdin, decode=False)
- return (out, err, 0)
- except c_util.ProcessExecutionError as e:
- return (e.stdout, e.stderr, e.exit_code)
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- if not self._img_path:
- raise RuntimeError()
-
- return nocloud_kvm_snapshot.NoCloudKVMSnapshot(
- self.platform, self.properties, self.config,
- self.features, self._img_path)
-
- def destroy(self):
- """Unset path to signal image is no longer used.
-
- The removal of the images and all other items is handled by the
- framework. In some cases we want to keep the images, so let the
- framework decide whether to keep or destroy everything.
- """
- self._img_path = None
- shutil.rmtree(self._workd)
-
- super(NoCloudKVMImage, self).destroy()
-
-# vi: ts=4 expandtab