PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/silverlining/commands/create_node.py

https://bitbucket.org/ianb/silverlining/
Python | 125 lines | 105 code | 13 blank | 7 comment | 24 complexity | 4d06f8f57bcc7348e8535b2f4b4cbe5c MD5 | raw file
Possible License(s): GPL-2.0
  1. """Creates a new server/node"""
  2. import re
  3. import time
  4. from cmdutils import CommandError
  5. from silverlining.etchosts import set_etc_hosts
  6. from silversupport.shell import run
  7. #from silverlining.nodeset import NodeSet
  8. ESTIMATED_TIME = 60
  9. AFTER_PING_WAIT = 10
  10. def command_create_node(config):
  11. #if NodeSet.is_nodeset(config.args.node):
  12. # return command_create_nodeset(config)
  13. node_hostname = config.node_hostname
  14. node_exists = False
  15. if config.args.if_not_exists:
  16. config.logger.info('Checking if node %s exists' % node_hostname)
  17. for node in config.driver.list_nodes():
  18. if node.name == node_hostname:
  19. config.logger.notify('Node exists: %s' % node)
  20. node_exists = True
  21. break
  22. else:
  23. config.logger.info('No node by the name %s exists; continuing with create'
  24. % node_hostname)
  25. if not node_exists:
  26. config.logger.info('Getting image/size info')
  27. image = config.select_image(image_match=config.args.image)
  28. size = config.select_size(size_match=config.args.size)
  29. config.logger.notify('Creating node (image=%s; size=%s)' % (
  30. image.name, size.name))
  31. if not re.search(r'^[a-z0-9.-]+$', node_hostname):
  32. raise CommandError(
  33. "Invalid hostname (must contain only letters, numbers, ., and -): %r"
  34. % node_hostname)
  35. assert node_hostname
  36. resp = config.driver.create_node(
  37. name=node_hostname,
  38. image=image,
  39. size=size,
  40. ex_files={'/root/.ssh/authorized_keys': config.get('root_authorized_keys')},
  41. )
  42. public_ip = resp.public_ip[0]
  43. config.logger.notify('Status %s at IP %s' % (
  44. resp.state, public_ip))
  45. set_etc_hosts(config, [node_hostname], public_ip)
  46. if config.args.setup_node or config.args.wait:
  47. if not node_exists:
  48. wait_for_node_ready_ping(config, public_ip)
  49. config.logger.notify('Waiting %s seconds for full boot'
  50. % AFTER_PING_WAIT)
  51. time.sleep(AFTER_PING_WAIT)
  52. else:
  53. return
  54. if config.args.setup_node:
  55. from silverlining.commands.setup_node import command_setup_node
  56. config.args.node = node_hostname
  57. config.logger.notify('Setting up server')
  58. command_setup_node(config)
  59. def command_create_nodeset(config):
  60. nodeset = NodeSet(config.args.node)
  61. nodes = nodeset.nodes
  62. all_nodes = config.driver.list_nodes()
  63. for node_name, node_config in sorted(nodes.items()):
  64. for node in all_nodes:
  65. if node.name == node_name:
  66. config.logger.notify('Node exists: %s' % node_name)
  67. break
  68. else:
  69. create_node(config, node_name, node_config)
  70. def conditional_create_node(config, node_name, node_config):
  71. config.logger.info('Checking if node %s (%s) exists' % (node_name, node_config.create_node_type))
  72. def wait_for_node_ready(config, node_name):
  73. """Polls the server until it is ready"""
  74. ## FIXME: the Rackspace API is too slow to use this technique
  75. config.logger.start_progress('Waiting for server to be ready...')
  76. config.logger.debug('Waiting an initial %s seconds' % ESTIMATED_TIME)
  77. time.sleep(ESTIMATED_TIME)
  78. while 1:
  79. config.logger.show_progress()
  80. for node in config.driver.list_nodes():
  81. if node.name == node_name:
  82. if node.state == 'ACTIVE':
  83. active = True
  84. else:
  85. active = False
  86. break
  87. else:
  88. config.logger.warn(
  89. "No node with the name %s listed" % node_name)
  90. config.logger.warn(
  91. "Continuing, but this may not complete")
  92. time.sleep(10)
  93. config.logger.end_progress('server active.')
  94. def wait_for_node_ready_ping(config, node_hostname):
  95. """Poll a server via ping until it is ready"""
  96. start = time.time()
  97. config.logger.start_progress('Waiting for server to be ready...')
  98. config.logger.debug('Waiting an initial %s seconds' % ESTIMATED_TIME)
  99. time.sleep(ESTIMATED_TIME)
  100. while 1:
  101. config.logger.show_progress()
  102. stdout, stderr, returncode = run(
  103. ['ping', '-c', '2', '-w', '10', node_hostname],
  104. capture_stdout=True, capture_stderr=True)
  105. if returncode:
  106. config.logger.debug('Ping did not return successful result')
  107. else:
  108. config.logger.end_progress(
  109. "Server created (%s to create)" % format_time(time.time()-start))
  110. break
  111. def format_time(secs):
  112. return '%i:%02i' % (int(secs/60), int(secs)%60)