From 0092e1c2c2f97a25baabac002b496eccebba6394 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Sun, 5 Jan 2014 15:57:11 +0100 Subject: [PATCH] Don't instantiate tasks In practice they are just typed functions with attributes, having a reference to an object is just confusing. So: Task.run() is now a classmethod --- base/task.py | 13 +++++--- base/tasklist.py | 9 +++-- common/tasks/apt.py | 24 +++++++++----- common/tasks/boot.py | 18 ++++++---- common/tasks/bootstrap.py | 6 ++-- common/tasks/cleanup.py | 9 +++-- common/tasks/development.py | 3 +- common/tasks/filesystem.py | 33 ++++++++++++------- common/tasks/host.py | 6 ++-- common/tasks/initd.py | 15 ++++++--- common/tasks/locale.py | 9 +++-- common/tasks/loopback.py | 6 ++-- common/tasks/network.py | 9 +++-- common/tasks/packages.py | 6 ++-- common/tasks/partitioning.py | 9 +++-- common/tasks/security.py | 9 +++-- common/tasks/volume.py | 9 +++-- common/tasks/workspace.py | 6 ++-- plugins/admin_user/tasks.py | 15 ++++++--- plugins/build_metadata/tasks.py | 3 +- plugins/cloud_init/tasks.py | 15 ++++++--- plugins/image_commands/tasks.py | 3 +- plugins/minimize_size/tasks.py | 6 ++-- plugins/opennebula/tasks.py | 3 +- plugins/prebootstrapped/tasks.py | 12 ++++--- plugins/root_password/tasks.py | 3 +- plugins/unattended_upgrades/tasks.py | 6 ++-- plugins/vagrant/tasks.py | 19 +++++++---- providers/ec2/tasks/ami.py | 17 ++++++---- providers/ec2/tasks/boot.py | 3 +- providers/ec2/tasks/connection.py | 11 ++++--- providers/ec2/tasks/ebs.py | 9 +++-- providers/ec2/tasks/filesystem.py | 3 +- providers/ec2/tasks/host.py | 6 ++-- providers/ec2/tasks/initd.py | 3 +- providers/ec2/tasks/network.py | 9 +++-- providers/ec2/tasks/packages.py | 3 +- providers/virtualbox/tasks/guest_additions.py | 9 +++-- providers/virtualbox/tasks/packages.py | 3 +- 39 files changed, 237 insertions(+), 123 deletions(-) diff --git a/base/task.py b/base/task.py index 44abba4..e980477 100644 --- a/base/task.py +++ b/base/task.py @@ -5,8 +5,13 @@ class Task(object): predecessors = [] successors = [] - def __str__(self): - return '{module}.{task}'.format(module=self.__module__, task=self.__class__.__name__) + class __metaclass__(type): + def __repr__(cls): + return '{module}.{task}'.format(module=cls.__module__, task=cls.__name__) - def __repr__(self): - return self.__str__() + def __str__(cls): + return repr(cls) + + @classmethod + def run(cls, info): + pass diff --git a/base/tasklist.py b/base/tasklist.py index a07ee60..2803d7a 100644 --- a/base/tasklist.py +++ b/base/tasklist.py @@ -18,17 +18,16 @@ class TaskList(object): def run(self, info={}, dry_run=False): task_list = self.create_list() - log.debug('Tasklist:\n\t{list}'.format(list='\n\t'.join(repr(task) for task in task_list))) + log.debug('Tasklist:\n\t{list}'.format(list='\n\t'.join(map(repr, task_list)))) - for task_type in task_list: - task = task_type() + for task in task_list: if hasattr(task, 'description'): log.info(task.description) else: log.info('Running {task}'.format(task=task)) if not dry_run: task.run(info) - self.tasks_completed.append(task_type) + self.tasks_completed.append(task) def create_list(self): from common.phases import order @@ -47,7 +46,7 @@ class TaskList(object): for component in components: if len(component) > 1: cycles_found += 1 - log.debug('Cycle: {list}\n'.format(list=', '.join(repr(task) for task in component))) + log.debug('Cycle: {list}\n'.format(list=', '.join(map(repr, component)))) if cycles_found > 0: msg = ('{0} cycles were found in the tasklist, ' 'consult the logfile for more information.'.format(cycles_found)) diff --git a/common/tasks/apt.py b/common/tasks/apt.py index 72baba3..d654f0d 100644 --- a/common/tasks/apt.py +++ b/common/tasks/apt.py @@ -9,7 +9,8 @@ class AddDefaultSources(Task): description = 'Adding default release sources' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): if info.source_lists.target_exists('{system.release}'): import logging msg = ('{system.release} target already exists').format(**info.manifest_vars) @@ -25,7 +26,8 @@ class WriteSources(Task): description = 'Writing aptitude sources to disk' phase = phases.package_installation - def run(self, info): + @classmethod + def run(cls, info): for name, sources in info.source_lists.sources.iteritems(): if name == 'main': list_path = os.path.join(info.root, 'etc/apt/sources.list') @@ -40,7 +42,8 @@ class DisableDaemonAutostart(Task): description = 'Disabling daemon autostart' phase = phases.package_installation - def run(self, info): + @classmethod + def run(cls, info): rc_policy_path = os.path.join(info.root, 'usr/sbin/policy-rc.d') with open(rc_policy_path, 'w') as rc_policy: rc_policy.write(('#!/bin/sh\n' @@ -57,7 +60,8 @@ class AptUpdate(Task): phase = phases.package_installation predecessors = [locale.GenerateLocale, WriteSources] - def run(self, info): + @classmethod + def run(cls, info): log_check_call(['/usr/sbin/chroot', info.root, '/usr/bin/apt-get', 'update']) @@ -67,7 +71,8 @@ class AptUpgrade(Task): phase = phases.package_installation predecessors = [AptUpdate, DisableDaemonAutostart] - def run(self, info): + @classmethod + def run(cls, info): from subprocess import CalledProcessError try: log_check_call(['/usr/sbin/chroot', info.root, @@ -93,7 +98,8 @@ class PurgeUnusedPackages(Task): description = 'Removing unused packages' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): log_check_call(['/usr/sbin/chroot', info.root, '/usr/bin/apt-get', 'autoremove', '--purge']) @@ -103,7 +109,8 @@ class AptClean(Task): description = 'Clearing the aptitude cache' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): log_check_call(['/usr/sbin/chroot', info.root, '/usr/bin/apt-get', 'clean']) @@ -117,5 +124,6 @@ class EnableDaemonAutostart(Task): description = 'Re-enabling daemon autostart after installation' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): os.remove(os.path.join(info.root, 'usr/sbin/policy-rc.d')) diff --git a/common/tasks/boot.py b/common/tasks/boot.py index 7e666f8..7f814c3 100644 --- a/common/tasks/boot.py +++ b/common/tasks/boot.py @@ -8,7 +8,8 @@ class BlackListModules(Task): description = 'Blacklisting kernel modules' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): blacklist_path = os.path.join(info.root, 'etc/modprobe.d/blacklist.conf') with open(blacklist_path, 'a') as blacklist: blacklist.write(('# disable pc speaker\n' @@ -19,7 +20,8 @@ class DisableGetTTYs(Task): description = 'Disabling getty processes' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import sed_i inittab_path = os.path.join(info.root, 'etc/inittab') tty1 = '1:2345:respawn:/sbin/getty 38400 tty1' @@ -35,7 +37,8 @@ class AddGrubPackage(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('grub-pc') @@ -44,7 +47,8 @@ class InstallGrub(Task): phase = phases.system_modification predecessors = [apt.AptUpgrade] - def run(self, info): + @classmethod + def run(cls, info): from common.fs.loopbackvolume import LoopbackVolume from common.tools import log_check_call @@ -107,7 +111,8 @@ class AddExtlinuxPackage(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('extlinux') @@ -116,7 +121,8 @@ class InstallExtLinux(Task): phase = phases.system_modification predecessors = [apt.AptUpgrade] - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call log_check_call(['/usr/sbin/chroot', info.root, '/usr/bin/extlinux', diff --git a/common/tasks/bootstrap.py b/common/tasks/bootstrap.py index c48c2e0..8cb8d31 100644 --- a/common/tasks/bootstrap.py +++ b/common/tasks/bootstrap.py @@ -21,7 +21,8 @@ class MakeTarball(Task): description = 'Creating bootstrap tarball' phase = phases.os_installation - def run(self, info): + @classmethod + def run(cls, info): from hashlib import sha1 import os.path executable, options, arguments = get_bootstrap_args(info) @@ -45,7 +46,8 @@ class Bootstrap(Task): phase = phases.os_installation predecessors = [MakeTarball] - def run(self, info): + @classmethod + def run(cls, info): executable, options, arguments = get_bootstrap_args(info) if hasattr(info, 'tarball'): options.extend(['--unpack-tarball=' + info.tarball]) diff --git a/common/tasks/cleanup.py b/common/tasks/cleanup.py index 5d9dacb..c6cc3c1 100644 --- a/common/tasks/cleanup.py +++ b/common/tasks/cleanup.py @@ -8,7 +8,8 @@ class ClearMOTD(Task): description = 'Clearing the MOTD' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): with open('/var/run/motd', 'w'): pass @@ -17,7 +18,8 @@ class ShredHostkeys(Task): description = 'Securely deleting ssh hostkeys' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): ssh_hostkeys = ['ssh_host_dsa_key', 'ssh_host_rsa_key'] if info.manifest.system['release'] != 'squeeze': @@ -34,7 +36,8 @@ class CleanTMP(Task): description = 'Removing temporary files' phase = phases.system_cleaning - def run(self, info): + @classmethod + def run(cls, info): tmp = os.path.join(info.root, 'tmp') for tmp_file in [os.path.join(tmp, f) for f in os.listdir(tmp)]: if os.path.isfile(tmp_file): diff --git a/common/tasks/development.py b/common/tasks/development.py index cf8a546..b71504d 100644 --- a/common/tasks/development.py +++ b/common/tasks/development.py @@ -7,6 +7,7 @@ class TriggerRollback(Task): description = 'Triggering a rollback by throwing an exception' - def run(self, info): + @classmethod + def run(cls, info): from common.exceptions import TaskError raise TaskError('Trigger rollback') diff --git a/common/tasks/filesystem.py b/common/tasks/filesystem.py index b072c39..8baf3bc 100644 --- a/common/tasks/filesystem.py +++ b/common/tasks/filesystem.py @@ -10,7 +10,8 @@ class Format(Task): description = 'Formatting the volume' phase = phases.volume_preparation - def run(self, info): + @classmethod + def run(cls, info): for partition in info.volume.partition_map.partitions: partition.format() @@ -20,7 +21,8 @@ class TuneVolumeFS(Task): phase = phases.volume_preparation predecessors = [Format] - def run(self, info): + @classmethod + def run(cls, info): import re # Disable the time based filesystem check for partition in info.volume.partition_map.partitions: @@ -33,7 +35,8 @@ class AddXFSProgs(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('xfsprogs') @@ -41,7 +44,8 @@ class CreateMountDir(Task): description = 'Creating mountpoint for the root partition' phase = phases.volume_mounting - def run(self, info): + @classmethod + def run(cls, info): import os info.root = os.path.join(info.workspace, 'root') os.makedirs(info.root) @@ -52,7 +56,8 @@ class MountRoot(Task): phase = phases.volume_mounting predecessors = [CreateMountDir] - def run(self, info): + @classmethod + def run(cls, info): info.volume.partition_map.root.mount(info.root) @@ -61,7 +66,8 @@ class CreateBootMountDir(Task): phase = phases.volume_mounting predecessors = [MountRoot] - def run(self, info): + @classmethod + def run(cls, info): import os.path os.makedirs(os.path.join(info.root, 'boot')) @@ -71,7 +77,8 @@ class MountBoot(Task): phase = phases.volume_mounting predecessors = [CreateBootMountDir] - def run(self, info): + @classmethod + def run(cls, info): p_map = info.volume.partition_map p_map.root.add_mount(p_map.boot, 'boot') @@ -81,7 +88,8 @@ class MountSpecials(Task): phase = phases.os_installation predecessors = [Bootstrap] - def run(self, info): + @classmethod + def run(cls, info): root = info.volume.partition_map.root root.add_mount('/dev', 'dev', ['--bind']) root.add_mount('none', 'proc', ['--types', 'proc']) @@ -94,7 +102,8 @@ class UnmountRoot(Task): phase = phases.volume_unmounting successors = [volume.Detach] - def run(self, info): + @classmethod + def run(cls, info): info.volume.partition_map.root.unmount() @@ -103,7 +112,8 @@ class DeleteMountDir(Task): phase = phases.volume_unmounting predecessors = [UnmountRoot] - def run(self, info): + @classmethod + def run(cls, info): import os os.rmdir(info.root) del info.root @@ -113,7 +123,8 @@ class FStab(Task): description = 'Adding partitions to the fstab' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import os.path p_map = info.volume.partition_map mount_points = [{'path': '/', diff --git a/common/tasks/host.py b/common/tasks/host.py index 792a27a..dfaf1cc 100644 --- a/common/tasks/host.py +++ b/common/tasks/host.py @@ -7,7 +7,8 @@ class HostDependencies(Task): description = 'Determining required host dependencies' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): info.host_dependencies.add('debootstrap') from common.fs.loopbackvolume import LoopbackVolume @@ -27,7 +28,8 @@ class CheckHostDependencies(Task): phase = phases.preparation predecessors = [HostDependencies] - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call from subprocess import CalledProcessError for package in info.host_dependencies: diff --git a/common/tasks/initd.py b/common/tasks/initd.py index 5a5da89..99842f6 100644 --- a/common/tasks/initd.py +++ b/common/tasks/initd.py @@ -10,7 +10,8 @@ class InstallInitScripts(Task): description = 'Installing startup scripts' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import stat rwxr_xr_x = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | @@ -31,7 +32,8 @@ class AddExpandRoot(Task): phase = phases.system_modification successors = [InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): init_scripts_dir = os.path.join(assets, 'init.d') info.initd['install']['expand-root'] = os.path.join(init_scripts_dir, 'expand-root') @@ -41,7 +43,8 @@ class AddSSHKeyGeneration(Task): phase = phases.system_modification successors = [InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): init_scripts_dir = os.path.join(assets, 'init.d') install = info.initd['install'] from subprocess import CalledProcessError @@ -63,7 +66,8 @@ class RemoveHWClock(Task): phase = phases.system_modification successors = [InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): info.initd['disable'].append('hwclock.sh') if info.manifest.system['release'] == 'squeeze': info.initd['disable'].append('hwclockfirst.sh') @@ -74,7 +78,8 @@ class AdjustExpandRootScript(Task): phase = phases.system_modification predecessors = [InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): if 'expand-root' not in info.initd['install']: raise TaskError('The expand-root script was not installed') diff --git a/common/tasks/locale.py b/common/tasks/locale.py index 5456a24..7eb15e4 100644 --- a/common/tasks/locale.py +++ b/common/tasks/locale.py @@ -7,7 +7,8 @@ class LocaleBootstrapPackage(Task): description = 'Adding locale package to bootstrap installation' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): # We could bootstrap without locales, but things just suck without them # eg. error messages when running apt info.include_packages.add('locales') @@ -17,7 +18,8 @@ class GenerateLocale(Task): description = 'Generating the selected locale' phase = phases.package_installation - def run(self, info): + @classmethod + def run(cls, info): from common.tools import sed_i from common.tools import log_check_call locale_gen = os.path.join(info.root, 'etc/locale.gen') @@ -38,7 +40,8 @@ class SetTimezone(Task): description = 'Setting the selected timezone' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from shutil import copy tz_path = os.path.join(info.root, 'etc/timezone') timezone = info.manifest.system['timezone'] diff --git a/common/tasks/loopback.py b/common/tasks/loopback.py index 7af87b9..9420429 100644 --- a/common/tasks/loopback.py +++ b/common/tasks/loopback.py @@ -8,7 +8,8 @@ class Create(Task): phase = phases.volume_creation successors = [volume.Attach] - def run(self, info): + @classmethod + def run(cls, info): import os.path image_path = os.path.join(info.workspace, 'volume.{ext}'.format(ext=info.volume.extension)) info.volume.create(image_path) @@ -18,7 +19,8 @@ class MoveImage(Task): description = 'Moving volume image' phase = phases.image_registration - def run(self, info): + @classmethod + def run(cls, info): image_name = info.manifest.image['name'].format(**info.manifest_vars) filename = '{image_name}.{ext}'.format(image_name=image_name, ext=info.volume.extension) diff --git a/common/tasks/network.py b/common/tasks/network.py index e3129d6..ecd5eff 100644 --- a/common/tasks/network.py +++ b/common/tasks/network.py @@ -7,7 +7,8 @@ class RemoveDNSInfo(Task): description = 'Removing resolv.conf' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from os import remove remove(os.path.join(info.root, 'etc/resolv.conf')) @@ -16,7 +17,8 @@ class RemoveHostname(Task): description = 'Removing the hostname file' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from os import remove remove(os.path.join(info.root, 'etc/hostname')) @@ -25,7 +27,8 @@ class ConfigureNetworkIF(Task): description = 'Configuring network interfaces' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): interfaces_path = os.path.join(info.root, 'etc/network/interfaces') if_config = {'squeeze': ('auto lo\n' 'iface lo inet loopback\n' diff --git a/common/tasks/packages.py b/common/tasks/packages.py index 88d1776..ec04ba3 100644 --- a/common/tasks/packages.py +++ b/common/tasks/packages.py @@ -8,7 +8,8 @@ class InstallRemotePackages(Task): phase = phases.package_installation predecessors = [apt.AptUpgrade] - def run(self, info): + @classmethod + def run(cls, info): if len(info.packages.remote) == 0: return import os @@ -59,7 +60,8 @@ class InstallLocalPackages(Task): predecessors = [apt.AptUpgrade] successors = [InstallRemotePackages] - def run(self, info): + @classmethod + def run(cls, info): if len(info.packages.local) == 0: return from shutil import copy diff --git a/common/tasks/partitioning.py b/common/tasks/partitioning.py index 990d331..a9d982c 100644 --- a/common/tasks/partitioning.py +++ b/common/tasks/partitioning.py @@ -8,7 +8,8 @@ class PartitionVolume(Task): description = 'Partitioning the volume' phase = phases.volume_preparation - def run(self, info): + @classmethod + def run(cls, info): info.volume.partition_map.create(info.volume) @@ -18,7 +19,8 @@ class MapPartitions(Task): predecessors = [PartitionVolume] successors = [filesystem.Format] - def run(self, info): + @classmethod + def run(cls, info): info.volume.partition_map.map(info.volume) @@ -28,5 +30,6 @@ class UnmapPartitions(Task): predecessors = [filesystem.UnmountRoot] successors = [volume.Detach] - def run(self, info): + @classmethod + def run(cls, info): info.volume.partition_map.unmap(info.volume) diff --git a/common/tasks/security.py b/common/tasks/security.py index 50d8db6..ef109ee 100644 --- a/common/tasks/security.py +++ b/common/tasks/security.py @@ -7,7 +7,8 @@ class EnableShadowConfig(Task): description = 'Enabling shadowconfig' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call log_check_call(['/usr/sbin/chroot', info.root, '/sbin/shadowconfig', 'on']) @@ -16,7 +17,8 @@ class DisableSSHPasswordAuthentication(Task): description = 'Disabling SSH password authentication' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import sed_i sshd_config_path = os.path.join(info.root, 'etc/ssh/sshd_config') sed_i(sshd_config_path, '^#PasswordAuthentication yes', 'PasswordAuthentication no') @@ -26,7 +28,8 @@ class DisableSSHDNSLookup(Task): description = 'Disabling sshd remote host name lookup' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): sshd_config_path = os.path.join(info.root, 'etc/ssh/sshd_config') with open(sshd_config_path, 'a') as sshd_config: sshd_config.write('UseDNS no') diff --git a/common/tasks/volume.py b/common/tasks/volume.py index 54baddb..797886b 100644 --- a/common/tasks/volume.py +++ b/common/tasks/volume.py @@ -7,7 +7,8 @@ class Attach(Task): description = 'Attaching the volume' phase = phases.volume_creation - def run(self, info): + @classmethod + def run(cls, info): info.volume.attach() @@ -15,7 +16,8 @@ class Detach(Task): description = 'Detaching the volume' phase = phases.volume_unmounting - def run(self, info): + @classmethod + def run(cls, info): info.volume.detach() @@ -24,5 +26,6 @@ class Delete(Task): phase = phases.cleaning successors = [workspace.DeleteWorkspace] - def run(self, info): + @classmethod + def run(cls, info): info.volume.delete() diff --git a/common/tasks/workspace.py b/common/tasks/workspace.py index 836443b..b840a26 100644 --- a/common/tasks/workspace.py +++ b/common/tasks/workspace.py @@ -6,7 +6,8 @@ class CreateWorkspace(Task): description = 'Creating workspace' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): import os os.makedirs(info.workspace) @@ -15,6 +16,7 @@ class DeleteWorkspace(Task): description = 'Deleting workspace' phase = phases.cleaning - def run(self, info): + @classmethod + def run(cls, info): import os os.rmdir(info.workspace) diff --git a/plugins/admin_user/tasks.py b/plugins/admin_user/tasks.py index 56ebd9d..eb572e8 100644 --- a/plugins/admin_user/tasks.py +++ b/plugins/admin_user/tasks.py @@ -10,7 +10,8 @@ class AddSudoPackage(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('sudo') @@ -18,7 +19,8 @@ class CreateAdminUser(Task): description = 'Creating the admin user' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call log_check_call(['/usr/sbin/chroot', info.root, '/usr/sbin/useradd', @@ -30,7 +32,8 @@ class PasswordlessSudo(Task): description = 'Allowing the admin user to use sudo without a password' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): sudo_admin_path = os.path.join(info.root, 'etc/sudoers.d/99_admin') username = info.manifest.plugins['admin_user']['username'] with open(sudo_admin_path, 'w') as sudo_admin: @@ -45,7 +48,8 @@ class AdminUserCredentials(Task): phase = phases.system_modification predecessors = [InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): from common.tools import sed_i getcreds_path = os.path.join(info.root, 'etc/init.d/ec2-get-credentials') username = info.manifest.plugins['admin_user']['username'] @@ -56,7 +60,8 @@ class DisableRootLogin(Task): description = 'Disabling SSH login for root' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from subprocess import CalledProcessError from common.tools import log_check_call try: diff --git a/plugins/build_metadata/tasks.py b/plugins/build_metadata/tasks.py index ca566d9..f47ad4f 100644 --- a/plugins/build_metadata/tasks.py +++ b/plugins/build_metadata/tasks.py @@ -6,7 +6,8 @@ class WriteMetadata(Task): description = 'Writing bootstrap metadata to file' phase = phases.cleaning - def run(self, info): + @classmethod + def run(cls, info): metadata_path = info.manifest.plugins['build_metadata']['path'] with open(metadata_path, 'w') as metadata: metadata.write(('AMI_ID={ami_id}\n' diff --git a/plugins/cloud_init/tasks.py b/plugins/cloud_init/tasks.py index 965179a..75700bd 100644 --- a/plugins/cloud_init/tasks.py +++ b/plugins/cloud_init/tasks.py @@ -9,7 +9,8 @@ class AddBackports(Task): description = 'Adding backports to the apt sources' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): if info.source_lists.target_exists('{system.release}-backports'): import logging msg = ('{system.release}-backports target already exists').format(**info.manifest_vars) @@ -24,7 +25,8 @@ class AddCloudInitPackages(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources, AddBackports] - def run(self, info): + @classmethod + def run(cls, info): target = None if info.manifest.system['release'] in ['wheezy', 'stable']: target = '{system.release}-backports' @@ -36,7 +38,8 @@ class SetUsername(Task): description = 'Setting username in cloud.cfg' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import sed_i cloud_cfg = os.path.join(info.root, 'etc/cloud/cloud.cfg') username = info.manifest.plugins['cloud_init']['username'] @@ -51,7 +54,8 @@ class SetMetadataSource(Task): description = 'Setting metadata source' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): if 'metadata_sources' in info.manifest.plugins['cloud_init']: sources = info.manifest.plugins['cloud_init']['metadata_sources'] else: @@ -71,7 +75,8 @@ class DisableModules(Task): description = 'Setting cloud.cfg modules' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import re patterns = "" for pattern in info.manifest.plugins['cloud_init']['disable_modules']: diff --git a/plugins/image_commands/tasks.py b/plugins/image_commands/tasks.py index 667d63d..e1ec73c 100644 --- a/plugins/image_commands/tasks.py +++ b/plugins/image_commands/tasks.py @@ -6,7 +6,8 @@ class ImageExecuteCommand(Task): description = 'Execute command in the image' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call for user_cmd in info.manifest.plugins['image_commands']['commands']: diff --git a/plugins/minimize_size/tasks.py b/plugins/minimize_size/tasks.py index a6c49ed..96bfdf2 100644 --- a/plugins/minimize_size/tasks.py +++ b/plugins/minimize_size/tasks.py @@ -12,7 +12,8 @@ class AddFolderMounts(Task): phase = phases.os_installation predecessors = [bootstrap.Bootstrap] - def run(self, info): + @classmethod + def run(cls, info): info.minimize_size_folder = os.path.join(info.workspace, 'minimize_size') os.mkdir(info.minimize_size_folder) for folder in folders: @@ -28,7 +29,8 @@ class RemoveFolderMounts(Task): phase = phases.system_cleaning successors = [apt.AptClean] - def run(self, info): + @classmethod + def run(cls, info): import shutil for folder in folders: temp_path = os.path.join(info.minimize_size_folder, folder.replace('/', '_')) diff --git a/plugins/opennebula/tasks.py b/plugins/opennebula/tasks.py index 1c71432..6b3d26d 100644 --- a/plugins/opennebula/tasks.py +++ b/plugins/opennebula/tasks.py @@ -11,7 +11,8 @@ class OpenNebulaContext(Task): phase = phases.system_modification predecessors = [GenerateLocale] - def run(self, info): + @classmethod + def run(cls, info): import stat rwxr_xr_x = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | diff --git a/plugins/prebootstrapped/tasks.py b/plugins/prebootstrapped/tasks.py index 5c5acb2..c3ec9a6 100644 --- a/plugins/prebootstrapped/tasks.py +++ b/plugins/prebootstrapped/tasks.py @@ -17,7 +17,8 @@ class Snapshot(Task): phase = phases.package_installation predecessors = [packages.InstallRemotePackages, guest_additions.InstallGuestAdditions] - def run(self, info): + @classmethod + def run(cls, info): def mk_snapshot(): return info.volume.snapshot() snapshot = remount(info.volume, mk_snapshot) @@ -30,7 +31,8 @@ class CreateFromSnapshot(Task): phase = phases.volume_creation successors = [ebs.Attach] - def run(self, info): + @classmethod + def run(cls, info): volume_size = int(info.volume.partition_map.get_total_size() / 1024) snapshot = info.manifest.plugins['prebootstrapped']['snapshot'] ebs_volume = info.connection.create_volume(volume_size, @@ -49,7 +51,8 @@ class CopyImage(Task): phase = phases.package_installation predecessors = [packages.InstallRemotePackages, guest_additions.InstallGuestAdditions] - def run(self, info): + @classmethod + def run(cls, info): loopback_backup_name = 'volume-{id}.{ext}.backup'.format(id=info.run_id, ext=info.volume.extension) destination = os.path.join(info.manifest.bootstrapper['workspace'], loopback_backup_name) @@ -65,7 +68,8 @@ class CreateFromImage(Task): phase = phases.volume_creation successors = [volume.Attach] - def run(self, info): + @classmethod + def run(cls, info): info.volume.image_path = os.path.join(info.workspace, 'volume.{ext}'.format(ext=info.volume.extension)) loopback_backup_path = info.manifest.plugins['prebootstrapped']['image'] copyfile(loopback_backup_path, info.volume.image_path) diff --git a/plugins/root_password/tasks.py b/plugins/root_password/tasks.py index c6f89a0..85776cc 100644 --- a/plugins/root_password/tasks.py +++ b/plugins/root_password/tasks.py @@ -6,7 +6,8 @@ class SetRootPassword(Task): description = 'Setting the root password' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): from common.tools import log_check_call log_check_call(['/usr/sbin/chroot', info.root, '/usr/sbin/chpasswd'], 'root:' + info.manifest.plugins['root_password']['password']) diff --git a/plugins/unattended_upgrades/tasks.py b/plugins/unattended_upgrades/tasks.py index 97ea89a..2bb485a 100644 --- a/plugins/unattended_upgrades/tasks.py +++ b/plugins/unattended_upgrades/tasks.py @@ -8,7 +8,8 @@ class AddUnattendedUpgradesPackage(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('unattended-upgrades') @@ -16,7 +17,8 @@ class EnablePeriodicUpgrades(Task): description = 'Writing the periodic upgrades apt config file' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import os.path periodic_path = os.path.join(info.root, 'etc/apt/apt.conf.d/02periodic') update_interval = info.manifest.plugins['unattended_upgrades']['update_interval'] diff --git a/plugins/vagrant/tasks.py b/plugins/vagrant/tasks.py index d60293f..40655b6 100644 --- a/plugins/vagrant/tasks.py +++ b/plugins/vagrant/tasks.py @@ -14,7 +14,8 @@ class CreateVagrantBoxDir(Task): phase = phases.preparation predecessors = [workspace.CreateWorkspace] - def run(self, info): + @classmethod + def run(cls, info): info.vagrant_folder = os.path.join(info.workspace, 'vagrant') os.mkdir(info.vagrant_folder) @@ -24,7 +25,8 @@ class AddPackages(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('openssh-server') @@ -33,7 +35,8 @@ class AddInsecurePublicKey(Task): phase = phases.system_modification predecessors = [CreateAdminUser] - def run(self, info): + @classmethod + def run(cls, info): ssh_dir = os.path.join(info.root, 'home/vagrant/.ssh') os.mkdir(ssh_dir) @@ -50,7 +53,8 @@ class PackageBox(Task): description = 'Packaging the volume as a vagrant box' phase = phases.image_registration - def run(self, info): + @classmethod + def run(cls, info): box_basename = info.manifest.image['name'].format(**info.manifest_vars) box_name = '{name}.box'.format(name=box_basename) box_path = os.path.join(info.manifest.bootstrapper['workspace'], box_name) @@ -74,7 +78,7 @@ class PackageBox(Task): log_check_call(['ln', '-s', info.volume.image_path, disk_link]) ovf_path = os.path.join(info.vagrant_folder, 'box.ovf') - self.write_ovf(info, ovf_path, box_name, mac_address, disk_name) + cls.write_ovf(info, ovf_path, box_name, mac_address, disk_name) box_files = os.listdir(info.vagrant_folder) log_check_call(['tar', '--create', '--gzip', '--dereference', @@ -86,7 +90,7 @@ class PackageBox(Task): logging.getLogger(__name__).info('The vagrant box has been placed at {box_path}' .format(box_path=box_path)) - def write_ovf(self, info, destination, box_name, mac_address, disk_name): + def write_ovf(info, destination, box_name, mac_address, disk_name): namespaces = {'ovf': 'http://schemas.dmtf.org/ovf/envelope/1', 'rasd': 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData', 'vssd': 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData', @@ -153,6 +157,7 @@ class RemoveVagrantBoxDir(Task): phase = phases.cleaning successors = [workspace.DeleteWorkspace] - def run(self, info): + @classmethod + def run(cls, info): shutil.rmtree(info.vagrant_folder) del info.vagrant_folder diff --git a/providers/ec2/tasks/ami.py b/providers/ec2/tasks/ami.py index 9d79a33..60ab4df 100644 --- a/providers/ec2/tasks/ami.py +++ b/providers/ec2/tasks/ami.py @@ -16,7 +16,8 @@ class AMIName(Task): phase = phases.preparation predecessors = [Connect] - def run(self, info): + @classmethod + def run(cls, info): ami_name = info.manifest.image['name'].format(**info.manifest_vars) ami_description = info.manifest.image['description'].format(**info.manifest_vars) @@ -33,7 +34,8 @@ class BundleImage(Task): description = 'Bundling the image' phase = phases.image_registration - def run(self, info): + @classmethod + def run(cls, info): bundle_name = 'bundle-{id}'.format(id=info.run_id) info.bundle_path = os.path.join(info.workspace, bundle_name) log_check_call(['/usr/bin/euca-bundle-image', @@ -51,7 +53,8 @@ class UploadImage(Task): phase = phases.image_registration predecessors = [BundleImage] - def run(self, info): + @classmethod + def run(cls, info): manifest_file = os.path.join(info.bundle_path, info.ami_name + '.manifest.xml') if info.host['region'] == 'us-east-1': s3_url = 'https://s3.amazonaws.com/' @@ -72,7 +75,8 @@ class RemoveBundle(Task): phase = phases.cleaning successors = [workspace.DeleteWorkspace] - def run(self, info): + @classmethod + def run(cls, info): from shutil import rmtree rmtree(info.bundle_path) del info.bundle_path @@ -140,7 +144,8 @@ class RegisterAMI(Task): } } - def run(self, info): + @classmethod + def run(cls, info): registration_params = {'name': info.ami_name, 'description': info.ami_description} registration_params['architecture'] = {'i386': 'i386', @@ -169,7 +174,7 @@ class RegisterAMI(Task): registration_params['virtualization_type'] = 'hvm' else: registration_params['virtualization_type'] = 'paravirtual' - registration_params['kernel_id'] = (self.kernel_mapping + registration_params['kernel_id'] = (cls.kernel_mapping .get(info.host['region']) .get(grub_boot_device) .get(info.manifest.system['architecture'])) diff --git a/providers/ec2/tasks/boot.py b/providers/ec2/tasks/boot.py index b6af95e..399cbac 100644 --- a/providers/ec2/tasks/boot.py +++ b/providers/ec2/tasks/boot.py @@ -8,7 +8,8 @@ class ConfigurePVGrub(Task): description = 'Creating grub config files for PVGrub' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import stat rwxr_xr_x = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | diff --git a/providers/ec2/tasks/connection.py b/providers/ec2/tasks/connection.py index 6ba6158..73d8f8d 100644 --- a/providers/ec2/tasks/connection.py +++ b/providers/ec2/tasks/connection.py @@ -7,13 +7,15 @@ class GetCredentials(Task): description = 'Getting AWS credentials' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): keys = ['access-key', 'secret-key'] if info.manifest.volume['backing'] == 's3': keys.extend(['certificate', 'private-key', 'user-id']) - info.credentials = self.get_credentials(info.manifest, keys) + info.credentials = cls.get_credentials(info.manifest, keys) - def get_credentials(self, manifest, keys): + @classmethod + def get_credentials(cls, manifest, keys): from os import getenv creds = {} if all(key in manifest.data['credentials'] for key in keys): @@ -36,7 +38,8 @@ class Connect(Task): phase = phases.preparation predecessors = [GetCredentials, host.GetInfo] - def run(self, info): + @classmethod + def run(cls, info): from boto.ec2 import connect_to_region info.connection = connect_to_region(info.host['region'], aws_access_key_id=info.credentials['access-key'], diff --git a/providers/ec2/tasks/ebs.py b/providers/ec2/tasks/ebs.py index b541a54..b5f3fe8 100644 --- a/providers/ec2/tasks/ebs.py +++ b/providers/ec2/tasks/ebs.py @@ -6,7 +6,8 @@ class Create(Task): description = 'Creating the EBS volume' phase = phases.volume_creation - def run(self, info): + @classmethod + def run(cls, info): info.volume.create(info.connection, info.host['availabilityZone']) @@ -15,7 +16,8 @@ class Attach(Task): phase = phases.volume_creation predecessors = [Create] - def run(self, info): + @classmethod + def run(cls, info): info.volume.attach(info.host['instanceId']) @@ -23,5 +25,6 @@ class Snapshot(Task): description = 'Creating a snapshot of the EBS volume' phase = phases.image_registration - def run(self, info): + @classmethod + def run(cls, info): info.snapshot = info.volume.snapshot() diff --git a/providers/ec2/tasks/filesystem.py b/providers/ec2/tasks/filesystem.py index c2de2a1..9a77049 100644 --- a/providers/ec2/tasks/filesystem.py +++ b/providers/ec2/tasks/filesystem.py @@ -6,7 +6,8 @@ class S3FStab(Task): description = 'Adding the S3 root partition to the fstab' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): import os.path root = info.volume.partition_map.root diff --git a/providers/ec2/tasks/host.py b/providers/ec2/tasks/host.py index 851431b..9ae1972 100644 --- a/providers/ec2/tasks/host.py +++ b/providers/ec2/tasks/host.py @@ -8,7 +8,8 @@ class HostDependencies(Task): phase = phases.preparation successors = [host.CheckHostDependencies] - def run(self, info): + @classmethod + def run(cls, info): if info.manifest.volume['backing'] == 's3': info.host_dependencies.add('euca2ools') @@ -17,7 +18,8 @@ class GetInfo(Task): description = 'Retrieving instance metadata' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): import urllib2 import json metadata_url = 'http://169.254.169.254/latest/dynamic/instance-identity/document' diff --git a/providers/ec2/tasks/initd.py b/providers/ec2/tasks/initd.py index 7ec4318..88b0121 100644 --- a/providers/ec2/tasks/initd.py +++ b/providers/ec2/tasks/initd.py @@ -10,7 +10,8 @@ class AddEC2InitScripts(Task): phase = phases.system_modification successors = [initd.InstallInitScripts] - def run(self, info): + @classmethod + def run(cls, info): init_scripts = {'ec2-get-credentials': 'ec2-get-credentials', 'ec2-run-user-data': 'ec2-run-user-data'} diff --git a/providers/ec2/tasks/network.py b/providers/ec2/tasks/network.py index 888de1d..cbaf4ac 100644 --- a/providers/ec2/tasks/network.py +++ b/providers/ec2/tasks/network.py @@ -8,7 +8,8 @@ class EnableDHCPCDDNS(Task): description = 'Configuring the DHCP client to set the nameservers' phase = phases.system_modification - def run(self, info): + @classmethod + def run(cls, info): # The dhcp client that ships with debian sets the DNS servers per default. # For dhcpcd we need to configure it to do that. from common.tools import sed_i @@ -21,7 +22,8 @@ class AddBuildEssentialPackage(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('build-essential') @@ -29,7 +31,8 @@ class InstallEnhancedNetworking(Task): description = 'Installing network drivers for SR-IOV support' phase = phases.package_installation - def run(self, info): + @classmethod + def run(cls, info): drivers_url = 'http://downloads.sourceforge.net/project/e1000/ixgbevf stable/2.11.3/ixgbevf-2.11.3.tar.gz' archive = os.path.join(info.root, 'tmp', 'ixgbevf-2.11.3.tar.gz') diff --git a/providers/ec2/tasks/packages.py b/providers/ec2/tasks/packages.py index 8ce3044..3fb5dca 100644 --- a/providers/ec2/tasks/packages.py +++ b/providers/ec2/tasks/packages.py @@ -8,7 +8,8 @@ class DefaultPackages(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('openssh-server') info.packages.add('file') # Needed for the init scripts info.packages.add('dhcpcd') # isc-dhcp-client doesn't work properly with ec2 diff --git a/providers/virtualbox/tasks/guest_additions.py b/providers/virtualbox/tasks/guest_additions.py index 645bbe4..75eb028 100644 --- a/providers/virtualbox/tasks/guest_additions.py +++ b/providers/virtualbox/tasks/guest_additions.py @@ -8,7 +8,8 @@ class CheckGuestAdditionsPath(Task): description = 'Checking whether the VirtualBox Guest Additions image exists' phase = phases.preparation - def run(self, info): + @classmethod + def run(cls, info): import os.path guest_additions_path = info.manifest.bootstrapper['guest_additions'] if not os.path.exists(guest_additions_path): @@ -21,7 +22,8 @@ class AddGuestAdditionsPackages(Task): phase = phases.package_installation successors = [InstallRemotePackages] - def run(self, info): + @classmethod + def run(cls, info): info.packages.add('bzip2') info.packages.add('build-essential') info.packages.add('dkms') @@ -38,7 +40,8 @@ class InstallGuestAdditions(Task): phase = phases.package_installation predecessors = [InstallRemotePackages] - def run(self, info): + @classmethod + def run(cls, info): import os guest_additions_path = info.manifest.bootstrapper['guest_additions'] mount_dir = 'mnt/guest_additions' diff --git a/providers/virtualbox/tasks/packages.py b/providers/virtualbox/tasks/packages.py index a7ad411..316d5dd 100644 --- a/providers/virtualbox/tasks/packages.py +++ b/providers/virtualbox/tasks/packages.py @@ -8,7 +8,8 @@ class DefaultPackages(Task): phase = phases.preparation predecessors = [apt.AddDefaultSources] - def run(self, info): + @classmethod + def run(cls, info): kernels = {'amd64': 'linux-image-amd64', 'i386': 'linux-image-686', } info.packages.add(kernels.get(info.manifest.system['architecture']))