Skip to content
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

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6e63cca
WIP - generic role generator
jblancett Apr 13, 2016
5355eee
generators folder
jblancett Apr 13, 2016
8135af1
make extra_vars optional
jblancett Apr 13, 2016
50c584b
added some dummy generator playbooks
jblancett Apr 13, 2016
864ba01
generic generator subcommands
jblancett Apr 14, 2016
310bb6d
fix role generator to conform to new format
jblancett Apr 14, 2016
b6b7662
load config from ~/.ansible-dk/config
jblancett Apr 14, 2016
1504764
change --generator-repo to just --generator
jblancett Apr 14, 2016
ae2bc04
change path to name
jblancett Apr 14, 2016
f278ca9
role_path is now role_name
jblancett Apr 14, 2016
317620c
show name of thing being generated in debug output
jblancett Apr 14, 2016
83aecbb
take extra vars and pass them to ansible-playbook, in the same format…
jblancett Apr 15, 2016
d8b97e4
validate extra_vars with proper callback
jblancett Apr 18, 2016
58a3bdd
updated software definition for ansible-dk cli
jblancett Apr 18, 2016
751036b
added software definition for generators
jblancett Apr 18, 2016
1354920
absolute path for default generators
jblancett Apr 18, 2016
fd795d4
rename generators software definition to ansible-dk-generators and ma…
jblancett Apr 18, 2016
c958b40
dynamically generate subcommands
jblancett Apr 19, 2016
5f8325f
unique method names for better stack traces
jblancett Apr 19, 2016
7ea9f1a
fix default generator config
jblancett Apr 21, 2016
bd1539f
add .yml extension to config file
jblancett Apr 21, 2016
177f068
move default generators to default subdirectory
jblancett Apr 21, 2016
4821d00
pass debug to get_config
jblancett Apr 21, 2016
4ec570f
documentation for generator
jblancett Apr 21, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions GENERATE.md
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
87 changes: 78 additions & 9 deletions ansible-dk-cli/ansible-dk
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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):
Copy link
Contributor

@clintoncwolfe clintoncwolfe Apr 21, 2016

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.

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']
Copy link
Contributor

Choose a reason for hiding this comment

The 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):
Copy link
Contributor

Choose a reason for hiding this comment

The 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:
Copy link
Contributor

Choose a reason for hiding this comment

The 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:

adk_generator_command        # 'role' in ansible-dk generate role pony
adk_generator_target_path     # ./pony if we're in repo mode, . otherwise 
adk_generator_target_name   # 'pony' in ansible-dk generate role pony 
adk_generator_source             # /opt/ansible-dk/generators/default or whatever              

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
Expand Down
4 changes: 2 additions & 2 deletions config/software/ansible-dk-cli.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name "ansible-dk-cli"
default_version "0.1.0" # This is just to silence a warning
description "One day this might be a generic CLI tool; today it is a hack to make shell-init work"
description "generic CLI tool for ansible-dk"

# This isn't used yet (as we're a shell script, derp) but will be soon!
dependency 'click'
dependency 'ansible-dk-generators'

build do
copy Dir.pwd + "/ansible-dk-cli/ansible-dk", "#{install_dir}/embedded/bin"
Expand Down
7 changes: 7 additions & 0 deletions config/software/ansible-dk-generators.rb
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
6 changes: 6 additions & 0 deletions generators/default/config.yml
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"

6 changes: 6 additions & 0 deletions generators/default/filter.yml
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"

6 changes: 6 additions & 0 deletions generators/default/inventory.yml
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"

6 changes: 6 additions & 0 deletions generators/default/playbook.yml
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"

6 changes: 6 additions & 0 deletions generators/default/repo.yml
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"

23 changes: 23 additions & 0 deletions generators/default/role.yml
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 }}"