├── config.yml ├── README.md └── tower_populator /config.yml: -------------------------------------------------------------------------------- 1 | #support multiple orgs eventually 2 | org: Hyrule Ventures 3 | org_desc: Mining Rupees Daily 4 | users: 5 | - username: link 6 | email: link@hyrule.com 7 | first_name: Link 8 | is_superuser: yes 9 | last_name: Smith 10 | - username: gdorf 11 | email: gannon@hyrule.com 12 | first_name: Gannon 13 | is_superuser: false 14 | last_name: Dorf 15 | - username: zelda 16 | email: zelda@hyrule.com 17 | first_name: Zelda 18 | is_superuser: false 19 | last_name: Smith 20 | - username: epona 21 | email: epona@hyrule.com 22 | first_name: Epona 23 | is_superuser: false 24 | last_name: Horse 25 | - username: demise 26 | email: demise@hyrule.com 27 | first_name: De 28 | is_superuser: false 29 | last_name: Mise 30 | 31 | teams: 32 | - name: Ops 33 | description: The Ops Team 34 | users: 35 | - link 36 | - name: QA 37 | description: The QA Team 38 | users: 39 | - gdorf 40 | - name: Dev 41 | description: The Dev Team 42 | users: 43 | - zelda 44 | 45 | credentials: 46 | - name: EC2 SSH 47 | description: Used for EC2 instances 48 | team: Ops 49 | kind: ssh 50 | username: root 51 | private_key: /Users/jmartin/.ssh/ida_rsa 52 | - name: Local SSH 53 | description: Used for vagrant instances 54 | team: Ops 55 | kind: ssh 56 | username: vagrant 57 | private_key: /Users/jmartin/.vagrant.d/insecure_private_key 58 | - name: AWS creds 59 | description: Used for AWS 60 | team: Ops 61 | kind: aws 62 | username: YOU 63 | password: CANTHANDLETHIS 64 | - name: RAX creds 65 | description: Used for Rackspace 66 | team: Ops 67 | kind: rax 68 | username: me 69 | password: noyoucant 70 | 71 | inventories: 72 | - name: Production 73 | description: Production Machines 74 | groups: 75 | - name: EC2 76 | credential: AWS creds 77 | source: ec2 78 | description: EC2 hosts 79 | - name: RAX 80 | credential: RAX creds 81 | source: rax 82 | description: RAX hosts 83 | - name: Test 84 | description: Test Machines 85 | groups: 86 | - name: web 87 | source: manual 88 | hosts: 89 | - name: 10.42.0.6 90 | - name: 10.42.0.7 91 | - name: 10.42.0.8 92 | - name: 10.42.0.9 93 | - name: 10.42.0.10 94 | - name: QA 95 | description: QA Machines 96 | 97 | projects: 98 | - name: Hyrulian Playbooks 99 | description: Configures all the servers in Hyrule. 100 | scm_type: git 101 | scm_url: https://github.com/jsmartin/tower-demo-example-simple 102 | - name: Ansible Examples 103 | description: Some example roles and playbooks 104 | scm_type: git 105 | scm_url: https://github.com/ansible/ansible-examples 106 | 107 | job_templates: 108 | - name: Apache 109 | description: Confgure Apache servers 110 | inventory: Test 111 | project: Hyrulian Playbooks 112 | playbook: site.yml 113 | machine_credential: Local SSH 114 | job_type: run 115 | verbosity: 0 116 | forks: 5 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tower_populator 2 | 3 | The purpose of this project is to populate an Ansible Tower installation from a configuration file. 4 | 5 | ## Requirements 6 | 7 | pip install ansible-tower-cli 8 | 9 | **current version requires installation from tower-cli issue-9-unstable branch for dynamic group support** 10 | 11 | make sure you have ```~/.tower_cli.cfg``` configured with something like: 12 | 13 | 14 | host: 10.42.0.200 15 | username: admin 16 | password: password 17 | 18 | ## Usage 19 | 20 | Usage is simple. Declare the options you want in [config.yml](config.yml), and run the script: 21 | 22 | ``` 23 | ./tower_populator config.yml 24 | 25 | Creating Organization 26 | 27 | Hyrule Ventures Mining Rupees Daily 28 | 29 | Creating Users 30 | 31 | {'username': 'link', 'is_superuser': True, 'first_name': 'Link', 'last_name': 'Smith', 'email': 'link@hyrule.com'} 32 | {'username': 'gdorf', 'is_superuser': False, 'first_name': 'Gannon', 'last_name': 'Dorf', 'email': 'gannon@hyrule.com'} 33 | {'username': 'zelda', 'is_superuser': False, 'first_name': 'Zelda', 'last_name': 'Smith', 'email': 'zelda@hyrule.com'} 34 | {'username': 'epona', 'is_superuser': False, 'first_name': 'Epona', 'last_name': 'Horse', 'email': 'epona@hyrule.com'} 35 | {'username': 'demise', 'is_superuser': False, 'first_name': 'De', 'last_name': 'Mise', 'email': 'demise@hyrule.com'} 36 | 37 | Creating Teams 38 | 39 | {'description': 'The Ops Team', 'users': ['link'], 'name': 'Ops'} 40 | {'description': 'The QA Team', 'users': ['gdorf'], 'name': 'QA'} 41 | {'description': 'The Dev Team', 'users': ['zelda'], 'name': 'Dev'} 42 | 43 | Creating Credentials 44 | 45 | {'username': 'vagrant', 'kind': 'ssh', 'name': 'Local SSH', 'team': 'Ops', 'private_key': '/root/vagrant-key', 'description': 'Used for non-cloud instances'} 46 | {'username': 'myaccesskey', 'kind': 'aws', 'name': 'AWS creds', 'team': 'Ops', 'password': 'mysecretkey', 'description': 'Used for AWS'} 47 | {'username': 'myusername', 'kind': 'rax', 'name': 'Rax Creds', 'team': 'Ops', 'password': 'myapikey', 'description': 'Used for Rackspace'} 48 | 49 | Creating Inventories 50 | 51 | {'name': 'Production', 'groups': [{'source': 'ec2', 'credential': 'AWS creds', 'description': 'EC2 hosts', 'name': 'EC2'}], 'description': 'Production Machines'} 52 | {'name': 'Test', 'description': 'Test Machines'} 53 | {'name': 'QA', 'description': 'QA Machines'} 54 | 55 | Creating Projects 56 | 57 | {'scm_type': 'git', 'name': 'Hyrulian Playbooks', 'scm_url': 'https://github.com/jsmartin/demo-cli', 'description': 'Configures all the servers in Hyrule.'} 58 | {'scm_type': 'git', 'name': 'Ansible Examples', 'scm_url': 'https://github.com/ansible/ansible-examples', 'description': 'Some example roles and playbooks'} 59 | 60 | Must sync projects from Tower UI if pulling from SCM. Press any key after synch is finished. 61 | 62 | 63 | Creating Job Templates 64 | 65 | {'name': 'Apache', 'verbosity': 0, 'job_type': 'run', 'project': 'Hyrulian Playbooks', 'inventory': 'Production', 'forks': 7, 'machine_credential': 'Local SSH', 'playbook': 'apache.yml', 'description': 'Confgure Apache servers'} 66 | {'name': 'Graphite', 'verbosity': 2, 'job_type': 'run', 'project': 'Hyrulian Playbooks', 'inventory': 'Production', 'machine_credential': 'Local SSH', 'playbook': 'graphite.yml', 'description': 'Confgure Graphite servers'} 67 | ``` 68 | 69 | ## Gotchas 70 | 71 | tower-cli doesn't do everything the Tower UI does (yet), so there are some limitations: 72 | 73 | 1. All credential types use ```username``` and ```password``` as options, even AWS, Rackspace, etc. This is a [known issue](https://github.com/ansible/tower-cli/issues/13). 74 | 75 | -------------------------------------------------------------------------------- /tower_populator: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import yaml 4 | import sys 5 | import tower_cli 6 | import time 7 | from select import select 8 | import os.path 9 | from getpass import getpass 10 | 11 | class Config: 12 | def __init__(self, **entries): 13 | self.__dict__.update(entries) 14 | 15 | 16 | 17 | 18 | # load configuration 19 | c = yaml.load(open(sys.argv[1]).read()) 20 | tower = Config(**c) 21 | 22 | user_res = tower_cli.get_resource('user') 23 | team_res = tower_cli.get_resource('team') 24 | org_res = tower_cli.get_resource('organization') 25 | cred_res = tower_cli.get_resource('credential') 26 | inv_res = tower_cli.get_resource('inventory') 27 | host_res = tower_cli.get_resource('host') 28 | group_res = tower_cli.get_resource('group') 29 | project_res = tower_cli.get_resource('project') 30 | job_template_res = tower_cli.get_resource('job_template') 31 | 32 | print "\nCreating Organization\n" 33 | print tower.org, tower.org_desc 34 | # create organization 35 | org = org_res.create(name=tower.org, description=tower.org_desc) 36 | org_id = org['id'] 37 | 38 | if tower.users: 39 | print "\nCreating Users\n" 40 | # create users 41 | for u in tower.users: 42 | print u 43 | user = user_res.create(**u) 44 | org_res.associate(org_id, user['id']) 45 | 46 | if tower.teams: 47 | print "\nCreating Teams\n" 48 | # create teams 49 | for t in tower.teams: 50 | print t 51 | t['organization'] = org_id 52 | team = team_res.create(**t) 53 | for u in t['users']: 54 | user = user_res.get(username=u) 55 | team_res.associate(team['id'], user['id']) 56 | 57 | if tower.credentials: 58 | print "\nCreating Credentials\n" 59 | # create credentials 60 | for c in tower.credentials: 61 | print c 62 | if c.has_key('team') and c.has_key('user'): 63 | print "Creds must have either team or user, not both." 64 | sys.exit(1) 65 | if c.has_key('team'): 66 | team = team_res.get(name=team['name']) 67 | c['team'] = team['id'] 68 | if c.has_key('user'): 69 | user = user_res.get(name=user['name']) 70 | c['user'] = user['id'] 71 | if c.has_key('private_key'): 72 | key_file_path = os.path.expanduser(c['private_key']) 73 | c['ssh_key_data'] = open(key_file_path, 'r') 74 | if c.has_key('private_key_password'): 75 | if c['private_key_password'] == 'prompt': 76 | c['ssh_key_unlock'] = getpass('Enter your ssh key password: ') 77 | else: 78 | c['ssh_key_unlock'] = c['private_key_password'] 79 | c = cred_res.create(**c) 80 | 81 | if tower.inventories: 82 | # create inventories 83 | print "\nCreating Inventories\n" 84 | for i in tower.inventories: 85 | print i 86 | i['organization'] = org_id 87 | inv = inv_res.create(**i) 88 | # create dynamic groups, static ones can be imported better with awx-manage 89 | if i.has_key('groups'): 90 | for g in i['groups']: 91 | print g 92 | g['inventory'] = inv['id'] 93 | # set the credential if this group has one 94 | if g.has_key('credential'): 95 | cred = cred_res.get(name=g['credential']) 96 | g['credential'] = cred['id'] 97 | group = group_res.create(**g) 98 | # sync the group if it has a credential 99 | if group.has_key('group'): 100 | id = group['group'] 101 | elif group.has_key('id'): 102 | id = group['id'] 103 | if g.has_key('credential'): 104 | group_res.sync(id) 105 | if g.has_key('hosts'): 106 | for h in g['hosts']: 107 | h['inventory'] = inv['id'] 108 | print h 109 | host = host_res.create(**h) 110 | host_res.associate(host['id'], group['id']) 111 | 112 | if tower.projects: 113 | # create projects 114 | print "\nCreating Projects\n" 115 | for p in tower.projects: 116 | print p 117 | p['organization'] = org_id 118 | project_res.create(**p) 119 | 120 | if tower.job_templates: 121 | print "Waiting 60 seconds for projects to index." 122 | print "Press any key to skip if you know what you're doing." 123 | timeout = 60 124 | rlist, wlist, xlist = select([sys.stdin], [], [], timeout) 125 | # create job templates 126 | print "\nCreating Job Templates\n" 127 | for j in tower.job_templates: 128 | print j 129 | cred = cred_res.get(name=j['machine_credential']) 130 | j['credential'] = cred['id'] 131 | inv = inv_res.get(name=j['inventory']) 132 | j['inventory'] = inv['id'] 133 | project = project_res.get(name=j['project']) 134 | j['project'] = project['id'] 135 | j['organization'] = org_id 136 | job_template_res.create(**j) 137 | 138 | 139 | 140 | 141 | 142 | 143 | --------------------------------------------------------------------------------