Exemple #1
0
def lookup(appname, *vms):
    """lookup(appname, *vms)

    Lookup the addresses for virtual machines in a Ravello application.

    The *appname* parameter must be the name of the application. After this
    parameter you may pass one or multiple positional arguments containing the
    VM names. If the VMs are not specified, all VMs in the application are
    selected. The first VM argument may also be a sequence, set or mapping
    containing VM names.

    The return value is a list of Fabric host strings, and may be directly
    assigned to *env.hosts*.
    """
    app = cache.get_application(name=appname)
    if app is None:
        error.raise_error("Application `{0}` does not exist.", appname)
    if isinstance(vms, compat.str):
        vms = [vms]
    app = cache.get_application(app['id'])
    hosts = []
    for vm in app.get('vms', []):
        if vms and vm['name'] not in vms:
            continue
        host = vm['dynamicMetadata']['externalIp']
        if fab.env.ravello_user:
            host = '{0}@{1}'.format(fab.env.ravello_user, host)
        hosts.append(host)
    return hosts
Exemple #2
0
 def check(path, check):
     try:
         validate.validate_node(manifest, path, check)
     except validate.ValidationError as e:
         path = validate.pathref(e[1])
         error.raise_error('{0}: {1}: {2}',
                     manifest.get('_filename', '<dict>'), path, e[0])
Exemple #3
0
def start_application(name, wait=True, show_progress=True, timeout=1200):
    """start_application(name, wait=True, show_progress=True, timeout=1200)

    Start up an application.

    The *name* argument must be the name of an application. If *wait* is
    nonzero, then this function will wait until the application is up and its
    VMs are accessible via ssh. If *show_progress* is nonzero then a progress
    bar is shown.  The *timeout* argument specifies the timeout in seconds.
    The default timeout is 20 minutes. Application startup times vary greatly
    between clouds, and whether or not the application has already been
    published.

    This method will start all VMs in the application that are in the 'STOPPED'
    state. If *wait* is nonzero, then all VMs must either be in the 'STOPPED'
    state (in which case they will get started), in the 'STARTED' state (in
    which case there is nothing to do), or in a state that will eventually
    transition to 'STARTED' state (currently 'STARTING' and 'PUBLISHING'). If a
    VM is in another state, then no action is taken and an exception is raised,
    because this call would just timeout without the ability to complete.

    This function has no return value, and raises an exception in case of an
    error.
    """
    app = cache.get_application(name=name)
    if app is None:
        error.raise_error("Application `{0}` does not exist.", name)
    app = application.start_application(app)
    if wait:
        state = application.get_application_state(app)
        if state not in application.vm_reuse_states:
            error.raise_error("Cannot wait for app in state '{0}'.", state)
        vms = set((vm['name'] for vm in app['vms']))
        with env.let(quiet=not show_progress):
            application.wait_for_application(app, vms, timeout)
Exemple #4
0
 def remote_checkout(self, version):
     repotype = env.manifest['repository']['type']
     if not repotype:
         error.raise_error('Unknown repository type, cannot checkout.')
     url = env.manifest['repository']['url']
     commands = versioncontrol.get_checkout_command(url, version, repotype)
     super(DeployTask, self).run(commands=commands)
Exemple #5
0
def create_archive():
    ravello_dir = util.get_ravello_dir()
    try:
        st = os.stat(ravello_dir)
    except OSError:
        st = None
    if st and not stat.S_ISDIR(st.st_mode):
        error.raise_error("Path `{0}` exists but is not a directory.",
                          ravello_dir)
    elif st is None:
        os.mkdir(ravello_dir)
    distfile = os.path.join(ravello_dir, 'dist.tar.gz')
    try:
        st = os.stat(distfile)
    except OSError:
        st = None
    if st and st.st_mtime >= env.start_time:
        return distfile
    archive = tarfile.TarFile.open(distfile, 'w:gz')
    repotype = env.manifest['repository']['type']
    files = versioncontrol.walk_repository('.', repotype)
    for fname in files:
        if fname.startswith(ravello_dir):
            continue
        archive.add(fname, recursive=False)
    archive.close()
    return distfile
