provision.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #!/usr/bin/env python
  2. import os
  3. import argparse
  4. import json
  5. import sys
  6. from string import Template
  7. from subprocess import call
  8. import tempfile
  9. import time
  10. STORAGE = '/opt/docker/etc/.registry/provision.json'
  11. PROVISION_DIR = '/opt/docker/provision/'
  12. PLAYBOOK_TAGS=['bootstrap', 'build', 'onbuild', 'entrypoint']
  13. PLAYBOOK = Template(
  14. """---
  15. - hosts: all
  16. vars_files:
  17. - ./variables-webdevops.yml
  18. - ./variables.yml
  19. roles:
  20. - $roles
  21. """)
  22. def readJson():
  23. ret = {}
  24. # create registry directory if it doesn't exists
  25. if not os.path.exists(os.path.dirname(STORAGE)):
  26. os.mkdir(os.path.dirname(STORAGE))
  27. # try to read file
  28. if os.path.isfile(STORAGE):
  29. f=open(STORAGE).read()
  30. ret = json.loads(f)
  31. return ret
  32. def saveJson(data):
  33. with open(STORAGE, 'w') as f:
  34. json.dump(data, f)
  35. def buildRoleList(tags):
  36. json = readJson()
  37. roleList = {}
  38. # fetch roles list for each tag
  39. for tag in tags:
  40. if tag in json:
  41. for role in json[tag]:
  42. roleRow = json[tag][role]
  43. if role not in roleList:
  44. roleList[role] = {}
  45. if 'tags' not in roleList[role]:
  46. roleList[role]['tags'] = {}
  47. roleList[role]['role'] = role
  48. roleList[role]['added'] = roleRow['added']
  49. roleList[role]['priority'] = roleRow['priority']
  50. roleList[role]['tags'][tag] = tag
  51. return roleList
  52. def buildSortedRoleList(tags):
  53. roleList = buildRoleList(tags)
  54. # sort list
  55. roleList = sorted(roleList, key=lambda x: (roleList[x]['priority'], roleList[x]['added']))
  56. return roleList
  57. def buildPlaybook(roleList):
  58. ## build playbook
  59. ret = PLAYBOOK.substitute(
  60. roles = "\n - ".join(roleList)
  61. )
  62. return ret
  63. def buildPlaybookFromArgs(args):
  64. roleList = []
  65. ## add roles from tag (if use registry is active)
  66. if args.useRegistry and args.tags:
  67. roleList.extend(buildSortedRoleList(args.tags))
  68. ## add roles from command arguments
  69. if args.roles:
  70. for role in args.roles:
  71. roleList.extend(role.split(','))
  72. if roleList:
  73. return buildPlaybook(roleList)
  74. else:
  75. return False
  76. def actionRun(args):
  77. if args.playbook:
  78. ## predefined playbook
  79. playbook = args.playbook
  80. else:
  81. ## dynamic playbook
  82. playbookContent = buildPlaybookFromArgs(args)
  83. if playbookContent:
  84. f = tempfile.NamedTemporaryFile(dir=PROVISION_DIR, prefix='playbook.', suffix='.yml', delete=False)
  85. f.write(playbookContent)
  86. f.close()
  87. playbook = f.name
  88. else:
  89. ## nothing to do
  90. sys.exit(0)
  91. ## build ansible command with args
  92. cmd = [
  93. 'ansible-playbook',
  94. playbook,
  95. '-i', 'localhost,',
  96. '--connection=local',
  97. ]
  98. if args.tags:
  99. cmd.extend([
  100. '--tags=' + ','.join(args.tags)
  101. ])
  102. if args.args:
  103. cmd.extend(args.args)
  104. ## run ansible
  105. retval = call(cmd)
  106. ## cleanup dynamic playbook
  107. if not args.playbook:
  108. os.unlink(playbook)
  109. sys.exit(retval)
  110. def actionPlaybook(args):
  111. playbook = buildPlaybookFromArgs(args)
  112. if playbook:
  113. print playbook
  114. else:
  115. sys.exit(1)
  116. def actionList(args):
  117. json = readJson()
  118. list = {}
  119. for tag in args.tags:
  120. if tag in json:
  121. for role in json[tag]:
  122. print role
  123. def actionAdd(args):
  124. json = readJson()
  125. for tag in args.tags:
  126. for role in args.role:
  127. if tag not in json:
  128. json[tag] = {}
  129. json[tag][role] = {
  130. 'name': role,
  131. 'added': int(time.time()),
  132. 'priority': args.priority
  133. }
  134. saveJson(json)
  135. def actionSummary(args):
  136. # list all roles in each possible tag
  137. for tag in PLAYBOOK_TAGS:
  138. roleList = buildRoleList([tag])
  139. if roleList:
  140. maxLength = len(max(roleList.keys(), key=len))
  141. print "Roles in " + tag + ":"
  142. for role in roleList:
  143. print ' - ' + role.ljust(maxLength, ' ') + ' [priority: ' + str(roleList[role]['priority']) + ']'
  144. print ''
  145. def main(args):
  146. actions = {
  147. 'list': actionList,
  148. 'add': actionAdd,
  149. 'summary': actionSummary,
  150. 'playbook': actionPlaybook,
  151. 'run': actionRun
  152. }
  153. func = actions.get(args.action, lambda: "nothing")
  154. return func(args)
  155. if __name__ == '__main__':
  156. parser = argparse.ArgumentParser()
  157. subparsers = parser.add_subparsers(
  158. title='subcommands',
  159. dest='action'
  160. )
  161. ###################################
  162. ## SUMMARY command
  163. summary = subparsers.add_parser('summary')
  164. ###################################
  165. ## RUN command
  166. run = subparsers.add_parser('run')
  167. run.add_argument(
  168. '--tag',
  169. dest='tags',
  170. choices=PLAYBOOK_TAGS,
  171. required=True,
  172. action='append',
  173. help='Ansible tag'
  174. )
  175. run.add_argument(
  176. '--playbook',
  177. dest='playbook',
  178. help='Ansible playbook'
  179. )
  180. run.add_argument(
  181. '--use-registry',
  182. dest='useRegistry',
  183. action='store_true',
  184. help='Use registred roles'
  185. )
  186. run.add_argument(
  187. '--role',
  188. dest='roles',
  189. action='append',
  190. help='Ansible role'
  191. )
  192. run.add_argument('args', nargs=argparse.REMAINDER)
  193. ###################################
  194. ## PLAYBOOK command
  195. playbook = subparsers.add_parser('playbook')
  196. playbook.add_argument(
  197. '--tag',
  198. dest='tags',
  199. choices=PLAYBOOK_TAGS,
  200. required=True,
  201. action='append',
  202. help='Ansible tag'
  203. )
  204. playbook.add_argument(
  205. '--use-registry',
  206. dest='useRegistry',
  207. action='store_true',
  208. help='Use registred roles'
  209. )
  210. playbook.add_argument(
  211. '--role',
  212. dest='roles',
  213. action='append',
  214. help='Ansible tag'
  215. )
  216. playbook.add_argument('args', nargs=argparse.REMAINDER)
  217. ###################################
  218. ## LIST command
  219. list = subparsers.add_parser('list')
  220. list.add_argument(
  221. '--tag',
  222. dest='tags',
  223. choices=PLAYBOOK_TAGS,
  224. required=True,
  225. action='append',
  226. help='Ansible tag'
  227. )
  228. list.add_argument('args', nargs=argparse.REMAINDER)
  229. ###################################
  230. ## ADD command
  231. add = subparsers.add_parser('add')
  232. add.add_argument(
  233. '--tag',
  234. dest='tags',
  235. choices=PLAYBOOK_TAGS,
  236. required=True,
  237. action='append',
  238. help='Ansible tag'
  239. )
  240. add.add_argument(
  241. '--priority',
  242. type=int,
  243. default=100,
  244. dest='priority',
  245. help='Priority for role [default 100, 1 is most important]'
  246. )
  247. add.add_argument('role', metavar='roles', nargs='+', help='Ansible roles')
  248. add.add_argument('args', nargs=argparse.REMAINDER)
  249. ## Execute
  250. args = parser.parse_args()
  251. main(args)