mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 07:26:29 +00:00
Plugin architecture working
This commit is contained in:
parent
4dbdb387cd
commit
e63e2cca0c
21 changed files with 135 additions and 88 deletions
6
build-debian-cloud
Executable file
6
build-debian-cloud
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__' and __package__ is None:
|
||||||
|
from common import main
|
||||||
|
main.main()
|
|
@ -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
|
||||||
|
|
|
@ -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
31
common/main.py
Normal 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)
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
|
|
@ -1 +0,0 @@
|
||||||
from main import init_subparser
|
|
37
ec2/main.py
37
ec2/main.py
|
@ -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
|
|
|
@ -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
0
plugins/__init__.py
Normal file
6
plugins/admin_user/__init__.py
Normal file
6
plugins/admin_user/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
def modify_tasklist(tasklist, manifest):
|
||||||
|
from providers.ec2.packages import ImagePackages
|
||||||
|
from adminuser import AddSudoPackage
|
||||||
|
tasklist.after(ImagePackages, AddSudoPackage())
|
7
plugins/admin_user/adminuser.py
Normal file
7
plugins/admin_user/adminuser.py
Normal 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')
|
5
plugins/build_metadata/__init__.py
Normal file
5
plugins/build_metadata/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
|
def modify_tasklist(tasklist, manifest):
|
||||||
|
from buildmetadata import PrintInfo
|
||||||
|
tasklist.append(PrintInfo())
|
7
plugins/build_metadata/buildmetadata.py
Normal file
7
plugins/build_metadata/buildmetadata.py
Normal 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
4
providers/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import ec2
|
||||||
|
|
||||||
|
|
||||||
|
providers = {'ec2': ec2}
|
25
providers/ec2/__init__.py
Normal file
25
providers/ec2/__init__.py
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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):
|
|
@ -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
|
Loading…
Add table
Reference in a new issue