Exemple #6
0
def create_blueprint(name, bpname=None, wait=True):
    """create_blueprint(name, bpname=None)

    Create a blueprint from an application.

    The *name* argument must be an application whose VMs are either all in
    the STOPPED or in the STARTED state.  The *bpname* argument is the name
    of the blueprint. If the blueprint name is not specified, a new unique name
    will be allocated.

    The return value of this function is the name of the blueprint that was
    created.
    """
    app = cache.get_application(name=name)
    if app is None:
        error.raise_error("Application `{0}` does not exist.", name)
    state = application.get_application_state(app)
    if state not in ('STOPPED', 'STARTED'):
        error.raise_error('Application `{0}` is currently in state {1}.\n'
                          'Can only save when STOPPED or STARTED.',
                          name, state)
    if bpname is None:
        bpname = new_blueprint_name('bp-{0}'.format(name))
    bp = application.create_blueprint(bpname, app)
    if wait:
        bp = application.wait_until_blueprint_is_in_state(bp, 'DONE')
    return application.appdef_from_app(bp)
Exemple #7
0
def synchronize_on_task(taskname, timeout=600):
    """Wait until all instances of ``taskname`` have completed.
    Returns a dictionary with the shared state of the VMs that
    were waited for.
    """
    waitfor = set()
    for vmdef in env.appdef['vms']:
        if vmdef['name'] not in env.vms:
            continue
        for taskdef in vmdef['tasks']:
            if taskdef['name'] == taskname:
                waitfor.add(vmdef['name'])
    state = {}
    end_time = time.time() + timeout
    while True:
        for vmdef in env.appdef['vms']:
            vmname = vmdef['name']
            vmstate = env.shared_state[vmname]  # resync
            if vmstate['exited']:
                state[vmname] = vmstate
                break
            if vmname not in waitfor:
                continue
            if taskname in vmstate['completed_tasks']:
                waitfor.remove(vmname)
                state[vmname] = vmstate
        if vmstate['exited'] or not waitfor:
            break
        console.debug('Waiting for %s' % repr(waitfor))
        time.sleep(5)
        if time.time() > end_time:
            error.raise_error("Timeout waiting for task `{0}`.", taskname)
    return state
Exemple #8
0
def create_application(name=None, blueprint=None, vms=None, cloud=None,
                       region=None, wait=True, show_progress=True):
    """create_application(name=None, blueprint=None, vms=None, cloud=None, \
            region=None, wait=True, show_progress=True)

    Create a new application.

    If *blueprint* is specified, then it must be the name of a blueprint from
    which the application is created. If *blueprint* is not specified, then an
    application will be created from scratch in which case *vms* needs to be
    specified containing a list of the VM definitions. The VM definitions are
    dictionaries containing string keys describing the VM. The arguments
    *cloud* and *region* specify which cloud and region to publish the
    application to.  If these are not specified, the application is published
    to the lowest cost cloud that fits the VM definitions. If *wait* is
    nonzero, then this function will wait until the application is started up
    and its VMs are accessible via ssh.  If *show_progress* is nonzero, then a
    progress bar is shown.

    The return value of this function is the application definition of the
    application that was created. In case of an error, an exception is raised.

    .. seealso::
       See :ref:`vm-ref` for the possible keys in a VM definition dictionary.
    """
    if blueprint:
        bp = cache.get_blueprint(name=blueprint)
        if bp is None:
            error.raise_error('Blueprint `{0}` not found.', blueprint)
        if name is None:
            name = new_application_name(bp['name'])
    else:
        if name is None:
            name = new_application_name()
    appdef = { 'name': name }
    if vms:
        appdef['vms'] = vms
    if blueprint:
        appdef['blueprint'] = blueprint
    manif = { 'applications': [appdef],
              'defaults': { 'vms': { 'smp': 1, 'memory': 2048 } } }
    manifest.check_manifest(manif)
    manifest.percolate_defaults(manif)
    manifest.check_manifest_entities(manif)
    app = application.create_new_application(appdef, False)
    app = application.publish_application(app, cloud, region)
    if wait:
        vms = set((vm['name'] for vm in app['vms']))
        with env.let(quiet=not show_progress):
            app = application.wait_for_application(app, vms)
    return application.appdef_from_app(app)
