2016-06-16 17:28:51 -04:00
#
# Copyright 2006-2009, 2013, 2014 Red Hat, Inc.
#
2018-04-04 14:35:41 +01:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 15:00:02 -04:00
# See the COPYING file in the top-level directory.
2016-06-16 17:28:51 -04:00
import os
2019-06-16 21:34:47 -04:00
from . . import progress
from . . devices import DeviceDisk
from . . logger import log
from . . storage import StoragePool , StorageVolume
2016-06-16 17:28:51 -04:00
def _build_pool ( conn , meter , path ) :
"""
Helper function for building a pool on demand . Used for building
a scratchdir pool for volume upload
"""
pool = StoragePool . lookup_pool_by_path ( conn , path )
2019-06-11 17:19:01 -04:00
if pool : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . debug ( " Existing pool ' %s ' found for %s " , pool . name ( ) , path )
2019-04-14 19:16:10 -04:00
StoragePool . ensure_pool_is_running ( pool , refresh = True )
2016-06-16 17:28:51 -04:00
return pool
2017-07-18 19:09:58 -04:00
name = StoragePool . find_free_name ( conn , " boot-scratch " )
2019-06-16 21:12:39 -04:00
log . debug ( " Building storage pool: path= %s name= %s " , path , name )
2016-06-16 17:28:51 -04:00
poolbuild = StoragePool ( conn )
poolbuild . type = poolbuild . TYPE_DIR
poolbuild . name = name
poolbuild . target_path = path
# Explicitly don't build? since if we are creating this directory
# we probably don't have correct perms
ret = poolbuild . install ( meter = meter , create = True , build = False ,
autostart = True )
return ret
2019-06-08 09:41:52 -04:00
class _MockStream :
_data_size = None
def send ( self , data ) :
if self . _data_size is None :
self . _data_size = len ( data )
2019-06-11 17:19:01 -04:00
block_size = 128
2019-06-08 09:41:52 -04:00
ret = min ( self . _data_size , block_size )
self . _data_size = max ( 0 , self . _data_size - block_size )
return ret
def finish ( self ) :
pass
2016-06-16 17:28:51 -04:00
def _upload_file ( conn , meter , destpool , src ) :
"""
Helper for uploading a file to a pool , via libvirt . Used for
kernel / initrd upload when we can ' t access the system scratchdir
"""
# Build stream object
2019-06-08 09:41:52 -04:00
if conn . in_testsuite ( ) :
stream = _MockStream ( )
else :
2019-06-11 17:19:01 -04:00
stream = conn . newStream ( 0 ) # pragma: no cover
2019-06-08 09:41:52 -04:00
2016-06-16 17:28:51 -04:00
def safe_send ( data ) :
while True :
ret = stream . send ( data )
if ret == 0 or ret == len ( data ) :
break
data = data [ ret : ]
2019-06-07 17:32:51 -04:00
meter = progress . ensure_meter ( meter )
2016-06-16 17:28:51 -04:00
# Build placeholder volume
size = os . path . getsize ( src )
basename = os . path . basename ( src )
2019-06-11 08:52:12 -04:00
name = StorageVolume . find_free_name ( conn , destpool , basename )
2019-06-16 21:12:39 -04:00
log . debug ( " Generated volume name %s " , name )
2016-06-16 17:28:51 -04:00
2018-03-20 12:18:35 -04:00
vol_install = DeviceDisk . build_vol_install ( conn , name , destpool ,
2016-06-16 17:28:51 -04:00
( float ( size ) / 1024.0 / 1024.0 / 1024.0 ) , True )
2018-03-20 12:18:35 -04:00
disk = DeviceDisk ( conn )
2016-06-16 17:28:51 -04:00
disk . set_vol_install ( vol_install )
disk . validate ( )
2018-09-03 16:44:38 -04:00
disk . build_storage ( meter )
2016-06-16 17:28:51 -04:00
vol = disk . get_vol_object ( )
if not vol :
2019-06-11 17:19:01 -04:00
raise RuntimeError ( # pragma: no cover
" Failed to lookup scratch media volume " )
2016-06-16 17:28:51 -04:00
try :
# Register upload
offset = 0
length = size
flags = 0
2019-06-08 09:41:52 -04:00
if not conn . in_testsuite ( ) :
2019-06-11 17:19:01 -04:00
vol . upload ( stream , offset , length , flags ) # pragma: no cover
2016-06-16 17:28:51 -04:00
# Open source file
2018-03-18 11:50:22 -04:00
fileobj = open ( src , " rb " )
2016-06-16 17:28:51 -04:00
# Start transfer
total = 0
2021-05-21 17:22:26 -04:00
msg = _ ( " Transferring ' %(filename)s ' " ) % {
" filename " : os . path . basename ( src ) }
meter . start ( msg , size )
2016-06-16 17:28:51 -04:00
while True :
2021-02-03 14:02:32 -05:00
blocksize = 1024 * 1024 # 1 MiB
2016-06-16 17:28:51 -04:00
data = fileobj . read ( blocksize )
if not data :
break
safe_send ( data )
total + = len ( data )
meter . update ( total )
# Cleanup
stream . finish ( )
2021-04-07 12:37:38 -04:00
meter . end ( )
2019-06-11 17:19:01 -04:00
except Exception : # pragma: no cover
2018-03-18 11:50:22 -04:00
vol . delete ( 0 )
2016-06-16 17:28:51 -04:00
raise
return vol
2020-09-08 18:41:41 -04:00
def upload_paths ( conn , system_scratchdir , meter , pathlist ) :
2016-06-16 17:28:51 -04:00
"""
2020-09-08 18:41:41 -04:00
Upload passed paths to the connection scratchdir
2016-06-16 17:28:51 -04:00
"""
# Build pool
2019-06-16 21:12:39 -04:00
log . debug ( " Uploading kernel/initrd media " )
2016-06-16 17:28:51 -04:00
pool = _build_pool ( conn , meter , system_scratchdir )
2020-09-08 18:41:41 -04:00
tmpvols = [ ]
newpaths = [ ]
try :
for path in pathlist :
vol = _upload_file ( conn , meter , pool , path )
newpaths . append ( vol . path ( ) )
tmpvols . append ( vol )
except Exception : # pragma: no cover
for vol in tmpvols :
vol . delete ( 0 )
raise
2016-06-16 17:28:51 -04:00
2020-09-08 18:41:41 -04:00
return newpaths , tmpvols