Plugin architecture working

This commit is contained in:
Anders Ingemann 2013-05-16 08:00:28 +02:00
parent 4dbdb387cd
commit e63e2cca0c
21 changed files with 135 additions and 88 deletions

6
build-debian-cloud Executable file
View file

@ -0,0 +1,6 @@
#!/usr/bin/env python
if __name__ == '__main__' and __package__ is None:
from common import main
main.main()

View file

@ -2,3 +2,4 @@ from bootstrapinfo import BootstrapInformation
from manifest import Manifest from manifest import Manifest
from task import Task from task import Task
from tasklist import TaskList from tasklist import TaskList
from plugin import Plugin

View file

@ -3,4 +3,4 @@
class BootstrapInformation(object): class BootstrapInformation(object):
def __init__(self, manifest=None, args=None): def __init__(self, manifest=None, args=None):
self.manifest = manifest self.manifest = manifest
self.args = args self.args = args

31
common/main.py Normal file
View file

@ -0,0 +1,31 @@
from providers import providers
def main():
from argparse import ArgumentParser
parser = ArgumentParser(description='Bootstrap Debian for the cloud.')
parser.add_argument('--debug', action='store_true',
help='Print debugging information')
parser.set_defaults(func=run)
subparsers = parser.add_subparsers(title='providers', description='supported providers', dest='provider')
for provider in providers.values():
provider.init_subparser(subparsers)
args = parser.parse_args()
args.func(args)
def run(args):
provider = providers[args.provider]
manifest = provider.Manifest(args.manifest)
manifest.validate()
manifest.load_plugins()
tasklist = provider.tasklist(manifest)
tasklist.plugins(manifest)
from common import BootstrapInformation
bootstrap_info = BootstrapInformation(manifest, args)
tasklist.run(bootstrap_info)

View file

@ -7,8 +7,16 @@ class Manifest(object):
self.parse(json.load(open(self.path))) self.parse(json.load(open(self.path)))
def parse(self, data): def parse(self, data):
self.volume = data['volume'] self.volume = data['volume']
self.system = data['system'] self.system = data['system']
self.plugins = data['plugins']
def validate(self): def validate(self):
pass pass
def load_plugins(self):
self.loaded_plugins = []
for modname in self.plugins.keys():
if self.plugins[modname]['enabled']:
plugin = __import__('plugins.%s' % modname, fromlist=['plugins'])
self.loaded_plugins.append(plugin)

View file

@ -1,15 +1,24 @@
class TaskList(list): class TaskList(list):
def run(self, info):
def plugins(self, manifest):
for plugin in manifest.loaded_plugins:
plugin.modify_tasklist(self, manifest)
def run(self, bootstrap_info):
for task in self: for task in self:
task.run(info) task.run(bootstrap_info)
def before(self, task): def before(self, ref, task):
pass i = next(i for i, task in enumerate(self) if type(task) is ref)
self.insert(i, task)
def replace(self, task): def replace(self, ref, task):
pass i = next(i for i, task in enumerate(self) if type(task) is ref)
self.pop(i)
self.insert(i, task)
def after(self, task): def after(self, ref, task):
pass i = next(i for i, task in enumerate(self) if type(task) is ref)
self.insert(i+1, task)

View file

@ -1,18 +0,0 @@
#!/usr/bin/env python
def main():
from argparse import ArgumentParser
import ec2
parser = ArgumentParser(description='Bootstrap Debian for the cloud.')
parser.add_argument('--debug', action='store_true',
help='Print debugging information')
subparsers = parser.add_subparsers(title='providers', description='supported providers', dest='provider')
ec2.init_subparser(subparsers)
args = parser.parse_args()
args.func(args)
if __name__ == '__main__' and __package__ is None:
main()

View file

@ -1 +0,0 @@
from main import init_subparser

View file

@ -1,37 +0,0 @@
def init_subparser(subparsers):
cmd = subparsers.add_parser('ec2', help='Bootstrap Debian for EC2')
cmd.add_argument('--access-key', help='AWS Access Key', metavar='ID')
cmd.add_argument('--secret-key', help='AWS Secret Key', metavar='KEY')
cmd.add_argument('manifest', help='Manifest file to use for bootstrapping', metavar='MANIFEST')
cmd.set_defaults(func=run)
def run(args):
from manifest import Manifest
from common import BootstrapInformation
manifest = Manifest(args.manifest)
manifest.validate()
task_list = get_tasklist(manifest)
info = BootstrapInformation(manifest=manifest, args=args)
task_list.run(info)
def get_tasklist(manifest):
from common import TaskList
import packages
import ec2
import host
task_list = TaskList()
task_list.extend([packages.HostPackages(),
packages.ImagePackages(),
ec2.GetCredentials(),
host.GetInfo(),
ec2.Connect(),
host.InstallPackages()
])
return task_list

View file

@ -25,12 +25,12 @@
"size" : "1G" "size" : "1G"
}, },
"plugins": { "plugins": {
"admin-user": { "admin_user": {
"enabled": true "enabled": true
}, },
"build-metadata": { "build_metadata": {
"enabled": false, "enabled": true,
"path": "/root/build-metadata-{ami_name}" "path" : "/root/build-metadata-{ami_name}"
} }
} }
} }

0
plugins/__init__.py Normal file
View file

View file