Exemple #9
0
def default_application(appname):
    """The default application loading function."""
    parts = appname.split(':')
    if len(parts) in (1, 2) and env.manifest is None:
        error.raise_error('No manifest found ({0}).\n'
                          'Please specify the fully qualified app name.\n'
                          "Use 'ravtest ps -a' for a list.",
                          manifest.manifest_name())
    if len(parts) in (1, 2):
        project = env.manifest['project']['name']
        console.info('Project name is `{0}`.', project)
        defname = parts[0]
        instance = parts[1] if len(parts) == 2 else None
    elif len(parts) == 3:
        project, defname, instance = parts
    else:
        error.raise_error('Illegal application name: `{0}`.', appname)
    apps = cache.find_applications(project, defname, instance)
    if len(apps) == 0:
        error.raise_error('No instances of application `{0}` exist.',
                          defname)
    elif len(apps) > 1:
        error.raise_error('Multiple instances of `{0}` exist.\n'
                          'Use `ravtest ps` to list the instances and then\n'
                          'specify the application with its instance id.',
                          defname)
    app = cache.get_application(apps[0]['id'])
    return app
Exemple #10
0
def create_keypair():
    """Create a new keypair and upload it to Ravello."""
    cfgdir = util.get_config_dir()
    privname = os.path.join(cfgdir, 'id_ravello')
    pubname = privname + '.pub'
    keyname = 'ravello@%s' % socket.gethostname()
    # Prefer to generate the key locallly with ssh-keygen because
    # that gives us more privacy. If ssh-keygen is not available, ask
    # for a key through the API.
    sshkeygen = util.which('ssh-keygen')
    if sshkeygen:
        try:
            console.info("Generating keypair using 'ssh-keygen'...")
            subprocess.call(['ssh-keygen', '-q', '-t', 'rsa', '-C', keyname,
                             '-b', '2048', '-N', '', '-f', privname])
        except subprocess.CalledProcessError as e:
            error.raise_error('ssh-keygen returned with error status {0}',
                              e.returncode)
        with file(pubname) as fin:
            pubkey = fin.read()
        keyparts = pubkey.strip().split()
    else:
        keyname = 'ravello@api-generated'
        console.info('Requesting a new keypair via the API...')
        keypair = env.api.create_keypair()
        with file(privname, 'w') as fout:
            fout.write(keypair['privateKey'])
        with file(pubname, 'w') as fout:
            fout.write(keypair['publicKey'].rstrip())
            fout.write(' {0} (generated remotely)\n'.format(keyname))
        pubkey = keypair['publicKey'].rstrip()
        keyparts = pubkey.split()
        keyparts[2:] = [keyname]
    # Create the pubkey in the API under a unique name
    pubkeys = env.api.get_pubkeys()
    keyname = util.get_unused_name(keyname, pubkeys)
    keyparts[2] = keyname
    keydata = '{0} {1} {2}\n'.format(*keyparts)
    pubkey = {'name': keyname}
    pubkey['publicKey'] = keydata
    pubkey = env.api.create_pubkey(pubkey)
    with file(pubname, 'w') as fout:
        fout.write(keydata)
    env.public_key = pubkey
    env.private_key_file = privname
    return pubkey
Exemple #11
0
def wait_until_blueprint_is_in_state(bp, state, timeout=None,
                                     poll_timeout=None):
    """Wait until a blueprint is in a given state."""
    if timeout is None:
        timeout = 300
    if poll_timeout is None:
        poll_timeout = 5
    end_time = time.time() + timeout
    while True:
        if time.time() > end_time:
            break
        poll_end_time = time.time() + poll_timeout
        bp = cache.get_blueprint(bp['id'], force_reload=True)
        bpstate = get_blueprint_state(bp)
        if bpstate == state:
            return bp
        time.sleep(max(0, poll_end_time - time.time()))
    error.raise_error("Blueprint `{0}` did not reach state '{1}' within "
                      "{2} seconds.", bp['name'], state, timeout)
    return bp
Exemple #12
0
def do_save(args, env):
    """The "ravello save" command."""

    with env.let(quiet=True):
        login.default_login()
        keypair.default_keypair()
        manif = manifest.default_manifest(required=False)

    app = application.default_application(args.application)
    appname = app["name"]
    project, defname, instance = appname.split(":")

    state = application.get_application_state(app)
    if state not in ("STOPPED", "STARTED"):
        error.raise_error(
            "Application `{0}:{1}` is currently in state {2}.\n" "Can only create blueprint when STOPPED or STARTED.",
            defname,
            instance,
            state,
        )

    if state == "STARTED" and not env.always_confirm:
        console.info("Application `{0}:{1}` is currently running.", defname, instance)
        result = console.confirm("Do you want to continue with a live snapshot")
        if not result:
            console.info("Not confirmed.")
            return error.EX_OK

    template = "{0}:{1}".format(project, defname)
    bpname = util.get_unused_name(template, cache.get_blueprints())
    parts = bpname.split(":")

    console.info("Saving blueprint as `{0}:{1}`.", parts[1], parts[2])

    blueprint = env.api.create_blueprint(bpname, app)
    env.blueprint = blueprint  # for tests

    console.info("Blueprint creation process started.")
    console.info("Use 'ravtest ps -b' to monitor progress.")

    return error.EX_OK
