class CreatePartitionsCommand(DeviceModifyingCommand): """ takes care of creating the partitions on the target system """ class CanNotCreatePartitionException( DeviceModifyingCommand.CommandExecutionException): """ is called if a partition can not be created, for whatever reason """ COMMAND_DOES = 'create the partitions' ERROR_REPORT_EXCEPTION_CLASS = CanNotCreatePartitionException READ_PARTITION_TABLE_COMMAND = RemoteHostCommand('sudo sfdisk -d {DEVICE}') WRITE_PARTITION_TABLE_COMMAND = RemoteHostCommand( 'echo "{PARTITION_TABLE}" | sudo sfdisk {DEVICE}') def _execute(self): self.source_remote_executor = RemoteHostExecutor( self._source.remote_host) self._execute_on_every_device(self._replicate_partition_table, None, include_swap=True) self.source_remote_executor.close() self.source_remote_executor = None @DeviceModifyingCommand._collect_errors def _replicate_partition_table(self, remote_executor, source_device, target_device): """ replicates the partition table of the source device and applies it to the target device :param remote_executor: remote executor to use for execution :type remote_executor: RemoteHostExecutor :param source_device: the source device :type source_device: (str, dict) :param target_device: the target device :type target_device: (str, dict) """ partition_table = self._read_partition_table( self.source_remote_executor, source_device[0]) if partition_table: self._write_partition_table(remote_executor, target_device[0], partition_table) else: self.logger.debug( 'no valid partition table found for {source_device}'.format( source_device=source_device)) def _write_partition_table(self, remote_executor, target_device_id, partition_table): remote_executor.execute( self.WRITE_PARTITION_TABLE_COMMAND.render( partition_table=self._make_string_echo_safe(partition_table), device='/dev/{device_id}'.format(device_id=target_device_id))) def _read_partition_table(self, source_remote_executor, source_device_id): try: return source_remote_executor.execute( self.READ_PARTITION_TABLE_COMMAND.render( device='/dev/{device_id}'.format( device_id=source_device_id))) except RemoteHostExecutor.ExecutionException: return '' def _make_string_echo_safe(self, string): return string.replace('"', '\\"')
class SyncCommand(DeviceModifyingCommand): """ does the actual sync and makes sure, that temp mounts are created and used, to avoid problems introduced by overlapping mountpoints. """ class SyncingException(DeviceModifyingCommand.CommandExecutionException): """ raised if an error occurs during the sync """ COMMAND_DOES = 'do the sync' ERROR_REPORT_EXCEPTION_CLASS = SyncingException ACCEPTED_EXIT_CODES = (24,) def _execute(self): self.source_remote_executor = RemoteHostExecutor(self._source.remote_host) self._execute_on_every_device(self._sync_disk, self._sync_partition) self.source_remote_executor.close() self.source_remote_executor = None return Commander.Signal.SLEEP def _sync_disk(self, remote_executor, source_device, target_device): self._sync_device(self.source_remote_executor, source_device[1]['mountpoint'], target_device[1]['mountpoint']) def _sync_partition( self, remote_executor, source_device, target_device, source_partition_device, target_partition_device ): self._sync_device( self.source_remote_executor, source_partition_device[1]['mountpoint'], target_partition_device[1]['mountpoint'], ) @DeviceModifyingCommand._collect_errors def _sync_device(self, remote_executor, source_directory, target_directory): if source_directory: remote_executor.execute( RemoteHostCommand(self._target.blueprint['commands']['sync']).render( source_dir=self._create_temp_bind_mount(remote_executor, source_directory), target_dir='{user}{remote_host_address}:{target_directory}'.format( user=('{username}@'.format(username=self._target.remote_host.username)) if self._target.remote_host.username else '', remote_host_address=self._target.remote_host.address, target_directory=target_directory, ) ), accepted_exit_codes=self.ACCEPTED_EXIT_CODES ) def _create_temp_bind_mount(self, remote_executor, source_directory): temp_mountpoint = MountpointMapper.map_mountpoint('/tmp', source_directory) remote_executor.execute( DefaultRemoteHostCommand.MAKE_DIRECTORY.render(directory=temp_mountpoint) ) try: remote_executor.execute(DefaultRemoteHostCommand.CHECK_MOUNTPOINT.render(directory=temp_mountpoint)) except RemoteHostExecutor.ExecutionException: remote_executor.execute( DefaultRemoteHostCommand.BIND_MOUNT.render( directory=source_directory, mountpoint=temp_mountpoint ) ) return temp_mountpoint