diff --git a/bootstrapvz/plugins/ansible/__init__.py b/bootstrapvz/plugins/ansible/__init__.py new file mode 100644 index 0000000..f060ff3 --- /dev/null +++ b/bootstrapvz/plugins/ansible/__init__.py @@ -0,0 +1,13 @@ +import tasks + + +def validate_manifest(data, validator, error): + import os.path + schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml')) + validator(data, schema_path) + + +def resolve_tasks(taskset, manifest): + taskset.add(tasks.AddPackages) + taskset.add(tasks.CheckPlaybookPath) + taskset.add(tasks.RunAnsiblePlaybook) diff --git a/bootstrapvz/plugins/ansible/manifest-schema.yml b/bootstrapvz/plugins/ansible/manifest-schema.yml new file mode 100644 index 0000000..0fc2f57 --- /dev/null +++ b/bootstrapvz/plugins/ansible/manifest-schema.yml @@ -0,0 +1,29 @@ +--- +$schema: http://json-schema.org/draft-04/schema# +title: Ansible plugin manifest +type: object +properties: + plugins: + type: object + properties: + ansible: + type: object + properties: + extra_vars: {type: string} + tags: {type: string} + skip_tags: {type: string} + opt_flags: + type: array + flag: {type: string} + minItems: 1 + hosts: + type: array + host: {type: string} + minItems: 1 + playbook: {$ref: '#/definitions/absolute_path'} + required: + - playbook +definitions: + absolute_path: + pattern: ^/[^\0]+$ + type: string diff --git a/bootstrapvz/plugins/ansible/tasks.py b/bootstrapvz/plugins/ansible/tasks.py new file mode 100644 index 0000000..9d1c893 --- /dev/null +++ b/bootstrapvz/plugins/ansible/tasks.py @@ -0,0 +1,98 @@ +from bootstrapvz.base import Task +from bootstrapvz.common import phases +from bootstrapvz.common.tasks import apt +import os + + +class CheckPlaybookPath(Task): + description = 'Checking whether the playbook path exist' + phase = phases.preparation + + @classmethod + def run(cls, info): + from bootstrapvz.common.exceptions import TaskError + playbook = info.manifest.plugins['ansible']['playbook'] + if not os.path.exists(playbook): + msg = 'The playbook file {playbook} does not exist.'.format(playbook=playbook) + raise TaskError(msg) + if not os.path.isfile(playbook): + msg = 'The playbook path {playbook} does not point to a file.'.format(playbook=playbook) + raise TaskError(msg) + + +class AddPackages(Task): + description = 'Making sure python is installed' + phase = phases.preparation + predecessors = [apt.AddDefaultSources] + + @classmethod + def run(cls, info): + info.packages.add('python') + + +class RunAnsiblePlaybook(Task): + description = 'Running ansible playbooks' + phase = phases.system_modification + + @classmethod + def run(cls, info): + from bootstrapvz.common.tools import log_check_call + + # Extract playbook and directory + playbook = info.manifest.plugins['ansible']['playbook'] + playbook_dir = os.path.dirname(os.path.realpath(playbook)) + + # Check for hosts + hosts = None + if 'hosts' in info.manifest.plugins['ansible']: + hosts = info.manifest.plugins['ansible']['hosts'] + + # Check for extra vars + extra_vars = None + if 'extra_vars' in info.manifest.plugins['ansible']: + extra_vars = info.manifest.plugins['ansible']['extra_vars'] + + tags = None + if 'tags' in info.manifest.plugins['ansible']: + tags = info.manifest.plugins['ansible']['tags'] + + skip_tags = None + if 'skip_tags' in info.manifest.plugins['ansible']: + skip_tags = info.manifest.plugins['ansible']['skip_tags'] + + opt_flags = None + if 'opt_flags' in info.manifest.plugins['ansible']: + opt_flags = info.manifest.plugins['ansible']['opt_flags'] + + # build the inventory file + inventory = os.path.join(info.root, 'tmp/bootstrap-inventory') + with open(inventory, 'w') as handle: + conn = '{} ansible_connection=chroot'.format(info.root) + content = "" + + if hosts: + for host in hosts: + content += '[{}]\n{}\n'.format(host, conn) + else: + content = conn + + handle.write(content) + + # build the ansible command + cmd = ['ansible-playbook', '-i', inventory, os.path.basename(playbook)] + if extra_vars: + tmp_cmd = ['--extra-vars', '\"{}\"'.format(extra_vars)] + cmd.extend(tmp_cmd) + if tags: + tmp_cmd = ['--tags={}'.format(tags)] + cmd.extend(tmp_cmd) + if skip_tags: + tmp_cmd = ['--skip_tags={}'.format(skip_tags)] + cmd.extend(tmp_cmd) + if opt_flags: + # Should probably do proper validation on these, but I don't think it should be used very often. + cmd.extend(opt_flags) + + # Run and remove the inventory file + log_check_call(cmd, cwd=playbook_dir) + os.remove(inventory)