-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add generator subcommand to ansible-dk CLI #65
base: master
Are you sure you want to change the base?
Changes from all commits
6e63cca
5355eee
8135af1
50c584b
864ba01
310bb6d
b6b7662
1504764
ae2bc04
f278ca9
317620c
83aecbb
d8b97e4
58a3bdd
751036b
1354920
fd795d4
c958b40
5f8325f
7ea9f1a
bd1539f
177f068
4821d00
4ec570f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# ansible-dk generate | ||
|
||
An ansible-dk cli subcommand for generating skeleton Ansible code layouts | ||
|
||
### Usage: | ||
>$ ansible-dk generate repo foo | ||
|
||
Would generate a skeleton ansible repo named foo by running a generator playbook | ||
located at /opt/ansible-dk/generators/default/repo.yml | ||
|
||
Note: The default generators are still in development and in most cases don't do anything yet. | ||
|
||
### Custom Generators | ||
You can supply custom generator playbooks. This can be done with a cli arg: | ||
>$ ansible-dk generate repo -g /path/to/my/generators foo | ||
|
||
This would generate an ansible repo named foo using a playbook at /path/to/my/generators/repo.yml | ||
|
||
You can also set this in a config file so you won't have to pass it to the cli every time. | ||
Add something like this to ~/.ansible-dk/config.yml: | ||
``` | ||
--- | ||
generator: /path/to/my/generators | ||
``` | ||
|
||
### Variables | ||
By default all generator playbooks are passed a variable of [thing]_name. Example: repo_name | ||
You can add custom variables to run with your playbooks in the same format you'd pass them to `ansible-playbooks`: | ||
>$ ansible-dk generate repo foo -e foo=bar -e bar=foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,13 +6,40 @@ import click | |
import os | ||
import sys | ||
import json | ||
import yaml | ||
from tempfile import NamedTemporaryFile | ||
from ansible.executor import playbook_executor | ||
from ansible.inventory import Inventory | ||
from ansible.parsing.dataloader import DataLoader | ||
from ansible.vars import VariableManager | ||
from collections import namedtuple | ||
|
||
################################################### | ||
# Defaults | ||
RUBY_ABI = "2.1.0" | ||
PYTHON_ABI = "2.7" | ||
HOME = os.getenv("HOME") | ||
|
||
def get_config(debug=False): | ||
config_path=os.path.expanduser('~/.ansible-dk/config.yml') | ||
config = { | ||
'generator': '/opt/ansible-dk/generators/default' | ||
} | ||
if os.path.isfile(config_path): | ||
try: | ||
config.update(yaml.load(open(config_path, 'r'))) | ||
if debug: | ||
click.echo("Loaded config from %s:\n%s" % (config_path, config)) | ||
return config | ||
except: | ||
if debug: | ||
click.echo("Error loading config file %s" % config_path) | ||
return config | ||
else: | ||
if debug: | ||
click.echo("No config file found at %s" % config_path) | ||
return config | ||
|
||
# pull version from version-manifest file left by package install | ||
def check_version(): | ||
file='/opt/ansible-dk/version-manifest.json' | ||
|
@@ -101,19 +128,61 @@ def verify(): | |
|
||
################################################### | ||
# generate command | ||
@cli.group() | ||
@cli.group(help='A tool for generating skeleton Ansible code layouts. More info: https://github.com/omniti-labs/ansible-dk/blob/master/GENERATE.md') | ||
def generate(): | ||
pass | ||
|
||
@generate.command(name='playbook') | ||
@click.option('--name', required=True, help='Name of playbook to generate') | ||
def generate_playbook(name): | ||
print("Generating playbook: ", name) | ||
def parse_extra_vars(context, param, e): | ||
extra_vars = {} | ||
for var in e: | ||
try: | ||
key, value = var.split('=') | ||
except ValueError: | ||
raise click.BadParameter('must be in the format var=value') | ||
extra_vars[key] = value | ||
return extra_vars | ||
|
||
# dynamically create generate subcommands | ||
def generate_method(thing): | ||
@generate.command(name=thing, help='Generate ansible %s' % thing) | ||
@click.option('--debug', is_flag=True, help="Enable debug mode") | ||
@click.option('--generator', '-g', default=False, metavar='/opt/ansible-dk/generators/default', help='Path to custom generator repo') | ||
@click.option('-e', 'extra_vars', multiple=True, callback=parse_extra_vars, metavar='var=value', help='extra vars to pass to ansible, multiple ok') | ||
@click.argument('name') | ||
def generated_method(debug, generator, name, extra_vars): | ||
if not generator: | ||
generator = get_config(debug)['generator'] | ||
extra_vars[thing+'_name'] = name | ||
playbook_path = "%s/%s.yml" % (generator, thing) | ||
if debug: | ||
click.echo('generating %s named %s using %s' % (thing, name, playbook_path)) | ||
run_ansible(playbook_path, extra_vars) | ||
generated_method.__name__ = 'generate_%s' % thing | ||
|
||
generate_things = ['repo', 'role', 'filter', 'inventory', 'config', 'playbook'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong - repo should treat its 'name' parameter differently, and needs to create the directory. The implementation of 'repo' is different than the others. |
||
for thing in generate_things: | ||
generate_method(thing) | ||
|
||
@generate.command(name='role') | ||
@click.option('--name', required=True, help='Name of role to generate') | ||
def generate_role(name): | ||
print("Generating role: ", name) | ||
def run_ansible(playbook, vars=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to figure out the target path and pass it into this function |
||
if not os.path.exists(playbook): | ||
print 'Error - specified role generator playbook does not exist' | ||
sys.exit() | ||
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'remote_user', 'private_key_file', 'ssh_common_args', 'sftp_extra_args', 'scp_extra_args', 'ssh_extra_args', 'verbosity']) | ||
options = Options(connection='local', module_path=None, forks=100, become=None, become_method=None, become_user=None, check=False, listhosts=False, listtasks=False, listtags=False, syntax=False, remote_user=None, private_key_file=None, ssh_common_args=None, sftp_extra_args=None, scp_extra_args=None, ssh_extra_args=None, verbosity=None) | ||
loader = DataLoader() | ||
variable_manager = VariableManager() | ||
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost') | ||
variable_manager.set_inventory(inventory) | ||
if vars: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will ALWAYS have vars to pass into the run. We need to determine what they are, but a good start would be:
The ansible-dk CLI will maintain a list of 'context vars' that it passes to the ansible run. We must document these in the README or somewhere else. |
||
variable_manager.extra_vars = vars | ||
playbook_executor.PlaybookExecutor( | ||
playbooks=[playbook], | ||
inventory=inventory, | ||
options=options, | ||
loader=loader, | ||
variable_manager=variable_manager, | ||
passwords=dict() | ||
).run() | ||
|
||
################################################### | ||
# Call main CLI | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name "ansible-dk-generators" | ||
default_version "0.1.0" # This is just to silence a warning | ||
description "a set of generic playbooks for the ansible-dk generator" | ||
|
||
build do | ||
copy Dir.pwd + "/generators", "#{install_dir}/" | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
tasks: | ||
- debug: msg="running dummy config generator playbook" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
tasks: | ||
- debug: msg="running dummy filter generator playbook" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
tasks: | ||
- debug: msg="running dummy inventory generator playbook" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
tasks: | ||
- debug: msg="running dummy playbook generator playbook" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
tasks: | ||
- debug: msg="running dummy repo generator playbook" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--- | ||
- hosts: localhost | ||
connection: local | ||
vars: | ||
role_subdirectories: | ||
- tasks | ||
- handlers | ||
- templates | ||
- files | ||
- vars | ||
- meta | ||
tasks: | ||
|
||
- name: create top level role directory | ||
file: state=directory path="{{ role_name }}" recurse=yes | ||
|
||
- name: create subdirectories | ||
file: state=directory path="{{ role_name }}/{{ item }}" | ||
with_items: "{{ role_subdirectories }}" | ||
|
||
- name: create main.yml files | ||
copy: content="---\n" dest="{{ role_name }}/{{ item }}/main.yml" | ||
with_items: "{{ role_subdirectories }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should comment this section to describe your intent as to what is going on here. Cleverness can be harmful, remember this code has to be maintained by the whole team.