utils.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import codecs
  2. import hashlib
  3. import json
  4. import logging
  5. import sys
  6. from docker.errors import APIError
  7. from Queue import Queue, Empty
  8. from threading import Thread
  9. log = logging.getLogger(__name__)
  10. def parallel_execute(command, containers, doing_msg, done_msg, **options):
  11. """
  12. Execute a given command upon a list of containers in parallel.
  13. """
  14. stream = codecs.getwriter('utf-8')(sys.stdout)
  15. lines = []
  16. errors = {}
  17. for container in containers:
  18. write_out_msg(stream, lines, container.name, doing_msg)
  19. q = Queue()
  20. def container_command_execute(container, command, **options):
  21. try:
  22. getattr(container, command)(**options)
  23. except APIError as e:
  24. errors[container.name] = e.explanation
  25. q.put(container)
  26. for container in containers:
  27. t = Thread(
  28. target=container_command_execute,
  29. args=(container, command),
  30. kwargs=options,
  31. )
  32. t.daemon = True
  33. t.start()
  34. done = 0
  35. while done < len(containers):
  36. try:
  37. container = q.get(timeout=1)
  38. write_out_msg(stream, lines, container.name, done_msg)
  39. done += 1
  40. except Empty:
  41. pass
  42. if errors:
  43. for container in errors:
  44. stream.write("ERROR: for {} {} \n".format(container, errors[container]))
  45. def write_out_msg(stream, lines, container_name, msg):
  46. """
  47. Using special ANSI code characters we can write out the msg over the top of
  48. a previous status message, if it exists.
  49. """
  50. if container_name in lines:
  51. position = lines.index(container_name)
  52. diff = len(lines) - position
  53. # move up
  54. stream.write("%c[%dA" % (27, diff))
  55. # erase
  56. stream.write("%c[2K\r" % 27)
  57. stream.write("{}: {} \n".format(container_name, msg))
  58. # move back down
  59. stream.write("%c[%dB" % (27, diff))
  60. else:
  61. diff = 0
  62. lines.append(container_name)
  63. stream.write("{}: {}... \r\n".format(container_name, msg))
  64. stream.flush()
  65. def json_hash(obj):
  66. dump = json.dumps(obj, sort_keys=True, separators=(',', ':'))
  67. h = hashlib.sha256()
  68. h.update(dump)
  69. return h.hexdigest()