@ -24,6 +24,10 @@ import os
import json
import json
import subprocess
import subprocess
from yaml import YAMLError
from yaml import YAMLError
import tempfile
from yaml import load , YAMLError
>> >> >> > feature / copy - vault - dataloader : Add method get_real_file ( file_path ) to dataloader
from ansible . compat . six import text_type , string_types
from ansible . compat . six import text_type , string_types
from ansible . errors import AnsibleFileNotFound , AnsibleParserError , AnsibleError
from ansible . errors import AnsibleFileNotFound , AnsibleParserError , AnsibleError
@ -58,10 +62,15 @@ class DataLoader():
def __init__ ( self ) :
def __init__ ( self ) :
self . _basedir = ' . '
self . _basedir = ' . '
self . _FILE_CACHE = dict ( )
self . _FILE_CACHE = dict ( )
self . _tempfiles = set ( )
# initialize the vault stuff with an empty password
# initialize the vault stuff with an empty password
self . set_vault_password ( None )
self . set_vault_password ( None )
def __del__ ( self ) :
for f in self . _tempfiles :
os . unlink ( f )
def set_vault_password ( self , vault_password ) :
def set_vault_password ( self , vault_password ) :
self . _vault_password = vault_password
self . _vault_password = vault_password
self . _vault = VaultLib ( password = vault_password )
self . _vault = VaultLib ( password = vault_password )
@ -292,3 +301,65 @@ class DataLoader():
f . close ( )
f . close ( )
except ( OSError , IOError ) as e :
except ( OSError , IOError ) as e :
raise AnsibleError ( " Could not read vault password file %s : %s " % ( this_path , e ) )
raise AnsibleError ( " Could not read vault password file %s : %s " % ( this_path , e ) )
def _create_content_tempfile ( self , content ) :
''' Create a tempfile containing defined content '''
fd , content_tempfile = tempfile . mkstemp ( )
f = os . fdopen ( fd , ' wb ' )
content = to_bytes ( content )
try :
f . write ( content )
except Exception as err :
os . remove ( content_tempfile )
raise Exception ( err )
finally :
f . close ( )
return content_tempfile
def get_real_file ( self , file_path ) :
"""
If the file is vault encrypted return a path to a temporary decrypted file
If the file is not encrypted then the path is returned
Temporary files are cleanup in the destructor
"""
if not file_path or not isinstance ( file_path , string_types ) :
raise AnsibleParserError ( " Invalid filename: ' %s ' " % str ( file_path ) )
if not self . path_exists ( file_path ) or not self . is_file ( file_path ) :
raise AnsibleFileNotFound ( " the file_name ' %s ' does not exist, or is not readable " % file_path )
if not self . _vault :
self . _vault = VaultLib ( password = " " )
real_path = self . path_dwim ( file_path )
try :
with open ( real_path , ' rb ' ) as f :
data = f . read ( )
if self . _vault . is_encrypted ( data ) :
# if the file is encrypted and no password was specified,
# the decrypt call would throw an error, but we check first
# since the decrypt function doesn't know the file name
if not self . _vault_password :
raise AnsibleParserError ( " A vault password must be specified to decrypt %s " % file_path )
data = self . _vault . decrypt ( data )
# Make a temp file
real_path = self . _create_content_tempfile ( data )
self . _tempfiles . add ( real_path )
return real_path
except ( IOError , OSError ) as e :
raise AnsibleParserError ( " an error occurred while trying to read the file ' %s ' : %s " % ( file_name , str ( e ) ) )
def cleanup_real_file ( self , file_path ) :
"""
Removes any temporary files created from a previous call to
get_real_file . file_path must be the path returned from a
previous call to get_real_file .
"""
if file_path in self . _tempfiles :
os . unlink ( file_path )
self . _tempfiles . remove ( file_path ) ;