diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 39d8ca40..5bde16b9 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -22,6 +23,7 @@ import argparse import logging import os +import sys import cdist from cdist import core @@ -67,6 +69,7 @@ class Emulator(object): self.commandline() self.setup_object() + self.save_stdin() self.record_requirements() self.record_auto_requirements() self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) @@ -137,6 +140,27 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) + chunk_size = 8192 + def _read_stdin(self): + return sys.stdin.buffer.read(self.chunk_size) + def save_stdin(self): + """If something is written to stdin, save it in the object as + $__object/stdin so it can be accessed in manifest and gencode-* + scripts. + """ + if not sys.stdin.isatty(): + try: + # go directly to file instead of using CdistObject's api + # as that does not support streaming + path = os.path.join(self.cdist_object.absolute_path, 'stdin') + with open(path, 'wb') as fd: + chunk = self._read_stdin() + while chunk: + fd.write(chunk) + chunk = self._read_stdin() + except EnvironmentError as e: + raise cdist.Error('Failed to read from stdin: %s' % e) + def record_requirements(self): """record requirements""" diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 077ea111..ff18fe87 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -21,12 +21,17 @@ import os import shutil +import string +import filecmp +import random import cdist from cdist import test from cdist.exec import local from cdist import emulator from cdist import core +from cdist import config +import cdist.context local_base_path = test.cdist_base_path @@ -114,8 +119,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) def tearDown(self): - pass - #shutil.rmtree(self.temp_dir) + shutil.rmtree(self.temp_dir) def test_autorequire(self): initial_manifest = os.path.join(self.local.manifest_path, "init") @@ -216,3 +220,47 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertTrue('optional1' in cdist_object.parameters) self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) + + +class StdinTestCase(test.CdistTestCase): + + def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.target_host = 'localhost' + self.temp_dir = self.mkdtemp() + os.environ['__cdist_out_dir'] = self.temp_dir + local_base_path = fixtures + + self.context = cdist.context.Context( + target_host=self.target_host, + remote_copy='scp -o User=root -q', + remote_exec='ssh -o User=root -q', + base_path=local_base_path, + exec_path=test.cdist_exec_path, + debug=False) + self.config = config.Config(self.context) + + def tearDown(self): + os.environ = self.orig_environ + shutil.rmtree(self.temp_dir) + + def test_file_from_stdin(self): + handle, destination = self.mkstemp(dir=self.temp_dir) + os.close(handle) + source_handle, source = self.mkstemp(dir=self.temp_dir) + candidates = string.ascii_letters+string.digits + with os.fdopen(source_handle, 'w') as fd: + for x in range(100): + fd.write(''.join(random.sample(candidates, len(candidates)))) + + handle, initial_manifest = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.write('__file_from_stdin %s --source %s\n' % (destination, source)) + self.context.initial_manifest = initial_manifest + self.config.stage_prepare() + + cdist_type = core.CdistType(self.config.local.type_path, '__file') + cdist_object = core.CdistObject(cdist_type, self.config.local.object_path, destination) + # Test weither stdin has been stored correctly + self.assertTrue(filecmp.cmp(source, os.path.join(cdist_object.absolute_path, 'stdin'))) diff --git a/lib/cdist/test/emulator/fixtures/conf/explorer/.keep b/lib/cdist/test/emulator/fixtures/conf/explorer/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file b/lib/cdist/test/emulator/fixtures/conf/type/__file new file mode 120000 index 00000000..c57c4134 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file @@ -0,0 +1 @@ +../../../../../../../conf/type/__file \ No newline at end of file diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest new file mode 100755 index 00000000..b4908cbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +source="$(cat "$__object/parameter/source")" +cat "$source" | __file "/$__object_id" --source /dev/null diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required @@ -0,0 +1 @@ +source