Ejemplo n.º 1
0
    def _establish_ssh_connection(self):
        """Connect to the running instance with ssh"""
        if self.aborted:
            return
        self.log.debug('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.log_level == logging.DEBUG:
                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.log_level == logging.DEBUG:
            print()
        client = paramiko.client.SSHClient()
        client.set_missing_host_key_policy(paramiko.WarningPolicy())
        self.log.debug('Attempt ssh connection to %s' % instance_ip)
        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 (Exception, ConnectionResetError):
                if self.log_level == logging.DEBUG:
                    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
Ejemplo n.º 2
0
    def _unpack_image(self, image_dir, image_filename):
        """Unpack the uploaded image file"""
        if self.aborted:
            return
        raw_image_file = None
        files = ''
        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]
        elif image_filename[-3:] == 'raw':
            raw_image_file = image_filename

        if files:
            # Find the disk image
            for fl in files:
                if fl.strip()[-2:] == 'xz':
                    self.log.debug('Inflating image: {}'.format(fl))
                    command = 'xz -d %s/%s' % (image_dir, fl)
                    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
Ejemplo n.º 3
0
    def _format_storage_volume(self, device_id):
        """Format the storage volume"""
        if self.aborted:
            return
        self.log.debug('Formating storage volume')
        parted = self._get_command_from_instance('parted')
        sfdisk = 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 result
Ejemplo n.º 4
0
    def _find_device_name(self, device_size):
        """Match an attached volume by size"""
        try:
            lsblk_out = json.loads(self._execute_ssh_command('lsblk -a -J'))
        except Exception:
            self.log.error(
                '"lsblk -a -J" command failed on helper instance. Ensure the '
                'helper instance has lsblk >= 2.27 which has the json option.')
            lsblk_out = {'blockdevices': tuple()}

        for device in lsblk_out['blockdevices']:
            if device.get('children'):
                continue
            this_device_size = device['size']
            unit = this_device_size[-1]
            try:
                size = int(this_device_size[:-1])
            except ValueError:
                self.log.info('Skipping non integer sized disk')
                continue

            size_multiplier = 1
            if unit == 'T':
                size_multiplier = 1024
            disk_size = size * size_multiplier
            if disk_size == device_size:
                # We do not need to worry about finding the same device twice
                # Only 2 disks get attached and they are known to have
                # different sizes
                return '/dev/%s' % device['name']

        self._clean_up()
        msg = 'Could not find attached disk device with size %sG' % device_size
        raise EC2UploadImgException(msg)
Ejemplo n.º 5
0
    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.log_level == logging.DEBUG:
                print()
            if repeat_count == self.wait_count:
                self.operation_complete = True
                if self.log_level == logging.DEBUG:
                    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
            self.log.info('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.log_level == logging.DEBUG:
                self.progress_timer.cancel()
            time.sleep(self.default_sleep)  # Wait for the thread
            if self.log_level == logging.DEBUG:
                print()

        return repeat_count
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
 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 Exception:
         error_msg = 'Specified subnet %s not found' % self.vpc_subnet_id
         raise EC2UploadImgException(error_msg)
Ejemplo n.º 8
0
 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 Exception:
         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)
Ejemplo n.º 9
0
    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"""
        if self.launch_ami_id:
            image = self._connect().describe_images(
                ImageIds=[self.launch_ami_id])['Images'][0]
        elif self.running_id:
            helper_instance = self._get_helper_instance()
            image = self._connect().describe_images(
                ImageIds=[helper_instance['ImageId']])['Images'][0]
        else:
            error_msg = 'Could not determine helper image virtualization '
            error_msg += 'type necessary for root swap method'
            raise EC2UploadImgException(error_msg)

        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)
Ejemplo n.º 10
0
    def _get_helper_instance(self):
        """Returns handle to running instance"""
        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)

        self.vpc_subnet_id = helper_instance['SubnetId']
        self._set_zone_to_use()

        return helper_instance
Ejemplo n.º 11
0
    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.aborted:
            return
        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_error
            raise EC2UploadImgException(msg)

        return stdout.read().strip().decode('utf-8')