Exemple #13
0
def wait_until_application_is_in_state(app, state, timeout=None,
                                       poll_timeout=None):
    """Wait until an application is in a given state."""
    if timeout is None:
        timeout = 900
    if poll_timeout is None:
        poll_timeout = 10
    end_time = time.time() + timeout
    while True:
        if time.time() > end_time:
            break
        poll_end_time = time.time() + poll_timeout
        app = cache.get_application(app['id'], force_reload=True)
        appstate = get_application_state(app)
        if appstate == state:
            return app
        console.show_progress(appstate[0])
        time.sleep(max(0, poll_end_time - time.time()))
    error.raise_error("Application `{0}` did not reach state '{1}' within "
                      "{2} seconds.", app['name'], state, timeout)
    return app
Exemple #14
0
def load_manifest(filename=None):
    """Load the project manifest, merge in the default manifest,
    and return the result."""
    if filename is None:
        filename = manifest_name()
    if not manifest_exists(filename):
        error.raise_error('Project manifest ({0}) not found.', filename)
    with file(filename) as fin:
        try:
            manifest = yaml.load(fin)
        except yaml.error.YAMLError as e:
            if env.verbose:
                error.raise_error('Illegal YAML in manifest.\n'
                                  'Message from parser: {!s}', e)
            else:
                error.raise_error('Illegal YAML in manifest.\n'
                                  'Try --verbose for more information.')
    manifest['_filename'] = filename
    directory, _ = os.path.split(os.path.abspath(filename))
    _, project = os.path.split(directory)
    manifest['_directory'] = directory
    packagedir = testmill.packagedir()
    filename = os.path.join(packagedir, 'defaults.yml')
    with file(filename) as fin:
        defaults = yaml.load(fin)
    merge(defaults, manifest)
    env.manifest = manifest
    return manifest
Exemple #15
0
def load_keypair():
    """Try to load a keypair that exists in ~/.ravello."""
    cfgdir = util.get_config_dir()
    privname = os.path.join(cfgdir, 'id_ravello')
    try:
        st = os.stat(privname)
    except OSError:
        return
    if not stat.S_ISREG(st.st_mode):
        error.raise_error("Private key {0} is not a regular file.", pivname)
    pubname = privname + '.pub'
    try:
        st = os.stat(pubname)
    except OSError:
        st = None
    if st is None:
        error.raise_error("Public key {0} does not exist.", pubname)
    elif not stat.S_ISREG(st.st_mode):
        error.raise_error("Public key {0} is not a regular file.", pubname)
    with file(pubname) as fin:
        pubkey = fin.read()
    keyparts = pubkey.strip().split()
    pubkeys = env.api.get_pubkeys()
    for pubkey in pubkeys:
        if pubkey['name'] == keyparts[2]:
            env.public_key = pubkey
            env.private_key_file = privname
            return pubkey
Exemple #16
0
def stop_application(name, wait=True, timeout=300):
    """stop_application(name)

    Stop an application with name *name*.

    This method will stop all VMs in the application that are currently in the
    'STARTED' state. VMs other states are not touched.
    
    The application may not be fully stopped even after this call. For example,
    if a VM is in the 'STARTING' state, it will eventually transition to
    'STARTED'. But a 'STARTNG' VM cannot be stopped before it reaches the
    'STARTED' state.
    """
    app = cache.get_application(name=name)
    if app is None:
        error.raise_error("Application `{0}` does not exist.", name)
    app = application.stop_application(app)
    if wait:
        state = application.get_application_state(app)
        if state not in ('STARTED', 'STOPPING', 'STOPPED'):
            error.raise_error("Cannot wait for app in state '{0}',", state)
        application.wait_until_application_is_in_state(app, 'STOPPED', timeout)
Exemple #17
0
def do_run(args, env):
    """The "ravello run" command."""
    login.default_login()
    keypair.default_keypair()
    manif = manifest.default_manifest()

    appname = args.application
    for appdef in manif.get('applications', []):
        if appdef['name'] == appname:
            break
    else:
        error.raise_error("Unknown application `{0}`.", appname)

    vms = set((vm['name'] for vm in appdef.get('vms', [])))
    if args.vms:
        only = set((name for name in args.vms.split(',')))
        if not only <= vms:
            unknown = [name for name in only if name not in vms]
            what = inflect.plural_noun('virtual machine', len(unknown))
            error.raise_error("Unknown {0}: {1}", ', '.join(unknown), what)
        vms = [name for name in vms if name in only]
    if not vms:
        error.raise_error('No virtual machines in application.')

    app = application.create_or_reuse_application(appdef, args.new)
    app = application.wait_for_application(app, vms)

    if args.command:
        for vm in appdef['vms']:
            for task in vm['tasks']:
                if task['name'] == 'execute':
                    task['commands'] = [args.command]
    elif args.dry_run:
        for vm in appdef['vms']:
            vm['tasks'] = []

    ret = tasks.run_all_tasks(app, vms)

    console.info('\n== The following services will be available for {0} '
                 'minutes:\n', appdef['keepalive'])

    for vm in app['vms']:
        if vm['name'] not in vms:
            continue
        svcs = vm.get('suppliedServices')
        if not svcs:
            continue
        console.info('On virtual machine `{0}`:', vm['name'])
        for svc in svcs:
            svc = svc['baseService']
            addr = util.format_service(vm, svc)
            console.info('    * {0}: {1}', svc['name'], addr)
        console.info('')

    return error.EX_OK if ret == 0 else error.EX_SOFTWARE
Exemple #18
0
def do_ssh(args, env):
    """The "ravello ssh" command."""

    with env.let(quiet=True):
        login.default_login()
        keypair.default_keypair()

    if manifest.manifest_exists():
        with env.let(quiet=True):
            manif = manifest.default_manifest()
    else:
        manif = None

    parts = args.application.split(':')
    if len(parts) in (1, 2) and manif is None:
        error.raise_error('No manifest found ({0}).\n'
                          'Please specify the fully qualified app name.\n'
                          'Use `ravtest ps --all` for a list.',
                          manifest.manifest_name())
    if len(parts) in (1, 2):
        project = manif['project']['name']
        console.info('Project name is `{0}`.', project)
        defname = parts[0]
        instance = parts[1] if len(parts) == 2 else None
    elif len(parts) == 3:
        project, defname, instance = parts
    else:
        error.raise_error('Illegal application name: `{0}`.', appname)

    apps = cache.find_applications(project, defname, instance)
    if len(apps) == 0:
        error.raise_error('No instances of application `{0}` exist.',
                          defname)
    elif len(apps) > 1:
        error.raise_error('Multiple instances of `{0}` exist.\n'
                          'Use `ravtest ps` to list the instances and then\n'
                          'specify the application with its instance id.',
                          defname)
    app = cache.get_application(apps[0]['id'])
    appname = app['name']
    _, _, instance = appname.split(':')

    vmname = args.vm
    vm = application.get_vm(app, vmname)
    if vm is None:
        error.raise_error('Application `{0}:{1}` has no VM named `{2}`.\n'
                          'Use `ravtest ps --full` to see a list of VMs.',
                          defname, instance, vmname)
    console.info("Connecting to VM `{0}` of application `{1}:{2}`...",
                 vmname, defname, instance)

    # Start up the application and wait for it if we need to.

    state = application.get_application_state(app)
    if state not in ('PUBLISHING', 'STARTING', 'STOPPED', 'STARTED'):
        error.raise_error("VM `{0}` is in an unknown state.", vmname)

    userdata = vm.get('customVmConfigurationData', {})
    vmkey = userdata.get('keypair', {})

    if vmkey.get('id') != env.public_key['id']:
        error.raise_error("VM uses unknown public key `{0}`.",
                          vmkey.get('name'))

    application.start_application(app)
    application.wait_for_application(app, [vmname])

    # Now run ssh. Prefer openssh but fall back to using Fabric/Paramiko.

    host = 'ravello@{0}'.format(vm['dynamicMetadata']['externalIp'])
    command = '~/bin/run {0}'.format(args.testid)

    openssh = util.find_openssh()
    interactive = os.isatty(sys.stdin.fileno())

    if interactive and openssh:
        if not sys.platform.startswith('win'):
            # On Unix use execve(). This is the most efficient.
            argv = ['ssh', '-i', env.private_key_file,
                    '-o', 'UserKnownHostsFile=/dev/null',
                    '-o', 'StrictHostKeyChecking=no',
                    '-o', 'LogLevel=quiet',
                    '-t',  host, command]
            console.debug('Starting {0}', ' '.join(argv))
            os.execve(openssh, argv, os.environ)
        else:
            # Windows has execve() but for some reason it does not work
            # well with arguments with spaces in it. So use subprocess
            # instead.
            command = [openssh, '-i', env.private_key_file,
                       '-o', 'UserKnownHostsFile=NUL',
                       '-o', 'StrictHostKeyChecking=no',
                       '-o', 'LogLevel=quiet',
                       '-t', host, command]
            ssh = subprocess.Popen(command)
            ret = ssh.wait()
            error.exit(ret)

    # TODO: should also support PuTTY on Windows

    console.info(textwrap.dedent("""\
            Warning: no local openssh installation found.
            Falling back to Fabric/Paramiko for an interactive shell.
            However, please note:

            * CTRL-C and terminal resize signals may not work.
            * Output of programs that repaint the screen may
              be garbled (e.g. progress bars).
            """))

    fab.env.host_string = host
    fab.env.key_filename = env.private_key_file
    fab.env.disable_known_hosts = True
    fab.env.remote_interrupt = True
    fab.env.output_prefix = None
    fabric.state.output.running = None
    fabric.state.output.status = None

    ret = fab.run(command, warn_only=True)
    return ret.return_code