@ -0,0 +1,6 @@
def modify_tasklist(tasklist, manifest):
from providers.ec2.packages import ImagePackages
from adminuser import AddSudoPackage
tasklist.after(ImagePackages, AddSudoPackage())

View file

@ -0,0 +1,7 @@
from common import Task
class AddSudoPackage(Task):
def run(self, info):
super(AddSudoPackage, self).run(info)
info.img_packages[0].add('sudo')

View file

@ -0,0 +1,5 @@
def modify_tasklist(tasklist, manifest):
from buildmetadata import PrintInfo
tasklist.append(PrintInfo())

View file

@ -0,0 +1,7 @@
from common import Task
class PrintInfo(Task):
def run(self, info):
super(PrintInfo, self).run(info)
print('info')

4
providers/__init__.py Normal file
View file

@ -0,0 +1,4 @@
import ec2
providers = {'ec2': ec2}

25
providers/ec2/__init__.py Normal file
View file

@ -0,0 +1,25 @@
from manifest import Manifest
def init_subparser(subparsers):
sub = subparsers.add_parser('ec2', help='Bootstrap Debian for EC2')
sub.add_argument('--access-key', help='AWS Access Key', metavar='ID')
sub.add_argument('--secret-key', help='AWS Secret Key', metavar='KEY')
sub.add_argument('manifest', help='Manifest file to use for bootstrapping', metavar='MANIFEST')
def tasklist(manifest):
from common import TaskList
import packages
import ec2
import host
task_list = TaskList()
task_list.extend([packages.HostPackages(),
packages.ImagePackages(),
ec2.GetCredentials(),
host.GetInfo(),
ec2.Connect(),
host.InstallPackages()
])
return task_list

View file

@ -5,7 +5,6 @@ class GetCredentials(Task):
def run(self, info): def run(self, info):
super(GetCredentials, self).run(info) super(GetCredentials, self).run(info)
info.ec2_credentials = self.get_ec2_credentials(info.args, info.manifest) info.ec2_credentials = self.get_ec2_credentials(info.args, info.manifest)
return info
def get_ec2_credentials(self, args, manifest): def get_ec2_credentials(self, args, manifest):
from os import getenv from os import getenv
@ -37,4 +36,4 @@ class Connect(Task):
# info.ec2_connection = boto.ec2.connect_to_region(info.host['region'], # info.ec2_connection = boto.ec2.connect_to_region(info.host['region'],
# aws_access_key_id=info.ec2_credentials['access_key'], # aws_access_key_id=info.ec2_credentials['access_key'],
# aws_secret_access_key=info.ec2_credentials['secret_key']) # aws_secret_access_key=info.ec2_credentials['secret_key'])
return info # return 'ec2_connection', ec2_connection

View file

@ -4,13 +4,15 @@ from common import Task
class GetInfo(Task): class GetInfo(Task):
def run(self, info): def run(self, info):
super(GetInfo, self).run(info) super(GetInfo, self).run(info)
import urllib2 # import urllib2
import json # import json
# response = urllib2.urlopen('http://169.254.169.254/latest/dynamic/instance-identity/document') # response = urllib2.urlopen('http://169.254.169.254/latest/dynamic/instance-identity/document')
# info.host = json.load(response.read()) # info.host = json.load(response.read())
return info # return info
class InstallPackages(Task): class InstallPackages(Task):
def run(self, info): def run(self, info):
# Check if packages are installed with
# /usr/bin/dpkg -s ${name} | grep -q 'Status: install'
pass pass

View file

@ -4,7 +4,7 @@ import common
class Manifest(common.Manifest): class Manifest(common.Manifest):
def parse(self, data): def parse(self, data):
super(Manifest, self).parse(data) super(Manifest, self).parse(data)
self.credentials = data["credentials"] self.credentials = data["credentials"]
self.virtualization = data["virtualization"] self.virtualization = data["virtualization"]
def validate(self): def validate(self):

View file

@ -4,27 +4,20 @@ from common import Task
class HostPackages(Task): class HostPackages(Task):
def run(self, info): def run(self, info):
super(HostPackages, self).run(info) super(HostPackages, self).run(info)
info.host_pkg = self.get_host_packages(info.manifest)
return info
def get_host_packages(self, manifest):
packages = set(['debootstrap', packages = set(['debootstrap',
# To make sure a volume is not busy before unmounting we need lsof # To make sure a volume is not busy before unmounting we need lsof
'lsof', 'lsof',
]) ])
if manifest.volume['filesystem'] == 'xfs': if info.manifest.volume['filesystem'] == 'xfs':
packages.add('xfsprogs') packages.add('xfsprogs')
return packages info.host_packages = packages
class ImagePackages(Task): class ImagePackages(Task):
def run(self, info): def run(self, info):
super(ImagePackages, self).run(info) super(ImagePackages, self).run(info)
info.image_pkg_include, info.image_pkg_exclude = self.get_image_packages(info.manifest) manifest = info.manifest
return info
def get_image_packages(self, manifest):
# Add some basic packages we are going to need # Add some basic packages we are going to need
include = set(['udev', include = set(['udev',
'openssh-server', 'openssh-server',
@ -52,4 +45,4 @@ class ImagePackages(Task):
include = include.union(manifest.system['packages']) include = include.union(manifest.system['packages'])
return include, exclude info.img_packages = include, exclude