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