@ -58,7 +58,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
# First we process the .gns3 in order to be sure we don't have an error
for file in os . listdir ( project . _path ) :
if file . endswith ( " .gns3 " ) :
_export_project_file ( project , os . path . join ( project . _path , file ) , z , include_images , keep_compute_id , allow_all_nodes )
images = yield from _export_project_file ( project , os . path . join ( project . _path , file ) ,
z , include_images , keep_compute_id , allow_all_nodes , temporary_dir )
for root , dirs , files in os . walk ( project . _path , topdown = True ) :
files = [ f for f in files if not _filter_files ( os . path . join ( root , f ) ) ]
@ -78,6 +79,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
else :
z . write ( path , os . path . relpath ( path , project . _path ) , compress_type = zipfile . ZIP_DEFLATED )
downloaded_files = set ( )
for compute in project . computes :
if compute . id != " local " :
compute_files = yield from compute . list_files ( project )
@ -94,6 +97,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
response . close ( )
f . close ( )
z . write ( temp_path , arcname = compute_file [ " path " ] , compress_type = zipfile . ZIP_DEFLATED )
downloaded_files . add ( compute_file [ ' path ' ] )
return z
@ -121,7 +126,8 @@ def _filter_files(path):
return False
def _export_project_file ( project , path , z , include_images , keep_compute_id , allow_all_nodes ) :
@asyncio.coroutine
def _export_project_file ( project , path , z , include_images , keep_compute_id , allow_all_nodes , temporary_dir ) :
"""
Take a project file ( . gns3 ) and patch it for the export
@ -131,7 +137,7 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
"""
# Image file that we need to include in the exported archive
images = set ( )
images = [ ]
with open ( path ) as f :
topology = json . load ( f )
@ -139,6 +145,8 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
if " topology " in topology :
if " nodes " in topology [ " topology " ] :
for node in topology [ " topology " ] [ " nodes " ] :
compute_id = node . get ( ' compute_id ' , ' local ' )
if node [ " node_type " ] == " virtualbox " and node . get ( " properties " , { } ) . get ( " linked_clone " ) :
raise aiohttp . web . HTTPConflict ( text = " Topology with a linked {} clone could not be exported. Use qemu instead. " . format ( node [ " node_type " ] ) )
if not allow_all_nodes and node [ " node_type " ] in [ " virtualbox " , " vmware " , " cloud " ] :
@ -149,22 +157,42 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
if " properties " in node and node [ " node_type " ] != " docker " :
for prop , value in node [ " properties " ] . items ( ) :
if prop . endswith ( " image " ) :
if not keep_compute_id : # If we keep the original compute we can keep the image path
node [ " properties " ] [ prop ] = os . path . basename ( value )
if include_images is True :
images . add ( value )
if not prop . endswith ( " image " ) :
continue
if value is None or value . strip ( ) == ' ' :
continue
if not keep_compute_id : # If we keep the original compute we can keep the image path
node [ " properties " ] [ prop ] = os . path . basename ( value )
if include_images is True :
images . append ( {
' compute_id ' : compute_id ,
' image ' : value ,
' image_type ' : node [ ' node_type ' ]
} )
if not keep_compute_id :
topology [ " topology " ] [ " computes " ] = [ ] # Strip compute informations because could contain secret info like password
topology [ " topology " ] [ " computes " ] = [ ] # Strip compute information because could contain secret info like password
local_images = set ( [ i [ ' image ' ] for i in images if i [ ' compute_id ' ] == ' local ' ] )
for image in local_images :
_export_local_images ( project , image , z )
remote_images = set ( [
( i [ ' compute_id ' ] , i [ ' image_type ' ] , i [ ' image ' ] )
for i in images if i [ ' compute_id ' ] != ' local ' ] )
for image in images :
_export_images ( project , image , z )
for compute_id, image_type , image in remote_ images:
yield from _export_ remote_ images( project , compute_id , image_type , image , z , temporary_dir )
z . writestr ( " project.gns3 " , json . dumps ( topology ) . encode ( ) )
return images
def _export_images ( project , image , z ) :
def _export_ local_ images( project , image , z ) :
"""
Take a project file ( . gns3 ) and export images to the zip
@ -191,4 +219,45 @@ def _export_images(project, image, z):
arcname = os . path . join ( " images " , directory , os . path . basename ( image ) )
z . write ( path , arcname )
return
raise aiohttp . web . HTTPConflict ( text = " Topology could not be exported because the image {} is not available. If you use multiple server, we need a copy of the image on the main server. " . format ( image ) )
@asyncio.coroutine
def _export_remote_images ( project , compute_id , image_type , image , project_zipfile , temporary_dir ) :
"""
Export specific image from remote compute
: param project :
: param compute_id :
: param image_type :
: param image :
: param project_zipfile :
: return :
"""
log . info ( " Obtaining image ` {} ` from ` {} ` " . format ( image , compute_id ) )
try :
compute = [ compute for compute in project . computes if compute . id == compute_id ] [ 0 ]
except IndexError :
raise aiohttp . web . HTTPConflict (
text = " Cannot export image from ` {} ` compute. Compute doesn ' t exist. " . format ( compute_id ) )
( fd , temp_path ) = tempfile . mkstemp ( dir = temporary_dir )
f = open ( fd , " wb " , closefd = True )
response = yield from compute . download_image ( image_type , image )
if response . status != 200 :
raise aiohttp . web . HTTPConflict (
text = " Cannot export image from ` {} ` compute. Compute sent ` {} ` status. " . format (
compute_id , response . status ) )
while True :
data = yield from response . content . read ( 512 )
if not data :
break
f . write ( data )
response . close ( )
f . close ( )
arcname = os . path . join ( " images " , image_type , image )
log . info ( " Saved {} " . format ( arcname ) )
project_zipfile . write ( temp_path , arcname = arcname , compress_type = zipfile . ZIP_DEFLATED )