def _establish_ssh_connection(self): """Connect to the running instance with ssh""" if self.aborted: return if self.verbose: print('Waiting to obtain instance IP address') instance_ip = self.helper_instance.get('PublicIpAddress') if self.use_private_ip: instance_ip = self.helper_instance.get('PrivateIpAddress') timeout_counter = 1 while not instance_ip: instance = self._connect().describe_instances( InstanceIds=[self.helper_instance['InstanceId'] ])['Reservations'][0]['Instances'][0] instance_ip = instance.get('PublicIpAddress') if self.use_private_ip: instance_ip = instance.get('PrivateIpAddress') if self.verbose: print('. ', end=' ') sys.stdout.flush() if timeout_counter * self.default_sleep >= self.ssh_timeout: msg = 'Unable to obtain the instance IP address' raise EC2UploadImgException(msg) timeout_counter += 1 if self.verbose: print() client = paramiko.client.SSHClient() client.set_missing_host_key_policy(paramiko.WarningPolicy()) if self.verbose: print('Attempt ssh connection') ssh_connection = None timeout_counter = 1 while not ssh_connection: try: ssh_connection = client.connect( key_filename=self.ssh_key_private_key_file, username=self.inst_user_name, hostname=instance_ip) except: if self.verbose: print('. ', end=' ') sys.stdout.flush() time.sleep(self.default_sleep) if (timeout_counter * self.default_sleep >= self.ssh_timeout): self._clean_up() msg = 'Time out for ssh connection reached, ' msg += 'could not connect' raise EC2UploadImgException(msg) timeout_counter += 1 else: ssh_connection = True print() self.ssh_client = client
def _unpack_image(self, image_dir, image_filename): """Unpack the uploaded image file""" if (image_filename.find('.tar') != -1 or image_filename.find('.tbz') != -1 or image_filename.find('.tgz') != -1): command = 'tar -C %s -xvf %s/%s' % (image_dir, image_dir, image_filename) files = self._execute_ssh_command(command).split('\r\n') elif image_filename[-2:] == 'xz': files = [image_filename] raw_image_file = None if files: # Find the disk image for fl in files: if fl.strip()[-2:] == 'xz': if self.verbose: print('Inflating image: ', fl) command = 'xz -d %s/%s' % (image_dir, fl) result = self._execute_ssh_command(command) raw_image_file = fl.strip()[:-3] break if fl.strip()[-4:] == '.raw': raw_image_file = fl.strip() break if not raw_image_file: self._clean_up() msg = 'Unable to find raw image file with .raw extension' raise EC2UploadImgException(msg) return raw_image_file
def _format_storage_volume(self, device_id): """Format the storage volume""" if self.verbose: print('Formating storage volume') parted = self._get_command_from_instance('parted') sfdifk = None if not parted: sfdisk = self._get_command_from_instance('sfdisk') if not parted and not sfdisk: self._clean_up() msg = 'Neither parted nor sfdisk found on target image. ' msg += 'Need to partition storage device but cannot, exiting.' raise EC2UploadImgException(msg) if parted: command = '%s -s %s mklabel gpt' % (parted, device_id) result = self._execute_ssh_command(command) blockdev = self._get_command_from_instance('blockdev') command = '%s --getsize %s' % (blockdev, device_id) size = self._execute_ssh_command(command) command = ('%s -s %s unit s mkpart primary 2048 %d' % (parted, device_id, int(size) - 100)) result = self._execute_ssh_command(command) else: command = 'echo ",,L" > /tmp/partition.txt' result = self._execute_ssh_command(command) command = '%s %s < /tmp/partition.txt' % (sfdisk, device_id) result = self._execute_ssh_command(command) return 1
def _check_wait_status(self, wait_status, error_msg, repeat_count, skip_cleanup=False): """Check the wait status form the waiter and take appropriate action""" if wait_status: if self.verbose: print() if repeat_count == self.wait_count: self.operation_complete = True if self.verbose: self.progress_timer.cancel() time.sleep(self.default_sleep) # Wait for the thread if not skip_cleanup: self._clean_up() raise EC2UploadImgException(error_msg) repeat_count += 1 print('Entering wait loop number %d of %d' % (repeat_count, self.wait_count)) self.operation_complete = False self._show_progress() else: repeat_count = self.wait_count + 1 self.operation_complete = True if self.verbose: self.progress_timer.cancel() time.sleep(self.default_sleep) # Wait for the thread if self.verbose: print() return repeat_count
def _check_image_exists(self): """Check if an image with the given name already exists""" my_images = self._get_owned_images() for image in my_images: if image['Name'] == self.image_name: msg = 'Image with name "%s" already exists' % self.image_name raise EC2UploadImgException(msg)
def _check_subnet_exists(self): """Verify that the subnet being used for the helper instance exists""" try: self._connect().describe_subnets(SubnetIds=[self.vpc_subnet_id]) except: error_msg = 'Specified subnet %s not found' % self.vpc_subnet_id raise EC2UploadImgException(error_msg)
def _check_security_groups_exist(self): """Check that the specified security groups exist""" try: self._connect().describe_security_groups( GroupIds=self.security_group_ids.split(',')) except: error_msg = 'One or more of the specified security groups ' error_msg += 'could not be found: %s' % self.security_group_ids raise EC2UploadImgException(error_msg)
def _get_helper_instance(self): """Returns handle to running instance""" self._set_zone_to_use() helper_instance = self._connect().describe_instances( InstanceIds=[self.running_id])['Reservations'][0]['Instances'][0] if helper_instance['State']['Name'] != 'running': msg = 'Helper instance %s is not running' % self.running_id raise EC2UploadImgException(msg) return helper_instance
def _execute_ssh_command(self, command): """Execute a command on the remote machine, on error raise an exception return the result of stdout""" if self.inst_user_name != 'root': command = 'sudo %s' % command if not self.ssh_client: msg = 'No ssh connection established, cannot execute command' raise EC2UploadImgException(msg) stdin, stdout, stderr = self.ssh_client.exec_command(command, get_pty=True) cmd_error = stderr.read() if cmd_error: self._clean_up() msg = 'Execution of "%s" failed with the following error' % command msg += '\n%s' % cmd_err raise EC2UploadImgException(msg) return stdout.read().strip().decode('utf-8')
def _check_virt_type_consistent(self): """When using root swap the virtualization type of the helper image and the target image must be the same""" image = self._connect().describe_images( ImageIds=[self.launch_ami_id])['Images'][0] if not self.image_virt_type == image['VirtualizationType']: error_msg = 'Virtualization type of the helper image and the ' error_msg += 'target image must be the same when using ' error_msg += 'root-swap method for image creation.' raise EC2UploadImgException(error_msg)
def _find_equivalent_device(self, device_id): """Try and find a device that should be the same device in the instance than the one we attached with a given device id.""" device_letter = device_id[-1] expected_name = '/dev/xvd%s' % device_letter if self._device_exists(expected_name): return expected_name self._clean_up() msg = 'Could not find disk device in helper instance with path ' msg += '%s or %s' % (device_id, expected_name) raise EC2UploadImgException(msg)