PageRenderTime 26ms CodeModel.GetById 9ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/silverlining/commands/create_node.py

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