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)
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)
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
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)
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
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