Save output streams.
Implementation is 99% based on Steven's initial implementation.
This commit is contained in:
		
					parent
					
						
							
								13a13eee03
							
						
					
				
			
			
				commit
				
					
						9703e0f08e
					
				
			
		
					 21 changed files with 483 additions and 120 deletions
				
			
		| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
 | 
					# 2012-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -42,7 +43,7 @@ BANNER = """
 | 
				
			||||||
   "P'        ""         ""
 | 
					   "P'        ""         ""
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
REMOTE_COPY = "scp -o User=root"
 | 
					REMOTE_COPY = "scp -o User=root -q"
 | 
				
			||||||
REMOTE_EXEC = "ssh -o User=root"
 | 
					REMOTE_EXEC = "ssh -o User=root"
 | 
				
			||||||
REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}"
 | 
					REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,18 +81,73 @@ class CdistBetaRequired(cdist.Error):
 | 
				
			||||||
        return err_msg.format(*fmt_args)
 | 
					        return err_msg.format(*fmt_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CdistObjectError(Error):
 | 
					class CdistEntityError(Error):
 | 
				
			||||||
    """Something went wrong with an object"""
 | 
					    """Something went wrong while executing cdist entity"""
 | 
				
			||||||
 | 
					    def __init__(self, entity_name, entity_params, stderr_paths, subject=''):
 | 
				
			||||||
 | 
					        self.entity_name = entity_name
 | 
				
			||||||
 | 
					        self.entity_params = entity_params
 | 
				
			||||||
 | 
					        self.stderr_paths = stderr_paths
 | 
				
			||||||
 | 
					        if isinstance(subject, Error):
 | 
				
			||||||
 | 
					            self.original_error = subject
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.original_error = None
 | 
				
			||||||
 | 
					        self.message = str(subject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, cdist_object, message):
 | 
					    @property
 | 
				
			||||||
        self.name = cdist_object.name
 | 
					    def stderr(self):
 | 
				
			||||||
        self.source = " ".join(cdist_object.source)
 | 
					        output = []
 | 
				
			||||||
        self.message = message
 | 
					        for stderr_name, stderr_path in self.stderr_paths:
 | 
				
			||||||
 | 
					            if os.path.getsize(stderr_path) > 0:
 | 
				
			||||||
 | 
					                label_begin = '---- BEGIN ' + stderr_name + ':stderr ----'
 | 
				
			||||||
 | 
					                label_end = '---- END ' + stderr_name + ':stderr ----'
 | 
				
			||||||
 | 
					                output.append('\n' + label_begin)
 | 
				
			||||||
 | 
					                with open(stderr_path, 'r') as fd:
 | 
				
			||||||
 | 
					                    output.append(fd.read())
 | 
				
			||||||
 | 
					                output.append(label_end)
 | 
				
			||||||
 | 
					        return '\n'.join(output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return '%s: %s (defined at %s)' % (self.name,
 | 
					        output = []
 | 
				
			||||||
                                           self.message,
 | 
					        output.append(self.message)
 | 
				
			||||||
                                           self.source)
 | 
					        header = "\nError processing " + self.entity_name
 | 
				
			||||||
 | 
					        under_header = '=' * len(header)
 | 
				
			||||||
 | 
					        output.append(header)
 | 
				
			||||||
 | 
					        output.append(under_header)
 | 
				
			||||||
 | 
					        for param_name, param_value in self.entity_params:
 | 
				
			||||||
 | 
					            output.append(param_name + ': ' + str(param_value))
 | 
				
			||||||
 | 
					        output.append(self.stderr + '\n')
 | 
				
			||||||
 | 
					        return '\n'.join(output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CdistObjectError(CdistEntityError):
 | 
				
			||||||
 | 
					    """Something went wrong while working on a specific cdist object"""
 | 
				
			||||||
 | 
					    def __init__(self, cdist_object, subject=''):
 | 
				
			||||||
 | 
					        params = [
 | 
				
			||||||
 | 
					            ('name', cdist_object.name, ),
 | 
				
			||||||
 | 
					            ('path', cdist_object.absolute_path, ),
 | 
				
			||||||
 | 
					            ('source', " ".join(cdist_object.source), ),
 | 
				
			||||||
 | 
					            ('type', cdist_object.cdist_type.absolute_path, ),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        stderr_paths = []
 | 
				
			||||||
 | 
					        for stderr_name in os.listdir(cdist_object.stderr_path):
 | 
				
			||||||
 | 
					            stderr_path = os.path.join(cdist_object.stderr_path,
 | 
				
			||||||
 | 
					                                       stderr_name)
 | 
				
			||||||
 | 
					            stderr_paths.append((stderr_name, stderr_path, ))
 | 
				
			||||||
 | 
					        super().__init__("object '{}'".format(cdist_object.name),
 | 
				
			||||||
 | 
					                         params, stderr_paths, subject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InitialManifestError(CdistEntityError):
 | 
				
			||||||
 | 
					    """Something went wrong while executing initial manifest"""
 | 
				
			||||||
 | 
					    def __init__(self, initial_manifest, stderr_path, subject=''):
 | 
				
			||||||
 | 
					        params = [
 | 
				
			||||||
 | 
					            ('path', initial_manifest, ),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        stderr_paths = []
 | 
				
			||||||
 | 
					        stderr_paths = [
 | 
				
			||||||
 | 
					            ('init', stderr_path, ),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        super().__init__('initial manifest', params, stderr_paths, subject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def file_to_list(filename):
 | 
					def file_to_list(filename):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
 | 
					# 2013-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2016-2017 Darko Poljak (darko.poljak at gmail.com)
 | 
					# 2016-2017 Darko Poljak (darko.poljak at gmail.com)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
| 
						 | 
					@ -353,7 +354,9 @@ class Config(object):
 | 
				
			||||||
                base_path=args.remote_out_path,
 | 
					                base_path=args.remote_out_path,
 | 
				
			||||||
                quiet_mode=args.quiet,
 | 
					                quiet_mode=args.quiet,
 | 
				
			||||||
                archiving_mode=args.use_archiving,
 | 
					                archiving_mode=args.use_archiving,
 | 
				
			||||||
                configuration=configuration)
 | 
					                configuration=configuration,
 | 
				
			||||||
 | 
					                stdout_base_path=local.stdout_base_path,
 | 
				
			||||||
 | 
					                stderr_base_path=local.stderr_base_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            cleanup_cmds = []
 | 
					            cleanup_cmds = []
 | 
				
			||||||
            if cleanup_cmd:
 | 
					            if cleanup_cmd:
 | 
				
			||||||
| 
						 | 
					@ -400,7 +403,13 @@ class Config(object):
 | 
				
			||||||
        self._init_files_dirs()
 | 
					        self._init_files_dirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.explorer.run_global_explorers(self.local.global_explorer_out_path)
 | 
					        self.explorer.run_global_explorers(self.local.global_explorer_out_path)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
            self.manifest.run_initial_manifest(self.local.initial_manifest)
 | 
					            self.manifest.run_initial_manifest(self.local.initial_manifest)
 | 
				
			||||||
 | 
					        except cdist.Error as e:
 | 
				
			||||||
 | 
					            which = "init"
 | 
				
			||||||
 | 
					            stderr_path = os.path.join(self.local.stderr_base_path, which)
 | 
				
			||||||
 | 
					            raise cdist.InitialManifestError(self.local.initial_manifest,
 | 
				
			||||||
 | 
					                                             stderr_path, e)
 | 
				
			||||||
        self.iterate_until_finished()
 | 
					        self.iterate_until_finished()
 | 
				
			||||||
        self.cleanup()
 | 
					        self.cleanup()
 | 
				
			||||||
        self._remove_files_dirs()
 | 
					        self._remove_files_dirs()
 | 
				
			||||||
| 
						 | 
					@ -453,7 +462,9 @@ class Config(object):
 | 
				
			||||||
        objects_changed = False
 | 
					        objects_changed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for cdist_object in self.object_list():
 | 
					        for cdist_object in self.object_list():
 | 
				
			||||||
            if cdist_object.requirements_unfinished(cdist_object.requirements):
 | 
					            try:
 | 
				
			||||||
 | 
					                if cdist_object.requirements_unfinished(
 | 
				
			||||||
 | 
					                        cdist_object.requirements):
 | 
				
			||||||
                    """We cannot do anything for this poor object"""
 | 
					                    """We cannot do anything for this poor object"""
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -463,7 +474,8 @@ class Config(object):
 | 
				
			||||||
                    self.object_prepare(cdist_object)
 | 
					                    self.object_prepare(cdist_object)
 | 
				
			||||||
                    objects_changed = True
 | 
					                    objects_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if cdist_object.requirements_unfinished(cdist_object.autorequire):
 | 
					                if cdist_object.requirements_unfinished(
 | 
				
			||||||
 | 
					                        cdist_object.autorequire):
 | 
				
			||||||
                    """The previous step created objects we depend on -
 | 
					                    """The previous step created objects we depend on -
 | 
				
			||||||
                       wait for them
 | 
					                       wait for them
 | 
				
			||||||
                    """
 | 
					                    """
 | 
				
			||||||
| 
						 | 
					@ -472,6 +484,8 @@ class Config(object):
 | 
				
			||||||
                if cdist_object.state == core.CdistObject.STATE_PREPARED:
 | 
					                if cdist_object.state == core.CdistObject.STATE_PREPARED:
 | 
				
			||||||
                    self.object_run(cdist_object)
 | 
					                    self.object_run(cdist_object)
 | 
				
			||||||
                    objects_changed = True
 | 
					                    objects_changed = True
 | 
				
			||||||
 | 
					            except cdist.Error as e:
 | 
				
			||||||
 | 
					                raise cdist.CdistObjectError(cdist_object, e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return objects_changed
 | 
					        return objects_changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
# 2014 Daniel Heule (hda at sfs.biz)
 | 
					# 2014 Daniel Heule (hda at sfs.biz)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -80,6 +80,8 @@ class CdistObject(object):
 | 
				
			||||||
        self.code_local_path = os.path.join(self.path, "code-local")
 | 
					        self.code_local_path = os.path.join(self.path, "code-local")
 | 
				
			||||||
        self.code_remote_path = os.path.join(self.path, "code-remote")
 | 
					        self.code_remote_path = os.path.join(self.path, "code-remote")
 | 
				
			||||||
        self.parameter_path = os.path.join(self.path, "parameter")
 | 
					        self.parameter_path = os.path.join(self.path, "parameter")
 | 
				
			||||||
 | 
					        self.stdout_path = os.path.join(self.absolute_path, "stdout")
 | 
				
			||||||
 | 
					        self.stderr_path = os.path.join(self.absolute_path, "stderr")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def list_objects(cls, object_base_path, type_base_path, object_marker):
 | 
					    def list_objects(cls, object_base_path, type_base_path, object_marker):
 | 
				
			||||||
| 
						 | 
					@ -246,10 +248,11 @@ class CdistObject(object):
 | 
				
			||||||
        """Create this cdist object on the filesystem.
 | 
					        """Create this cdist object on the filesystem.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            os.makedirs(self.absolute_path, exist_ok=allow_overwrite)
 | 
					            for path in (self.absolute_path,
 | 
				
			||||||
            absolute_parameter_path = os.path.join(self.base_path,
 | 
					                         os.path.join(self.base_path, self.parameter_path),
 | 
				
			||||||
                                                   self.parameter_path)
 | 
					                         self.stdout_path,
 | 
				
			||||||
            os.makedirs(absolute_parameter_path, exist_ok=allow_overwrite)
 | 
					                         self.stderr_path):
 | 
				
			||||||
 | 
					                os.makedirs(path, exist_ok=allow_overwrite)
 | 
				
			||||||
        except EnvironmentError as error:
 | 
					        except EnvironmentError as error:
 | 
				
			||||||
            raise cdist.Error(('Error creating directories for cdist object: '
 | 
					            raise cdist.Error(('Error creating directories for cdist object: '
 | 
				
			||||||
                               '%s: %s') % (self, error))
 | 
					                               '%s: %s') % (self, error))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
# 2014 Daniel Heule (hda at sfs.biz)
 | 
					# 2014 Daniel Heule (hda at sfs.biz)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -127,8 +127,13 @@ class Code(object):
 | 
				
			||||||
                '__object_name': cdist_object.name,
 | 
					                '__object_name': cdist_object.name,
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            message_prefix = cdist_object.name
 | 
					            message_prefix = cdist_object.name
 | 
				
			||||||
            return self.local.run_script(script, env=env, return_output=True,
 | 
					            stderr_path = os.path.join(cdist_object.stderr_path,
 | 
				
			||||||
                                         message_prefix=message_prefix)
 | 
					                                       'gencode-' + which)
 | 
				
			||||||
 | 
					            with open(stderr_path, 'ba+') as stderr:
 | 
				
			||||||
 | 
					                return self.local.run_script(script, env=env,
 | 
				
			||||||
 | 
					                                             return_output=True,
 | 
				
			||||||
 | 
					                                             message_prefix=message_prefix,
 | 
				
			||||||
 | 
					                                             stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run_gencode_local(self, cdist_object):
 | 
					    def run_gencode_local(self, cdist_object):
 | 
				
			||||||
        """Run the gencode-local script for the given cdist object."""
 | 
					        """Run the gencode-local script for the given cdist object."""
 | 
				
			||||||
| 
						 | 
					@ -152,7 +157,12 @@ class Code(object):
 | 
				
			||||||
        which_exec = getattr(self, which)
 | 
					        which_exec = getattr(self, which)
 | 
				
			||||||
        script = os.path.join(which_exec.object_path,
 | 
					        script = os.path.join(which_exec.object_path,
 | 
				
			||||||
                              getattr(cdist_object, 'code_%s_path' % which))
 | 
					                              getattr(cdist_object, 'code_%s_path' % which))
 | 
				
			||||||
        return which_exec.run_script(script, env=env)
 | 
					        stderr_path = os.path.join(cdist_object.stderr_path, 'code-' + which)
 | 
				
			||||||
 | 
					        stdout_path = os.path.join(cdist_object.stdout_path, 'code-' + which)
 | 
				
			||||||
 | 
					        with open(stderr_path, 'ba+') as stderr, \
 | 
				
			||||||
 | 
					                open(stdout_path, 'ba+') as stdout:
 | 
				
			||||||
 | 
					            return which_exec.run_script(script, env=env, stdout=stdout,
 | 
				
			||||||
 | 
					                                         stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run_code_local(self, cdist_object):
 | 
					    def run_code_local(self, cdist_object):
 | 
				
			||||||
        """Run the code-local script for the given cdist object."""
 | 
					        """Run the code-local script for the given cdist object."""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
| 
						 | 
					@ -153,10 +153,16 @@ class Manifest(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        message_prefix = "initialmanifest"
 | 
					        message_prefix = "initialmanifest"
 | 
				
			||||||
        self.log.verbose("Running initial manifest " + initial_manifest)
 | 
					        self.log.verbose("Running initial manifest " + initial_manifest)
 | 
				
			||||||
        self.local.run_script(initial_manifest,
 | 
					        which = "init"
 | 
				
			||||||
 | 
					        stderr_path = os.path.join(self.local.stderr_base_path, which)
 | 
				
			||||||
 | 
					        stdout_path = os.path.join(self.local.stdout_base_path, which)
 | 
				
			||||||
 | 
					        with open(stderr_path, 'ba+') as stderr, \
 | 
				
			||||||
 | 
					                open(stdout_path, 'ba+') as stdout:
 | 
				
			||||||
 | 
					            self.local.run_script(
 | 
				
			||||||
 | 
					                initial_manifest,
 | 
				
			||||||
                env=self.env_initial_manifest(initial_manifest),
 | 
					                env=self.env_initial_manifest(initial_manifest),
 | 
				
			||||||
                message_prefix=message_prefix,
 | 
					                message_prefix=message_prefix,
 | 
				
			||||||
                              save_output=False)
 | 
					                stdout=stdout, stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def env_type_manifest(self, cdist_object):
 | 
					    def env_type_manifest(self, cdist_object):
 | 
				
			||||||
        type_manifest = os.path.join(self.local.type_path,
 | 
					        type_manifest = os.path.join(self.local.type_path,
 | 
				
			||||||
| 
						 | 
					@ -178,10 +184,16 @@ class Manifest(object):
 | 
				
			||||||
        type_manifest = os.path.join(self.local.type_path,
 | 
					        type_manifest = os.path.join(self.local.type_path,
 | 
				
			||||||
                                     cdist_object.cdist_type.manifest_path)
 | 
					                                     cdist_object.cdist_type.manifest_path)
 | 
				
			||||||
        message_prefix = cdist_object.name
 | 
					        message_prefix = cdist_object.name
 | 
				
			||||||
 | 
					        which = 'manifest'
 | 
				
			||||||
        if os.path.isfile(type_manifest):
 | 
					        if os.path.isfile(type_manifest):
 | 
				
			||||||
            self.log.verbose("Running type manifest %s for object %s",
 | 
					            self.log.verbose("Running type manifest %s for object %s",
 | 
				
			||||||
                             type_manifest, cdist_object.name)
 | 
					                             type_manifest, cdist_object.name)
 | 
				
			||||||
            self.local.run_script(type_manifest,
 | 
					            stderr_path = os.path.join(cdist_object.stderr_path, which)
 | 
				
			||||||
 | 
					            stdout_path = os.path.join(cdist_object.stdout_path, which)
 | 
				
			||||||
 | 
					            with open(stderr_path, 'ba+') as stderr, \
 | 
				
			||||||
 | 
					                    open(stdout_path, 'ba+') as stdout:
 | 
				
			||||||
 | 
					                self.local.run_script(
 | 
				
			||||||
 | 
					                    type_manifest,
 | 
				
			||||||
                    env=self.env_type_manifest(cdist_object),
 | 
					                    env=self.env_type_manifest(cdist_object),
 | 
				
			||||||
                    message_prefix=message_prefix,
 | 
					                    message_prefix=message_prefix,
 | 
				
			||||||
                                  save_output=False)
 | 
					                    stdout=stdout, stderr=stderr)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
# 2016-2017 Darko Poljak (darko.poljak at gmail.com)
 | 
					# 2016-2017 Darko Poljak (darko.poljak at gmail.com)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ import datetime
 | 
				
			||||||
import cdist
 | 
					import cdist
 | 
				
			||||||
import cdist.message
 | 
					import cdist.message
 | 
				
			||||||
from cdist import core
 | 
					from cdist import core
 | 
				
			||||||
import cdist.exec.util as exec_util
 | 
					import cdist.exec.util as util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ]
 | 
					CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,9 +120,11 @@ class Local(object):
 | 
				
			||||||
                                                     "explorer")
 | 
					                                                     "explorer")
 | 
				
			||||||
        self.object_path = os.path.join(self.base_path, "object")
 | 
					        self.object_path = os.path.join(self.base_path, "object")
 | 
				
			||||||
        self.messages_path = os.path.join(self.base_path, "messages")
 | 
					        self.messages_path = os.path.join(self.base_path, "messages")
 | 
				
			||||||
        self.files_path = os.path.join(self.conf_path, "files")
 | 
					        self.stdout_base_path = os.path.join(self.base_path, "stdout")
 | 
				
			||||||
 | 
					        self.stderr_base_path = os.path.join(self.base_path, "stderr")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Depending on conf_path
 | 
					        # Depending on conf_path
 | 
				
			||||||
 | 
					        self.files_path = os.path.join(self.conf_path, "files")
 | 
				
			||||||
        self.global_explorer_path = os.path.join(self.conf_path, "explorer")
 | 
					        self.global_explorer_path = os.path.join(self.conf_path, "explorer")
 | 
				
			||||||
        self.manifest_path = os.path.join(self.conf_path, "manifest")
 | 
					        self.manifest_path = os.path.join(self.conf_path, "manifest")
 | 
				
			||||||
        self.initial_manifest = (self.custom_initial_manifest or
 | 
					        self.initial_manifest = (self.custom_initial_manifest or
 | 
				
			||||||
| 
						 | 
					@ -165,6 +167,8 @@ class Local(object):
 | 
				
			||||||
        self.mkdir(self.object_path)
 | 
					        self.mkdir(self.object_path)
 | 
				
			||||||
        self.mkdir(self.bin_path)
 | 
					        self.mkdir(self.bin_path)
 | 
				
			||||||
        self.mkdir(self.cache_path)
 | 
					        self.mkdir(self.cache_path)
 | 
				
			||||||
 | 
					        self.mkdir(self.stdout_base_path)
 | 
				
			||||||
 | 
					        self.mkdir(self.stderr_base_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_files_dirs(self):
 | 
					    def create_files_dirs(self):
 | 
				
			||||||
        self._init_directories()
 | 
					        self._init_directories()
 | 
				
			||||||
| 
						 | 
					@ -200,7 +204,7 @@ class Local(object):
 | 
				
			||||||
        os.makedirs(path, exist_ok=True)
 | 
					        os.makedirs(path, exist_ok=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self, command, env=None, return_output=False, message_prefix=None,
 | 
					    def run(self, command, env=None, return_output=False, message_prefix=None,
 | 
				
			||||||
            save_output=True, quiet_mode=False):
 | 
					            stdout=None, stderr=None, save_output=True, quiet_mode=False):
 | 
				
			||||||
        """Run the given command with the given environment.
 | 
					        """Run the given command with the given environment.
 | 
				
			||||||
        Return the output as a string.
 | 
					        Return the output as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,6 +212,22 @@ class Local(object):
 | 
				
			||||||
        assert isinstance(command, (list, tuple)), (
 | 
					        assert isinstance(command, (list, tuple)), (
 | 
				
			||||||
                "list or tuple argument expected, got: %s" % command)
 | 
					                "list or tuple argument expected, got: %s" % command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        quiet = self.quiet_mode or quiet_mode
 | 
				
			||||||
 | 
					        do_save_output = save_output and not quiet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        close_stdout = False
 | 
				
			||||||
 | 
					        close_stderr = False
 | 
				
			||||||
 | 
					        if quiet:
 | 
				
			||||||
 | 
					            stderr = subprocess.DEVNULL
 | 
				
			||||||
 | 
					            stdout = subprocess.DEVNULL
 | 
				
			||||||
 | 
					        elif do_save_output:
 | 
				
			||||||
 | 
					            if not return_output and stdout is None:
 | 
				
			||||||
 | 
					                stdout = util.get_std_fd(self.stdout_base_path, 'local')
 | 
				
			||||||
 | 
					                close_stdout = True
 | 
				
			||||||
 | 
					            if stderr is None:
 | 
				
			||||||
 | 
					                stderr = util.get_std_fd(self.stderr_base_path, 'local')
 | 
				
			||||||
 | 
					                close_stderr = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if env is None:
 | 
					        if env is None:
 | 
				
			||||||
            env = os.environ.copy()
 | 
					            env = os.environ.copy()
 | 
				
			||||||
        # Export __target_host, __target_hostname, __target_fqdn
 | 
					        # Export __target_host, __target_hostname, __target_fqdn
 | 
				
			||||||
| 
						 | 
					@ -225,39 +245,33 @@ class Local(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.trace("Local run: %s", command)
 | 
					        self.log.trace("Local run: %s", command)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if self.quiet_mode or quiet_mode:
 | 
					 | 
				
			||||||
                stderr = subprocess.DEVNULL
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                stderr = None
 | 
					 | 
				
			||||||
            if save_output:
 | 
					 | 
				
			||||||
                output, errout = exec_util.call_get_output(
 | 
					 | 
				
			||||||
                    command, env=env, stderr=stderr)
 | 
					 | 
				
			||||||
                self.log.trace("Command: {}; local stdout: {}".format(
 | 
					 | 
				
			||||||
                    command, output))
 | 
					 | 
				
			||||||
                # Currently, stderr is not captured.
 | 
					 | 
				
			||||||
                # self.log.trace("Local stderr: {}".format(errout))
 | 
					 | 
				
			||||||
            if return_output:
 | 
					            if return_output:
 | 
				
			||||||
                    return output.decode()
 | 
					                output = subprocess.check_output(
 | 
				
			||||||
 | 
					                    command, env=env, stderr=stderr).decode()
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                # In some cases no output is saved.
 | 
					 | 
				
			||||||
                # This is used for shell command, stdout and stderr
 | 
					 | 
				
			||||||
                # must not be catched.
 | 
					 | 
				
			||||||
                if self.quiet_mode or quiet_mode:
 | 
					 | 
				
			||||||
                    stdout = subprocess.DEVNULL
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    stdout = None
 | 
					 | 
				
			||||||
                subprocess.check_call(command, env=env, stderr=stderr,
 | 
					                subprocess.check_call(command, env=env, stderr=stderr,
 | 
				
			||||||
                                      stdout=stdout)
 | 
					                                      stdout=stdout)
 | 
				
			||||||
 | 
					                output = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if do_save_output:
 | 
				
			||||||
 | 
					                util.log_std_fd(self.log, command, stderr, 'Local stderr')
 | 
				
			||||||
 | 
					                util.log_std_fd(self.log, command, stdout, 'Local stdout')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return output
 | 
				
			||||||
        except subprocess.CalledProcessError as e:
 | 
					        except subprocess.CalledProcessError as e:
 | 
				
			||||||
            exec_util.handle_called_process_error(e, command)
 | 
					            util.handle_called_process_error(e, command)
 | 
				
			||||||
        except OSError as error:
 | 
					        except OSError as error:
 | 
				
			||||||
            raise cdist.Error(" ".join(command) + ": " + error.args[1])
 | 
					            raise cdist.Error(" ".join(command) + ": " + error.args[1])
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            if message_prefix:
 | 
					            if message_prefix:
 | 
				
			||||||
                message.merge_messages()
 | 
					                message.merge_messages()
 | 
				
			||||||
 | 
					            if close_stdout:
 | 
				
			||||||
 | 
					                stdout.close()
 | 
				
			||||||
 | 
					            if close_stderr:
 | 
				
			||||||
 | 
					                stderr.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run_script(self, script, env=None, return_output=False,
 | 
					    def run_script(self, script, env=None, return_output=False,
 | 
				
			||||||
                   message_prefix=None, save_output=True):
 | 
					                   message_prefix=None, stdout=None, stderr=None):
 | 
				
			||||||
        """Run the given script with the given environment.
 | 
					        """Run the given script with the given environment.
 | 
				
			||||||
        Return the output as a string.
 | 
					        Return the output as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -271,8 +285,9 @@ class Local(object):
 | 
				
			||||||
                           script, " ".join(command))
 | 
					                           script, " ".join(command))
 | 
				
			||||||
            command.append(script)
 | 
					            command.append(script)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.run(command=command, env=env, return_output=return_output,
 | 
					        return self.run(command, env=env, return_output=return_output,
 | 
				
			||||||
                        message_prefix=message_prefix, save_output=save_output)
 | 
					                        message_prefix=message_prefix, stdout=stdout,
 | 
				
			||||||
 | 
					                        stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _cache_subpath_repl(self, matchobj):
 | 
					    def _cache_subpath_repl(self, matchobj):
 | 
				
			||||||
        if matchobj.group(2) == '%P':
 | 
					        if matchobj.group(2) == '%P':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ import logging
 | 
				
			||||||
import multiprocessing
 | 
					import multiprocessing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cdist
 | 
					import cdist
 | 
				
			||||||
import cdist.exec.util as exec_util
 | 
					import cdist.exec.util as util
 | 
				
			||||||
import cdist.util.ipaddr as ipaddr
 | 
					import cdist.util.ipaddr as ipaddr
 | 
				
			||||||
from cdist.mputil import mp_pool_run
 | 
					from cdist.mputil import mp_pool_run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,9 @@ class Remote(object):
 | 
				
			||||||
                 base_path=None,
 | 
					                 base_path=None,
 | 
				
			||||||
                 quiet_mode=None,
 | 
					                 quiet_mode=None,
 | 
				
			||||||
                 archiving_mode=None,
 | 
					                 archiving_mode=None,
 | 
				
			||||||
                 configuration=None):
 | 
					                 configuration=None,
 | 
				
			||||||
 | 
					                 stdout_base_path=None,
 | 
				
			||||||
 | 
					                 stderr_base_path=None):
 | 
				
			||||||
        self.target_host = target_host
 | 
					        self.target_host = target_host
 | 
				
			||||||
        self._exec = remote_exec
 | 
					        self._exec = remote_exec
 | 
				
			||||||
        self._copy = remote_copy
 | 
					        self._copy = remote_copy
 | 
				
			||||||
| 
						 | 
					@ -79,6 +81,9 @@ class Remote(object):
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.configuration = {}
 | 
					            self.configuration = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.stdout_base_path = stdout_base_path
 | 
				
			||||||
 | 
					        self.stderr_base_path = stderr_base_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.conf_path = os.path.join(self.base_path, "conf")
 | 
					        self.conf_path = os.path.join(self.base_path, "conf")
 | 
				
			||||||
        self.object_path = os.path.join(self.base_path, "object")
 | 
					        self.object_path = os.path.join(self.base_path, "object")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +110,7 @@ class Remote(object):
 | 
				
			||||||
        self._open_logger()
 | 
					        self._open_logger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _init_env(self):
 | 
					    def _init_env(self):
 | 
				
			||||||
        """Setup environment for scripts - HERE????"""
 | 
					        """Setup environment for scripts."""
 | 
				
			||||||
        # FIXME: better do so in exec functions that require it!
 | 
					        # FIXME: better do so in exec functions that require it!
 | 
				
			||||||
        os.environ['__remote_copy'] = self._copy
 | 
					        os.environ['__remote_copy'] = self._copy
 | 
				
			||||||
        os.environ['__remote_exec'] = self._exec
 | 
					        os.environ['__remote_exec'] = self._exec
 | 
				
			||||||
| 
						 | 
					@ -237,7 +242,8 @@ class Remote(object):
 | 
				
			||||||
        self.log.trace(("Multiprocessing for parallel transfer "
 | 
					        self.log.trace(("Multiprocessing for parallel transfer "
 | 
				
			||||||
                        "finished"))
 | 
					                        "finished"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run_script(self, script, env=None, return_output=False):
 | 
					    def run_script(self, script, env=None, return_output=False, stdout=None,
 | 
				
			||||||
 | 
					                   stderr=None):
 | 
				
			||||||
        """Run the given script with the given environment on the remote side.
 | 
					        """Run the given script with the given environment on the remote side.
 | 
				
			||||||
        Return the output as a string.
 | 
					        Return the output as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,9 +255,11 @@ class Remote(object):
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        command.append(script)
 | 
					        command.append(script)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.run(command, env, return_output)
 | 
					        return self.run(command, env=env, return_output=return_output,
 | 
				
			||||||
 | 
					                        stdout=stdout, stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self, command, env=None, return_output=False):
 | 
					    def run(self, command, env=None, return_output=False, stdout=None,
 | 
				
			||||||
 | 
					            stderr=None):
 | 
				
			||||||
        """Run the given command with the given environment on the remote side.
 | 
					        """Run the given command with the given environment on the remote side.
 | 
				
			||||||
        Return the output as a string.
 | 
					        Return the output as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -284,9 +292,11 @@ class Remote(object):
 | 
				
			||||||
            cmd.append(string_cmd)
 | 
					            cmd.append(string_cmd)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            cmd.extend(command)
 | 
					            cmd.extend(command)
 | 
				
			||||||
        return self._run_command(cmd, env=env, return_output=return_output)
 | 
					        return self._run_command(cmd, env=env, return_output=return_output,
 | 
				
			||||||
 | 
					                                 stdout=stdout, stderr=stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _run_command(self, command, env=None, return_output=False):
 | 
					    def _run_command(self, command, env=None, return_output=False, stdout=None,
 | 
				
			||||||
 | 
					                     stderr=None):
 | 
				
			||||||
        """Run the given command with the given environment.
 | 
					        """Run the given command with the given environment.
 | 
				
			||||||
        Return the output as a string.
 | 
					        Return the output as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,6 +304,18 @@ class Remote(object):
 | 
				
			||||||
        assert isinstance(command, (list, tuple)), (
 | 
					        assert isinstance(command, (list, tuple)), (
 | 
				
			||||||
                "list or tuple argument expected, got: %s" % command)
 | 
					                "list or tuple argument expected, got: %s" % command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if return_output and stdout is not subprocess.PIPE:
 | 
				
			||||||
 | 
					            self.log.debug("return_output is True, ignoring stdout")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        close_stdout = False
 | 
				
			||||||
 | 
					        close_stderr = False
 | 
				
			||||||
 | 
					        if not return_output and stdout is None:
 | 
				
			||||||
 | 
					            stdout = util.get_std_fd(self.stdout_base_path, 'remote')
 | 
				
			||||||
 | 
					            close_stdout = True
 | 
				
			||||||
 | 
					        if stderr is None:
 | 
				
			||||||
 | 
					            stderr = util.get_std_fd(self.stderr_base_path, 'remote')
 | 
				
			||||||
 | 
					            close_stderr = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # export target_host, target_hostname, target_fqdn
 | 
					        # export target_host, target_hostname, target_fqdn
 | 
				
			||||||
        # for use in __remote_{exec,copy} scripts
 | 
					        # for use in __remote_{exec,copy} scripts
 | 
				
			||||||
        os_environ = os.environ.copy()
 | 
					        os_environ = os.environ.copy()
 | 
				
			||||||
| 
						 | 
					@ -305,19 +327,26 @@ class Remote(object):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if self.quiet_mode:
 | 
					            if self.quiet_mode:
 | 
				
			||||||
                stderr = subprocess.DEVNULL
 | 
					                stderr = subprocess.DEVNULL
 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                stderr = None
 | 
					 | 
				
			||||||
            output, errout = exec_util.call_get_output(
 | 
					 | 
				
			||||||
                command, env=os_environ, stderr=stderr)
 | 
					 | 
				
			||||||
            self.log.trace("Command: {}; remote stdout: {}".format(
 | 
					 | 
				
			||||||
                command, output))
 | 
					 | 
				
			||||||
            # Currently, stderr is not captured.
 | 
					 | 
				
			||||||
            # self.log.trace("Remote stderr: {}".format(errout))
 | 
					 | 
				
			||||||
            if return_output:
 | 
					            if return_output:
 | 
				
			||||||
                return output.decode()
 | 
					                output = subprocess.check_output(command, env=os_environ,
 | 
				
			||||||
 | 
					                                                 stderr=stderr).decode()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                subprocess.check_call(command, env=os_environ, stdout=stdout,
 | 
				
			||||||
 | 
					                                      stderr=stderr)
 | 
				
			||||||
 | 
					                output = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            util.log_std_fd(self.log, command, stderr, 'Remote stderr')
 | 
				
			||||||
 | 
					            util.log_std_fd(self.log, command, stdout, 'Remote stdout')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return output
 | 
				
			||||||
        except subprocess.CalledProcessError as e:
 | 
					        except subprocess.CalledProcessError as e:
 | 
				
			||||||
            exec_util.handle_called_process_error(e, command)
 | 
					            util.handle_called_process_error(e, command)
 | 
				
			||||||
        except OSError as error:
 | 
					        except OSError as error:
 | 
				
			||||||
            raise cdist.Error(" ".join(command) + ": " + error.args[1])
 | 
					            raise cdist.Error(" ".join(command) + ": " + error.args[1])
 | 
				
			||||||
        except UnicodeDecodeError:
 | 
					        except UnicodeDecodeError:
 | 
				
			||||||
            raise DecodeError(command)
 | 
					            raise DecodeError(command)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            if close_stdout:
 | 
				
			||||||
 | 
					                stdout.close()
 | 
				
			||||||
 | 
					            if close_stderr:
 | 
				
			||||||
 | 
					                stderr.close()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2016 Darko Poljak (darko.poljak at gmail.com)
 | 
					# 2016-2017 Darko Poljak (darko.poljak at gmail.com)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
from tempfile import TemporaryFile
 | 
					from tempfile import TemporaryFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cdist
 | 
					import cdist
 | 
				
			||||||
| 
						 | 
					@ -115,6 +116,7 @@ import cdist
 | 
				
			||||||
#     return (result.stdout, result.stderr)
 | 
					#     return (result.stdout, result.stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Currently not used.
 | 
				
			||||||
def call_get_output(command, env=None, stderr=None):
 | 
					def call_get_output(command, env=None, stderr=None):
 | 
				
			||||||
    """Run the given command with the given environment.
 | 
					    """Run the given command with the given environment.
 | 
				
			||||||
    Return the tuple of stdout and stderr output as a byte strings.
 | 
					    Return the tuple of stdout and stderr output as a byte strings.
 | 
				
			||||||
| 
						 | 
					@ -145,6 +147,7 @@ def handle_called_process_error(err, command):
 | 
				
			||||||
                          " ".join(command), err.returncode, output))
 | 
					                          " ".join(command), err.returncode, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Currently not used.
 | 
				
			||||||
def _call_get_stdout(command, env=None, stderr=None):
 | 
					def _call_get_stdout(command, env=None, stderr=None):
 | 
				
			||||||
    """Run the given command with the given environment.
 | 
					    """Run the given command with the given environment.
 | 
				
			||||||
    Return the stdout output as a byte string, stderr is ignored.
 | 
					    Return the stdout output as a byte string, stderr is ignored.
 | 
				
			||||||
| 
						 | 
					@ -158,3 +161,16 @@ def _call_get_stdout(command, env=None, stderr=None):
 | 
				
			||||||
        output = fout.read()
 | 
					        output = fout.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return output
 | 
					    return output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_std_fd(base_path, name):
 | 
				
			||||||
 | 
					    path = os.path.join(base_path, name)
 | 
				
			||||||
 | 
					    stdfd = open(path, 'ba+')
 | 
				
			||||||
 | 
					    return stdfd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def log_std_fd(log, command, stdfd, prefix):
 | 
				
			||||||
 | 
					    if stdfd is not None and stdfd != subprocess.DEVNULL:
 | 
				
			||||||
 | 
					        stdfd.seek(0, 0)
 | 
				
			||||||
 | 
					        log.trace("Command: {}; {}: {}".format(
 | 
				
			||||||
 | 
					            command, prefix, stdfd.read().decode()))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,6 @@ class Shell(object):
 | 
				
			||||||
        self._init_environment()
 | 
					        self._init_environment()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log.trace("Starting shell...")
 | 
					        log.trace("Starting shell...")
 | 
				
			||||||
        # save_output=False -> do not catch stdout and stderr
 | 
					 | 
				
			||||||
        self.local.run([self.shell], self.env, save_output=False)
 | 
					        self.local.run([self.shell], self.env, save_output=False)
 | 
				
			||||||
        log.trace("Finished shell.")
 | 
					        log.trace("Finished shell.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										137
									
								
								cdist/test/capture_output/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								cdist/test/capture_output/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,137 @@
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
 | 
					# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is part of cdist.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# cdist is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# cdist is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					# along with cdist. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cdist
 | 
				
			||||||
 | 
					from cdist import core
 | 
				
			||||||
 | 
					from cdist import test
 | 
				
			||||||
 | 
					from cdist.exec import local
 | 
				
			||||||
 | 
					from cdist.exec import remote
 | 
				
			||||||
 | 
					from cdist.core import code
 | 
				
			||||||
 | 
					from cdist.core import manifest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os.path as op
 | 
				
			||||||
 | 
					my_dir = op.abspath(op.dirname(__file__))
 | 
				
			||||||
 | 
					fixtures = op.join(my_dir, 'fixtures')
 | 
				
			||||||
 | 
					conf_dir = op.join(fixtures, 'conf')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CaptureOutputTestCase(test.CdistTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        # logging.root.setLevel(logging.TRACE)
 | 
				
			||||||
 | 
					        self.temp_dir = self.mkdtemp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.local_dir = os.path.join(self.temp_dir, "local")
 | 
				
			||||||
 | 
					        self.hostdir = cdist.str_hash(self.target_host[0])
 | 
				
			||||||
 | 
					        self.host_base_path = os.path.join(self.local_dir, self.hostdir)
 | 
				
			||||||
 | 
					        os.makedirs(self.host_base_path)
 | 
				
			||||||
 | 
					        self.local = local.Local(
 | 
				
			||||||
 | 
					            target_host=self.target_host,
 | 
				
			||||||
 | 
					            target_host_tags=None,
 | 
				
			||||||
 | 
					            base_root_path=self.host_base_path,
 | 
				
			||||||
 | 
					            host_dir_name=self.hostdir,
 | 
				
			||||||
 | 
					            exec_path=cdist.test.cdist_exec_path,
 | 
				
			||||||
 | 
					            add_conf_dirs=[conf_dir])
 | 
				
			||||||
 | 
					        self.local.create_files_dirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.remote_dir = self.mkdtemp()
 | 
				
			||||||
 | 
					        remote_exec = self.remote_exec
 | 
				
			||||||
 | 
					        remote_copy = self.remote_copy
 | 
				
			||||||
 | 
					        self.remote = remote.Remote(
 | 
				
			||||||
 | 
					            target_host=self.target_host,
 | 
				
			||||||
 | 
					            remote_exec=remote_exec,
 | 
				
			||||||
 | 
					            remote_copy=remote_copy,
 | 
				
			||||||
 | 
					            base_path=self.remote_dir,
 | 
				
			||||||
 | 
					            stdout_base_path=self.local.stdout_base_path,
 | 
				
			||||||
 | 
					            stderr_base_path=self.local.stderr_base_path)
 | 
				
			||||||
 | 
					        self.remote.create_files_dirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.code = code.Code(self.target_host, self.local, self.remote)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.manifest = manifest.Manifest(self.target_host, self.local)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.cdist_type = core.CdistType(self.local.type_path,
 | 
				
			||||||
 | 
					                                         '__write_to_stdout_and_stderr')
 | 
				
			||||||
 | 
					        self.cdist_object = core.CdistObject(self.cdist_type,
 | 
				
			||||||
 | 
					                                             self.local.object_path,
 | 
				
			||||||
 | 
					                                             self.local.object_marker_name,
 | 
				
			||||||
 | 
					                                             '')
 | 
				
			||||||
 | 
					        self.cdist_object.create()
 | 
				
			||||||
 | 
					        self.output_dirs = {
 | 
				
			||||||
 | 
					            'object': {
 | 
				
			||||||
 | 
					                'stdout': os.path.join(self.cdist_object.absolute_path,
 | 
				
			||||||
 | 
					                                       'stdout'),
 | 
				
			||||||
 | 
					                'stderr': os.path.join(self.cdist_object.absolute_path,
 | 
				
			||||||
 | 
					                                       'stderr'),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'init': {
 | 
				
			||||||
 | 
					                'stdout': os.path.join(self.local.base_path, 'stdout'),
 | 
				
			||||||
 | 
					                'stderr': os.path.join(self.local.base_path, 'stderr'),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        shutil.rmtree(self.local_dir)
 | 
				
			||||||
 | 
					        shutil.rmtree(self.remote_dir)
 | 
				
			||||||
 | 
					        shutil.rmtree(self.temp_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _test_output(self, which, target, streams=('stdout', 'stderr')):
 | 
				
			||||||
 | 
					        for stream in streams:
 | 
				
			||||||
 | 
					            _should = '{0}: {1}\n'.format(which, stream)
 | 
				
			||||||
 | 
					            stream_path = os.path.join(self.output_dirs[target][stream], which)
 | 
				
			||||||
 | 
					            with open(stream_path, 'r') as fd:
 | 
				
			||||||
 | 
					                _is = fd.read()
 | 
				
			||||||
 | 
					            self.assertEqual(_should, _is)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_capture_code_output(self):
 | 
				
			||||||
 | 
					        self.cdist_object.code_local = self.code.run_gencode_local(
 | 
				
			||||||
 | 
					            self.cdist_object)
 | 
				
			||||||
 | 
					        self._test_output('gencode-local', 'object', ('stderr',))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.code.run_code_local(self.cdist_object)
 | 
				
			||||||
 | 
					        self._test_output('code-local', 'object')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.cdist_object.code_remote = self.code.run_gencode_remote(
 | 
				
			||||||
 | 
					            self.cdist_object)
 | 
				
			||||||
 | 
					        self._test_output('gencode-remote', 'object', ('stderr',))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.code.transfer_code_remote(self.cdist_object)
 | 
				
			||||||
 | 
					        self.code.run_code_remote(self.cdist_object)
 | 
				
			||||||
 | 
					        self._test_output('code-remote', 'object')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_capture_manifest_output(self):
 | 
				
			||||||
 | 
					        self.manifest.run_type_manifest(self.cdist_object)
 | 
				
			||||||
 | 
					        self._test_output('manifest', 'object')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_capture_init_manifest_output(self):
 | 
				
			||||||
 | 
					        initial_manifest = os.path.join(conf_dir, 'manifest', 'init')
 | 
				
			||||||
 | 
					        self.manifest.run_initial_manifest(initial_manifest)
 | 
				
			||||||
 | 
					        self._test_output('init', 'init')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unittest.main()
 | 
				
			||||||
							
								
								
									
										4
									
								
								cdist/test/capture_output/fixtures/conf/manifest/init
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								cdist/test/capture_output/fixtures/conf/manifest/init
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "init: stdout"
 | 
				
			||||||
 | 
					echo "init: stderr" >&2
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "gencode-local: stderr" >&2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "echo \"code-local: stdout\""
 | 
				
			||||||
 | 
					echo "echo \"code-local: stderr\" >&2"
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "gencode-remote: stderr" >&2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "echo \"code-remote: stdout\""
 | 
				
			||||||
 | 
					echo "echo \"code-remote: stderr\" >&2"
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "manifest: stdout"
 | 
				
			||||||
 | 
					echo "manifest: stderr" >&2
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of cdist.
 | 
					# This file is part of cdist.
 | 
				
			||||||
| 
						 | 
					@ -61,7 +61,9 @@ class CodeTestCase(test.CdistTestCase):
 | 
				
			||||||
            target_host=self.target_host,
 | 
					            target_host=self.target_host,
 | 
				
			||||||
            remote_exec=remote_exec,
 | 
					            remote_exec=remote_exec,
 | 
				
			||||||
            remote_copy=remote_copy,
 | 
					            remote_copy=remote_copy,
 | 
				
			||||||
            base_path=self.remote_dir)
 | 
					            base_path=self.remote_dir,
 | 
				
			||||||
 | 
					            stdout_base_path=self.local.stdout_base_path,
 | 
				
			||||||
 | 
					            stderr_base_path=self.local.stderr_base_path)
 | 
				
			||||||
        self.remote.create_files_dirs()
 | 
					        self.remote.create_files_dirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.code = code.Code(self.target_host, self.local, self.remote)
 | 
					        self.code = code.Code(self.target_host, self.local, self.remote)
 | 
				
			||||||
| 
						 | 
					@ -152,6 +154,7 @@ class CodeTestCase(test.CdistTestCase):
 | 
				
			||||||
        self.code.transfer_code_remote(self.cdist_object)
 | 
					        self.code.transfer_code_remote(self.cdist_object)
 | 
				
			||||||
        self.code.run_code_remote(self.cdist_object)
 | 
					        self.code.run_code_remote(self.cdist_object)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    import unittest
 | 
					    import unittest
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
					# 2010-2017 Steven Armstrong (steven-cdist at armstrong.cc)
 | 
				
			||||||
# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
					# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
# 2014      Daniel Heule     (hda at sfs.biz)
 | 
					# 2014      Daniel Heule     (hda at sfs.biz)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,19 @@ expected_object_names = sorted([
 | 
				
			||||||
    '__third/moon'])
 | 
					    '__third/moon'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CdistObjectErrorContext(object):
 | 
				
			||||||
 | 
					    def __init__(self, original_error):
 | 
				
			||||||
 | 
					        self.original_error = original_error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __enter__(self):
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __exit__(self, exc_type, exc_value, tb):
 | 
				
			||||||
 | 
					        if exc_type is not None:
 | 
				
			||||||
 | 
					            if exc_value.original_error:
 | 
				
			||||||
 | 
					                raise exc_value.original_error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConfigRunTestCase(test.CdistTestCase):
 | 
					class ConfigRunTestCase(test.CdistTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
| 
						 | 
					@ -87,7 +100,9 @@ class ConfigRunTestCase(test.CdistTestCase):
 | 
				
			||||||
            target_host=self.target_host,
 | 
					            target_host=self.target_host,
 | 
				
			||||||
            remote_copy=self.remote_copy,
 | 
					            remote_copy=self.remote_copy,
 | 
				
			||||||
            remote_exec=self.remote_exec,
 | 
					            remote_exec=self.remote_exec,
 | 
				
			||||||
            base_path=self.remote_dir)
 | 
					            base_path=self.remote_dir,
 | 
				
			||||||
 | 
					            stdout_base_path=self.local.stdout_base_path,
 | 
				
			||||||
 | 
					            stderr_base_path=self.local.stderr_base_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.local.object_path = self.object_base_path
 | 
					        self.local.object_path = self.object_base_path
 | 
				
			||||||
        self.local.type_path = type_base_path
 | 
					        self.local.type_path = type_base_path
 | 
				
			||||||
| 
						 | 
					@ -102,6 +117,20 @@ class ConfigRunTestCase(test.CdistTestCase):
 | 
				
			||||||
        os.environ = self.orig_environ
 | 
					        os.environ = self.orig_environ
 | 
				
			||||||
        shutil.rmtree(self.temp_dir)
 | 
					        shutil.rmtree(self.temp_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def assertRaisesCdistObjectError(self, original_error, callable_obj):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Test if a raised CdistObjectError was caused by the given
 | 
				
			||||||
 | 
					        original_error.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        with self.assertRaises(original_error):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                callable_obj()
 | 
				
			||||||
 | 
					            except cdist.CdistObjectError as e:
 | 
				
			||||||
 | 
					                if e.original_error:
 | 
				
			||||||
 | 
					                    raise e.original_error
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dependency_resolution(self):
 | 
					    def test_dependency_resolution(self):
 | 
				
			||||||
        first = self.object_index['__first/man']
 | 
					        first = self.object_index['__first/man']
 | 
				
			||||||
        second = self.object_index['__second/on-the']
 | 
					        second = self.object_index['__second/on-the']
 | 
				
			||||||
| 
						 | 
					@ -137,29 +166,33 @@ class ConfigRunTestCase(test.CdistTestCase):
 | 
				
			||||||
        first.requirements = [second.name]
 | 
					        first.requirements = [second.name]
 | 
				
			||||||
        second.requirements = [first.name]
 | 
					        second.requirements = [first.name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.assertRaises(cdist.UnresolvableRequirementsError):
 | 
					        self.assertRaisesCdistObjectError(
 | 
				
			||||||
            self.config.iterate_until_finished()
 | 
					            cdist.UnresolvableRequirementsError,
 | 
				
			||||||
 | 
					            self.config.iterate_until_finished)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_missing_requirements(self):
 | 
					    def test_missing_requirements(self):
 | 
				
			||||||
        """Throw an error if requiring something non-existing"""
 | 
					        """Throw an error if requiring something non-existing"""
 | 
				
			||||||
        first = self.object_index['__first/man']
 | 
					        first = self.object_index['__first/man']
 | 
				
			||||||
        first.requirements = ['__first/not/exist']
 | 
					        first.requirements = ['__first/not/exist']
 | 
				
			||||||
        with self.assertRaises(cdist.UnresolvableRequirementsError):
 | 
					        self.assertRaisesCdistObjectError(
 | 
				
			||||||
            self.config.iterate_until_finished()
 | 
					            cdist.UnresolvableRequirementsError,
 | 
				
			||||||
 | 
					            self.config.iterate_until_finished)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_requirement_broken_type(self):
 | 
					    def test_requirement_broken_type(self):
 | 
				
			||||||
        """Unknown type should be detected in the resolving process"""
 | 
					        """Unknown type should be detected in the resolving process"""
 | 
				
			||||||
        first = self.object_index['__first/man']
 | 
					        first = self.object_index['__first/man']
 | 
				
			||||||
        first.requirements = ['__nosuchtype/not/exist']
 | 
					        first.requirements = ['__nosuchtype/not/exist']
 | 
				
			||||||
        with self.assertRaises(cdist.core.cdist_type.InvalidTypeError):
 | 
					        self.assertRaisesCdistObjectError(
 | 
				
			||||||
            self.config.iterate_until_finished()
 | 
					            cdist.core.cdist_type.InvalidTypeError,
 | 
				
			||||||
 | 
					            self.config.iterate_until_finished)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_requirement_singleton_where_no_singleton(self):
 | 
					    def test_requirement_singleton_where_no_singleton(self):
 | 
				
			||||||
        """Missing object id should be detected in the resolving process"""
 | 
					        """Missing object id should be detected in the resolving process"""
 | 
				
			||||||
        first = self.object_index['__first/man']
 | 
					        first = self.object_index['__first/man']
 | 
				
			||||||
        first.requirements = ['__first']
 | 
					        first.requirements = ['__first']
 | 
				
			||||||
        with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError):
 | 
					        self.assertRaisesCdistObjectError(
 | 
				
			||||||
            self.config.iterate_until_finished()
 | 
					            cdist.core.cdist_object.MissingObjectIdError,
 | 
				
			||||||
 | 
					            self.config.iterate_until_finished)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dryrun(self):
 | 
					    def test_dryrun(self):
 | 
				
			||||||
        """Test if the dryrun option is working like expected"""
 | 
					        """Test if the dryrun option is working like expected"""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,12 +40,24 @@ class RemoteTestCase(test.CdistTestCase):
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        # another temp dir for remote base path
 | 
					        # another temp dir for remote base path
 | 
				
			||||||
        self.base_path = self.mkdtemp()
 | 
					        self.base_path = self.mkdtemp()
 | 
				
			||||||
 | 
					        self.remote = self.create_remote()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_remote(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        if not args:
 | 
				
			||||||
 | 
					            args = (self.target_host,)
 | 
				
			||||||
 | 
					        kwargs.setdefault('base_path', self.base_path)
 | 
				
			||||||
        user = getpass.getuser()
 | 
					        user = getpass.getuser()
 | 
				
			||||||
        remote_exec = "ssh -o User=%s -q" % user
 | 
					        kwargs.setdefault('remote_exec', 'ssh -o User=%s -q' % user)
 | 
				
			||||||
        remote_copy = "scp -o User=%s -q" % user
 | 
					        kwargs.setdefault('remote_copy', 'scp -o User=%s -q' % user)
 | 
				
			||||||
        self.remote = remote.Remote(self.target_host, base_path=self.base_path,
 | 
					        if 'stdout_base_path' not in kwargs:
 | 
				
			||||||
                                    remote_exec=remote_exec,
 | 
					            stdout_path = os.path.join(self.temp_dir, 'stdout')
 | 
				
			||||||
                                    remote_copy=remote_copy)
 | 
					            os.makedirs(stdout_path, exist_ok=True)
 | 
				
			||||||
 | 
					            kwargs['stdout_base_path'] = stdout_path
 | 
				
			||||||
 | 
					        if 'stderr_base_path' not in kwargs:
 | 
				
			||||||
 | 
					            stderr_path = os.path.join(self.temp_dir, 'stderr')
 | 
				
			||||||
 | 
					            os.makedirs(stderr_path, exist_ok=True)
 | 
				
			||||||
 | 
					            kwargs['stderr_base_path'] = stderr_path
 | 
				
			||||||
 | 
					        return remote.Remote(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
        shutil.rmtree(self.temp_dir)
 | 
					        shutil.rmtree(self.temp_dir)
 | 
				
			||||||
| 
						 | 
					@ -155,8 +167,8 @@ class RemoteTestCase(test.CdistTestCase):
 | 
				
			||||||
        os.chmod(remote_exec_path, 0o755)
 | 
					        os.chmod(remote_exec_path, 0o755)
 | 
				
			||||||
        remote_exec = remote_exec_path
 | 
					        remote_exec = remote_exec_path
 | 
				
			||||||
        remote_copy = "echo"
 | 
					        remote_copy = "echo"
 | 
				
			||||||
        r = remote.Remote(self.target_host, base_path=self.base_path,
 | 
					        r = self.create_remote(remote_exec=remote_exec,
 | 
				
			||||||
                          remote_exec=remote_exec, remote_copy=remote_copy)
 | 
					                               remote_copy=remote_copy)
 | 
				
			||||||
        self.assertEqual(r.run('true', return_output=True),
 | 
					        self.assertEqual(r.run('true', return_output=True),
 | 
				
			||||||
                         "%s\n" % self.target_host[0])
 | 
					                         "%s\n" % self.target_host[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,8 +179,8 @@ class RemoteTestCase(test.CdistTestCase):
 | 
				
			||||||
        os.chmod(remote_exec_path, 0o755)
 | 
					        os.chmod(remote_exec_path, 0o755)
 | 
				
			||||||
        remote_exec = remote_exec_path
 | 
					        remote_exec = remote_exec_path
 | 
				
			||||||
        remote_copy = "echo"
 | 
					        remote_copy = "echo"
 | 
				
			||||||
        r = remote.Remote(self.target_host, base_path=self.base_path,
 | 
					        r = self.create_remote(remote_exec=remote_exec,
 | 
				
			||||||
                          remote_exec=remote_exec, remote_copy=remote_copy)
 | 
					                               remote_copy=remote_copy)
 | 
				
			||||||
        handle, script = self.mkstemp(dir=self.temp_dir)
 | 
					        handle, script = self.mkstemp(dir=self.temp_dir)
 | 
				
			||||||
        with os.fdopen(handle, "w") as fd:
 | 
					        with os.fdopen(handle, "w") as fd:
 | 
				
			||||||
            fd.writelines(["#!/bin/sh\n", "true"])
 | 
					            fd.writelines(["#!/bin/sh\n", "true"])
 | 
				
			||||||
| 
						 | 
					@ -189,8 +201,8 @@ class RemoteTestCase(test.CdistTestCase):
 | 
				
			||||||
        os.chmod(remote_exec_path, 0o755)
 | 
					        os.chmod(remote_exec_path, 0o755)
 | 
				
			||||||
        remote_exec = remote_exec_path
 | 
					        remote_exec = remote_exec_path
 | 
				
			||||||
        remote_copy = "echo"
 | 
					        remote_copy = "echo"
 | 
				
			||||||
        r = remote.Remote(self.target_host, base_path=self.base_path,
 | 
					        r = self.create_remote(remote_exec=remote_exec,
 | 
				
			||||||
                          remote_exec=remote_exec, remote_copy=remote_copy)
 | 
					                               remote_copy=remote_copy)
 | 
				
			||||||
        output = r.run_script(script, return_output=True)
 | 
					        output = r.run_script(script, return_output=True)
 | 
				
			||||||
        self.assertEqual(output, "no_env\n")
 | 
					        self.assertEqual(output, "no_env\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,8 +214,8 @@ class RemoteTestCase(test.CdistTestCase):
 | 
				
			||||||
        env = {
 | 
					        env = {
 | 
				
			||||||
            '__object': 'test_object',
 | 
					            '__object': 'test_object',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        r = remote.Remote(self.target_host, base_path=self.base_path,
 | 
					        r = self.create_remote(remote_exec=remote_exec,
 | 
				
			||||||
                          remote_exec=remote_exec, remote_copy=remote_copy)
 | 
					                               remote_copy=remote_copy)
 | 
				
			||||||
        output = r.run_script(script, env=env, return_output=True)
 | 
					        output = r.run_script(script, env=env, return_output=True)
 | 
				
			||||||
        self.assertEqual(output, "test_object\n")
 | 
					        self.assertEqual(output, "test_object\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,9 @@ class ExplorerClassTestCase(test.CdistTestCase):
 | 
				
			||||||
            target_host=self.target_host,
 | 
					            target_host=self.target_host,
 | 
				
			||||||
            remote_exec=self.remote_exec,
 | 
					            remote_exec=self.remote_exec,
 | 
				
			||||||
            remote_copy=self.remote_copy,
 | 
					            remote_copy=self.remote_copy,
 | 
				
			||||||
            base_path=self.remote_base_path)
 | 
					            base_path=self.remote_base_path,
 | 
				
			||||||
 | 
					            stdout_base_path=self.local.stdout_base_path,
 | 
				
			||||||
 | 
					            stderr_base_path=self.local.stderr_base_path)
 | 
				
			||||||
        self.remote.create_files_dirs()
 | 
					        self.remote.create_files_dirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.explorer = explorer.Explorer(
 | 
					        self.explorer = explorer.Explorer(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,6 +109,7 @@ class ManifestTestCase(test.CdistTestCase):
 | 
				
			||||||
        cdist_object = core.CdistObject(cdist_type, self.local.object_path,
 | 
					        cdist_object = core.CdistObject(cdist_type, self.local.object_path,
 | 
				
			||||||
                                        self.local.object_marker_name,
 | 
					                                        self.local.object_marker_name,
 | 
				
			||||||
                                        'whatever')
 | 
					                                        'whatever')
 | 
				
			||||||
 | 
					        cdist_object.create()
 | 
				
			||||||
        handle, output_file = self.mkstemp(dir=self.temp_dir)
 | 
					        handle, output_file = self.mkstemp(dir=self.temp_dir)
 | 
				
			||||||
        os.close(handle)
 | 
					        os.close(handle)
 | 
				
			||||||
        os.environ['__cdist_test_out'] = output_file
 | 
					        os.environ['__cdist_test_out'] = output_file
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ next:
 | 
				
			||||||
	* Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková)
 | 
						* Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková)
 | 
				
			||||||
	* Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null	instead of closing them (michal-hanu-la)
 | 
						* Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null	instead of closing them (michal-hanu-la)
 | 
				
			||||||
	* Type __daemontools: Make it more robust and clean up the code (Kamila Součková)
 | 
						* Type __daemontools: Make it more robust and clean up the code (Kamila Součková)
 | 
				
			||||||
 | 
						* Core: Save output streams (Steven Armstrong, Darko Poljak)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4.7.3: 2017-11-10
 | 
					4.7.3: 2017-11-10
 | 
				
			||||||
	* Type __ccollect_source: Add create destination parameter (Dominique Roux)
 | 
						* Type __ccollect_source: Add create destination parameter (Dominique Roux)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue