Exemplo n.º 1
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)
Exemplo n.º 2
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
Exemplo n.º 3
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)
Exemplo n.º 4
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