def shutdown(self, wait=True): """Shutdown instance.""" if self.pid: # This relies on _execute which uses sudo over ssh. The ssh # connection would get killed before sudo exited, so ignore errors. cmd = ['shutdown', 'now'] try: self._execute(cmd) except util.InTargetExecuteError: pass self._ssh_close() if wait: LOG.debug("Executed shutdown. waiting on pid %s to end", self.pid) time_for_shutdown = 120 give_up_at = time.time() + time_for_shutdown pid_file_path = '/proc/%s' % self.pid msg = ("pid %s did not exit in %s seconds after shutdown." % (self.pid, time_for_shutdown)) while True: if not os.path.exists(pid_file_path): break if time.time() > give_up_at: raise util.PlatformError("shutdown", msg) self.pid = None
def start(self, wait=True, wait_for_cloud_init=False): """Start instance on EC2 with the platfrom's VPC.""" if self.instance: if self.instance.state['Name'] == 'running': return LOG.debug('starting instance %s', self.instance.id) self.instance.start() else: LOG.debug('launching instance') args = { 'ImageId': self.image_ami, 'InstanceType': self.platform.instance_type, 'KeyName': self.platform.key_name, 'MaxCount': 1, 'MinCount': 1, 'SecurityGroupIds': [self.platform.security_group.id], 'SubnetId': self.platform.subnet.id, 'TagSpecifications': [{ 'ResourceType': 'instance', 'Tags': [{ 'Key': 'Name', 'Value': self.platform.tag }] }], } if self.user_data: args['UserData'] = self.user_data try: instances = self.platform.ec2_resource.create_instances(**args) except botocore.exceptions.ClientError as error: error_msg = error.response['Error']['Message'] raise util.PlatformError('start', error_msg) self.instance = instances[0] LOG.debug('instance id: %s', self.instance.id) if wait: self.instance.wait_until_running() self.instance.reload() self.ssh_ip = self.instance.public_ip_address self._wait_for_system(wait_for_cloud_init)
def console_log(self): """Collect console log from instance. The console log is buffered and not always present, therefore may return empty string. """ try: # OutputBytes comes from platform._decode_console_output_as_bytes response = self.instance.console_output() return response['OutputBytes'] except KeyError: if 'Output' in response: msg = ("'OutputBytes' did not exist in console_output() but " "'Output' did: %s..." % response['Output'][0:128]) raise util.PlatformError('console_log', msg) return ('No Console Output [%s]' % self.instance).encode()
def collect_script(instance, base_dir, script, script_name): """Collect script data. @param instance: instance to run script on @param base_dir: base directory for output data @param script: script contents @param script_name: name of script to run @return_value: None, may raise errors """ LOG.debug('running collect script: %s', script_name) (out, err, exit) = instance.run_script( script.encode(), rcs=False, description='collect: {}'.format(script_name)) if err: LOG.debug("collect script %s had stderr: %s", script_name, err) if not isinstance(out, bytes): raise util.PlatformError( "Collection of '%s' returned type %s, expected bytes: %s" % (script_name, type(out), out)) c_util.write_file(os.path.join(base_dir, script_name), out)
def _wait_for_system(self, wait_for_cloud_init): """Wait until system has fully booted and cloud-init has finished. @param wait_time: maximum time to wait @return_value: None, may raise OSError if wait_time exceeded """ def clean_test(test): """Clean formatting for system ready test testcase.""" return ' '.join(line for line in test.strip().splitlines() if not line.lstrip().startswith('#')) boot_timeout = self.config['boot_timeout'] tests = [self.config['system_ready_script']] if wait_for_cloud_init: tests.append(self.config['cloud_init_ready_script']) formatted_tests = ' && '.join(clean_test(t) for t in tests) cmd = ('i=0; while [ $i -lt {time} ] && i=$(($i+1)); do {test} && ' 'exit 0; sleep 1; done; exit 1').format(time=boot_timeout, test=formatted_tests) end_time = time.time() + boot_timeout while True: try: return_code = self.execute( cmd, rcs=(0, 1), description='wait for instance start')[-1] if return_code == 0: break except util.InTargetExecuteError: LOG.warning("failed to connect via SSH") if time.time() < end_time: time.sleep(3) else: raise util.PlatformError( 'ssh', 'after %ss instance is not ' 'reachable' % boot_timeout)