-
Notifications
You must be signed in to change notification settings - Fork 0
/
mkplaybook.py
executable file
·120 lines (102 loc) · 3.43 KB
/
mkplaybook.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python3
from yaml import safe_load, dump
from os.path import join, dirname
from os import listdir
from sys import exit
def role2task(name, config):
"""Converts a role to a playbook task.
Parameters:
name (str): Name of this role
config (dict): Dictionary containing roles.yml
Returns:
str:The role as Ansible playbook task
"""
hosts = [name]
tags = ['_{}'.format(name)]
if name in config:
if 'hosts' in config[name]:
hosts += config[name]['hosts']
if 'tags' in config[name]:
tags += config[name]['tags']
if 'all' in hosts:
hosts = ['all']
if 'excludes' in config[name]:
hosts += ['!{}'.format(e) for e in config[name]['excludes']]
return {
'name': 'Execute role {}'.format(role),
'hosts': hosts,
'become': True,
'roles': [name],
'gather_facts': False,
'tags': tags,
'pre_tasks': [{
'name': 'Gather facts',
'setup': {},
'when': 'not ansible_facts'
}]
}
def resolve(name, deps, allRoles, resolved, unresolved):
"""Resolves dependencies of a role recursively
Parameters:
name (str): Name of this role
deps (list of str): Names of dependencies of this role
allRoles (dict): Dictionary of all roles for finding deps
resolved (list of str): List of resolved role names
unresolved (list of str): List of unresolved role names
"""
unresolved.append(name)
if name in resolved:
return # Already resolved
for dep in deps:
found = False
if dep in resolved:
found = True
if not found:
if dep in unresolved:
print('Circular dependency: {} <-> {}'.format(name, dep))
exit(1)
resolve(dep, allRoles[dep], allRoles, resolved, unresolved)
resolved.append(name)
unresolved.remove(name)
if __name__ == '__main__':
config = {} # roles.yml contents
playbook = [] # Playbook to write
# These are dicts of dependency lists
earlyRoles = {} # Roles to execute at the beginning
roles = {} # Roles to execute in the middle
lateRoles = {} # Roles to execute in the end
# Read config
with open(join(dirname(__file__), '../roles.yml')) as configFile:
config = safe_load(configFile)
# Stat roles
for role in listdir(join(dirname(__file__), '../roles')):
early = False
late = False
after = []
if role in config:
if 'early' in config[role]:
early = config[role]['early']
if 'late' in config[role]:
late = config[role]['late']
if 'after' in config[role]:
after = config[role]['after']
if early and late:
print('Role {} has both early and late set'.format(role))
exit(1)
if early:
earlyRoles[role] = after
elif late:
lateRoles[role] = after
else:
roles[role] = after
# Resolve dependencies
resolved = []
for r in [earlyRoles, roles, lateRoles]:
for name, deps in r.items():
resolve(name, deps, r, resolved, [])
# Build playbook
for role in resolved:
playbook.append(role2task(role, config))
# Write out
with open(join(dirname(__file__), '../.playbook.yml'), 'w') as out:
out.write(dump(playbook, default_flow_style=False))