Exemple #19
0
def wait_until_application_accepts_ssh(app, vms, timeout=None,
                                       poll_timeout=None):
    """Wait until an application is reachable by ssh.

    An application is reachable by SSH if all the VMs that have a public key in
    their userdata are connect()able on port 22. 
    """
    if timeout is None:
        timeout = 300
    if poll_timeout is None:
        poll_timeout = 5
    waitaddrs = set((vm['dynamicMetadata']['externalIp']
                     for vm in app['vms'] if vm['name'] in vms))
    aliveaddrs = set()
    end_time = time.time() + timeout
    # For the intricate details on non-blocking connect()'s, see Stevens,
    # UNIX network programming, volume 1, chapter 16.3 and following.
    while True:
        if time.time() > end_time:
            break
        waitfds = {}
        for addr in waitaddrs:
            sock = socket.socket()
            sock.setblocking(False)
            try:
                sock.connect((addr, 22))
            except socket.error as e:
                if e.errno not in nb_connect_errors:
                    console.debug('connect(): errno {.errno}'.format(e))
                    continue
            waitfds[sock.fileno()] = (sock, addr)
        poll_end_time = time.time() + poll_timeout
        while True:
            timeout = poll_end_time - time.time()
            if timeout < 0:
                for fd in waitfds:
                    sock, _ = waitfds[fd]
                    sock.close()
                break
            try:
                wfds = list(waitfds)
                _, wfds, _ = select.select([], wfds, [], timeout)
            except select.error as e:
                if e.args[0] == errno.EINTR:
                    continue
                console.debug('select(): errno {.errno}'.format(e))
                raise
            for fd in wfds:
                assert fd in waitfds
                sock, addr = waitfds[fd]
                try:
                    err = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
                except socket.error as e:
                    err = e.errno
                sock.close()
                if not err:
                    aliveaddrs.add(addr)
                    waitaddrs.remove(addr)
                del waitfds[fd]
            if not waitfds:
                break
        if not waitaddrs:
            return
        console.show_progress('C')  # 'C' = Connecting
        time.sleep(max(0, poll_end_time - time.time()))
    unreachable = set((vm['name'] for vm in app['vms']
                       if vm['dynamicMetadata']['externalIp'] in waitaddrs))
    noun = inflect.plural_noun('VM', len(unreachable))
    vmnames = '`{0}`'.format('`, `'.join(sorted(unreachable)))
    error.raise_error('{0} `{1}` did not become reachable within {2} seconds.',
                      noun, vmnames, timeout)
Exemple #20
0
def run_all_tasks(app, vms):
    """Run the runbook for an application ``app``."""
    hosts = []
    host_info = {}
    appname = app['name'].split(':')[1]
    for appdef in env.manifest['applications']:
        if appdef['name'] == appname:
            break
    else:
        error.raise_error('Application definition not found?')

    for vm in app['vms']:
        if vm['name'] not in vms:
            continue
        ipaddr = vm['dynamicMetadata']['externalIp']
        hosts.append(ipaddr)
        host_info[ipaddr] = vm['name']

    env.test_id = os.urandom(16).encode('hex')
    console.info('Starting run `{0}`.', env.test_id)
    env.host_info = host_info
    env.start_time = int(time.time())
    env.lock = multiprocessing.Lock()
    manager = multiprocessing.Manager()
    env.shared_state = manager.dict()
    for vmname in vms:
        vmstate = {}
        vmstate['exited'] = False
        vmstate['completed_tasks'] = {}
        vmstate['shell_env_update'] = {}
        env.shared_state[vmname] = vmstate
    env.appdef = appdef
    env.application = app
    env.vms = vms

    fab.env.user = '******'
    fab.env.key_filename = env.private_key_file
    fab.env.disable_known_hosts = True
    fab.env.remote_interrupt = True
    fab.env.hosts = hosts
    fab.env.parallel = True
    fab.env.output_prefix = env.debug
    fabric.state.output.running = env.debug
    fabric.state.output.output = True
    fabric.state.output.status = env.debug

    # This is where it all happens...
    noun = inflect.plural_noun('virtual machine', len(vms))
    console.info('Executing tasks on {0} {1}...', len(vms), noun)

    fabric.tasks.execute(run_tasklist, env)

    errors = set()
    for vmname in vms:
        vmstate = env.shared_state[vmname]
        for taskname,status in vmstate['completed_tasks'].items():
            if status != 0:
                errors.add('`{0}` on `{1}`'.format(taskname, vmname))

    if not errors:
        console.info('All tasks were executed succesfully!')
    else:
        what = inflect.plural_noun('task', len(errors))
        errapps = ', '.join(errors)
        console.error('The following {0} failed: {1}', what, errapps)

    fabric.network.disconnect_all()
    return len(errors)
Exemple #21
0
def do_ps(args, env):
    """The "ravello ps" command."""
    with env.let(quiet=True):
        login.default_login()
        pubkey = keypair.default_keypair()
        manif = manifest.default_manifest(required=False)

    if manif is None and not args.all:
        error.raise_error('Project manifest ({0}) not found.\n'
                          "Use 'ravtest ps -a' to list all applications.",
                          manifest.manifest_name())
    if args.all:
        project = None
    else:
        project = manif['project']['name']
        console.info('Project name is `{0}`.', project)
    
    if args.blueprint:
        apps = cache.find_blueprints(project)
        what = 'blueprint'
    else:
        apps = cache.find_applications(project)
        what = 'application'

    apps = sorted(apps, key=lambda app: app['name'])
    objs = inflect.plural_noun(what)
    console.writeln('Currently available {0}:\n', objs)

    current_project = None
    for app in apps:
        parts = app['name'].split(':')
        if parts[0] != project and not args.all:
            continue
        if args.all and current_project != parts[0]:
            console.writeln("== Project: `{0}`", parts[0])
            current_project = parts[0]
        if args.full and not args.blueprint:
            app = cache.get_application(app['id'])

        cloud = app.get('cloud')
        region = app.get('regionName')
        started = app.get('totalStartedVms')
        publish_time = app.get('publishStartTime')
        creation_time = app.get('creationTime')
        created = publish_time or creation_time
        if created:
            now = time.time()
            created = util.format_timedelta(now - created/1000)
            created = '{0} ago'.format(created)
        else:
            created = ''
        if args.full and not args.blueprint:
            vms = [ vm['name'] for vm in application.get_vms(app) ]
            vms = '`{0}`'.format('`, `'.join(vms))
            state = application.get_application_state(app)
        else:
            state = app.get('state') or ''

        console.writeln('=== {0}: `{1}:{2}`', what.title(), parts[1], parts[2])
        what2 = inflect.plural_noun('VM', started)
        if state:
            console.writeln('    state: {0}', state)
        if started is not None:
            console.writeln('    {0} {1} running', started, what2)
        if cloud is not None:
            console.writeln('    published to {0}/{1}', cloud, region)
        if created:
            console.writeln('    created: {0}', created)
        if args.full and not args.blueprint:
            console.writeln('    VMs: {0}', vms)
        console.writeln()

    return error.EX_OK