forked from ungleich-public/cdist
		
	Merge branch 'master' into preos
Signed-off-by: Nico Schottelius <nico@bento.schottelius.org> Conflicts: docs/changelog
This commit is contained in:
		
				commit
				
					
						84eb05aed6
					
				
			
		
					 19 changed files with 468 additions and 59 deletions
				
			
		|  | @ -30,6 +30,7 @@ create_file= | ||||||
| if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then | if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then | ||||||
|    if [ ! -f "$__object/parameter/source" ]; then |    if [ ! -f "$__object/parameter/source" ]; then | ||||||
|       create_file=1 |       create_file=1 | ||||||
|  |       echo create >> "$__messages_out" | ||||||
|    else |    else | ||||||
|       source="$(cat "$__object/parameter/source")" |       source="$(cat "$__object/parameter/source")" | ||||||
|       if [ "$source" = "-" ]; then |       if [ "$source" = "-" ]; then | ||||||
|  | @ -64,6 +65,7 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then | ||||||
| destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")" | destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")" | ||||||
| DONE | DONE | ||||||
|       if [ "$upload_file" ]; then |       if [ "$upload_file" ]; then | ||||||
|  |          echo upload >> "$__messages_out" | ||||||
|          cat << DONE |          cat << DONE | ||||||
| $__remote_copy $source ${__target_host}:\$destination_upload | $__remote_copy $source ${__target_host}:\$destination_upload | ||||||
| DONE | DONE | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| #!/bin/sh | #!/bin/sh | ||||||
| # | # | ||||||
| # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) | # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) | ||||||
| # 2013 Steven Armstrong (steven-cdist armstrong.cc) | # 2013 Steven Armstrong (steven-cdist armstrong.cc) | ||||||
| # | # | ||||||
| # This file is part of cdist. | # This file is part of cdist. | ||||||
|  | @ -26,58 +26,69 @@ stat_file="$__object/explorer/stat" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| get_current_value() { | get_current_value() { | ||||||
|    if [ -s "$stat_file" ]; then |     if [ -s "$stat_file" ]; then | ||||||
|       _name="$1" |         _name="$1" | ||||||
|       _value="$2" |         _value="$2" | ||||||
|       case "$_value" in |         case "$_value" in | ||||||
|          [0-9]*) |             [0-9]*) | ||||||
|             _index=2 |                 _index=2 | ||||||
|          ;; |             ;; | ||||||
|          *) |             *) | ||||||
|             _index=3 |                 _index=3 | ||||||
|          ;; |             ;; | ||||||
|       esac |         esac | ||||||
|       awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" |         awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" | ||||||
|       unset _name _value _index |         unset _name _value _index | ||||||
|    fi |     fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| set_group() { | set_group() { | ||||||
|    echo chgrp \"$1\" \"$destination\" |     echo chgrp \"$1\" \"$destination\" | ||||||
|  |     echo chgrp $1 >> "$__messages_out" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| set_owner() { | set_owner() { | ||||||
|    echo chown \"$1\" \"$destination\" |     echo chown \"$1\" \"$destination\" | ||||||
|  |     echo chown $1 >> "$__messages_out" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| set_mode() { | set_mode() { | ||||||
|    echo chmod \"$1\" \"$destination\" |    echo chmod \"$1\" \"$destination\" | ||||||
|  |    echo chmod $1 >> "$__messages_out" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| set_attributes= | set_attributes= | ||||||
| case "$state_should" in | case "$state_should" in | ||||||
|    present|exists) |     present|exists) | ||||||
|       # Note: Mode - needs to happen last as a chown/chgrp can alter mode by |     # Note: Mode - needs to happen last as a chown/chgrp can alter mode by | ||||||
|       #  clearing S_ISUID and S_ISGID bits (see chown(2)) |     #  clearing S_ISUID and S_ISGID bits (see chown(2)) | ||||||
|       for attribute in group owner mode; do |     for attribute in group owner mode; do | ||||||
|          if [ -f "$__object/parameter/$attribute" ]; then |         if [ -f "$__object/parameter/$attribute" ]; then | ||||||
|             value_should="$(cat "$__object/parameter/$attribute")" |             value_should="$(cat "$__object/parameter/$attribute")" | ||||||
|  | 
 | ||||||
|  |             # change 0xxx format to xxx format => same as stat returns | ||||||
|  |             if [ "$attribute" = mode ]; then | ||||||
|  |                 value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" | ||||||
|  |             fi | ||||||
|  |              | ||||||
|             value_is="$(get_current_value "$attribute" "$value_should")" |             value_is="$(get_current_value "$attribute" "$value_should")" | ||||||
|             if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then |             if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then | ||||||
|                "set_$attribute" "$value_should" |                 "set_$attribute" "$value_should" | ||||||
|             fi |             fi | ||||||
|          fi |         fi | ||||||
|       done |     done | ||||||
|    ;; |  | ||||||
| 
 | 
 | ||||||
|    absent) |     ;; | ||||||
|       if [ "$type" = "file" ]; then |  | ||||||
|          echo rm -f \"$destination\" |  | ||||||
|       fi |  | ||||||
|    ;; |  | ||||||
| 
 | 
 | ||||||
|    *) |     absent) | ||||||
|       echo "Unknown state: $state_should" >&2 |         if [ "$type" = "file" ]; then | ||||||
|       exit 1 |             echo rm -f \"$destination\" | ||||||
|    ;; |             echo remove >> "$__messages_out" | ||||||
|  |         fi | ||||||
|  |     ;; | ||||||
|  | 
 | ||||||
|  |     *) | ||||||
|  |         echo "Unknown state: $state_should" >&2 | ||||||
|  |         exit 1 | ||||||
|  |     ;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
|  | @ -50,6 +50,21 @@ source:: | ||||||
|    If not supplied, an empty file or directory will be created. |    If not supplied, an empty file or directory will be created. | ||||||
|    If source is '-' (dash), take what was written to stdin as the file content. |    If source is '-' (dash), take what was written to stdin as the file content. | ||||||
| 
 | 
 | ||||||
|  | MESSAGES | ||||||
|  | -------- | ||||||
|  | chgrp <group>:: | ||||||
|  |     Changed group membership | ||||||
|  | chown <owner>:: | ||||||
|  |     Changed owner | ||||||
|  | chmod <mode>:: | ||||||
|  |     Changed mode | ||||||
|  | create:: | ||||||
|  |     Empty file was created (no --source specified) | ||||||
|  | remove:: | ||||||
|  |     File exists, but state is absent, file will be removed by generated code. | ||||||
|  | upload:: | ||||||
|  |     File was uploaded | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| EXAMPLES | EXAMPLES | ||||||
| -------- | -------- | ||||||
|  | @ -90,5 +105,5 @@ SEE ALSO | ||||||
| 
 | 
 | ||||||
| COPYING | COPYING | ||||||
| ------- | ------- | ||||||
| Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is | Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is | ||||||
| granted under the terms of the GNU General Public License version 3 (GPLv3). | granted under the terms of the GNU General Public License version 3 (GPLv3). | ||||||
|  |  | ||||||
|  | @ -1,2 +1,3 @@ | ||||||
| # Rebuild rules - FIXME: do conditionally as soon as cdist supports it | if grep -q "^__file/etc/iptables.d/" "$__messages_in"; then | ||||||
| echo /etc/init.d/iptables restart |     echo /etc/init.d/iptables restart | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | @ -21,12 +21,7 @@ | ||||||
| base_dir=/etc/iptables.d | base_dir=/etc/iptables.d | ||||||
| 
 | 
 | ||||||
| name="$__object_id" | name="$__object_id" | ||||||
| 
 | state="$(cat "$__object/parameter/state")" | ||||||
| if [ -f "$__object/parameter/state" ]; then |  | ||||||
|     state="$(cat "$__object/parameter/state")" |  | ||||||
| else |  | ||||||
|     state="present" |  | ||||||
| fi |  | ||||||
| 
 | 
 | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # Basic setup | # Basic setup | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								cdist/conf/type/__iptables_rule/parameter/default/state
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cdist/conf/type/__iptables_rule/parameter/default/state
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | present | ||||||
							
								
								
									
										2
									
								
								cdist/conf/type/__package_zypper/explorer/pkg_version
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										2
									
								
								cdist/conf/type/__package_zypper/explorer/pkg_version
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							|  | @ -27,4 +27,4 @@ else | ||||||
|    name="$__object_id" |    name="$__object_id" | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| rpm -q --whatprovides "$name" 2>/dev/null || true | rpm -q --whatprovides "$name"  | grep -v 'no package provides' || true | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								cdist/conf/type/__package_zypper/gencode-remote
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										11
									
								
								cdist/conf/type/__package_zypper/gencode-remote
									
										
									
									
									
										
										
										Executable file → Normal file
									
								
							|  | @ -39,15 +39,22 @@ else | ||||||
|    state_should="present" |    state_should="present" | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
|  | pkg_version="$(cat "$__object/explorer/pkg_version")" | ||||||
|  | if [ -z "$pkg_version" ]; then | ||||||
|  |     state_is="absent" | ||||||
|  | else | ||||||
|  |     state_is="present" | ||||||
|  | fi | ||||||
|  | 
 | ||||||
| # Exit if nothing is needed to be done | # Exit if nothing is needed to be done | ||||||
| [ "$state_is" = "$state_should" ] && exit 0 | [ "$state_is" = "$state_should" ] && exit 0 | ||||||
| 
 | 
 | ||||||
| case "$state_should" in | case "$state_should" in | ||||||
|    present) |    present) | ||||||
|          echo zypper "$globalopts" install --auto-agree-with-licenses \"$name\" |          echo zypper $globalopts install --auto-agree-with-licenses \"$name\" ">/dev/null" | ||||||
|    ;; |    ;; | ||||||
|    absent) |    absent) | ||||||
|          echo pacman "$globalopts" remove \"$name\" |          echo zypper $globalopts remove \"$name\" ">/dev/null" | ||||||
|    ;; |    ;; | ||||||
|    *) |    *) | ||||||
|       echo "Unknown state: $state_should" >&2 |       echo "Unknown state: $state_should" >&2 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||||
| # | # | ||||||
| # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | ||||||
| # 2011 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. | ||||||
| # | # | ||||||
|  | @ -104,7 +104,8 @@ class Code(object): | ||||||
|                 '__object_id': cdist_object.object_id, |                 '__object_id': cdist_object.object_id, | ||||||
|                 '__object_name': cdist_object.name, |                 '__object_name': cdist_object.name, | ||||||
|             }) |             }) | ||||||
|             return self.local.run_script(script, env=env, return_output=True) |             message_prefix=cdist_object.name | ||||||
|  |             return self.local.run_script(script, env=env, return_output=True, message_prefix=message_prefix) | ||||||
| 
 | 
 | ||||||
|     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.""" | ||||||
|  | @ -119,9 +120,6 @@ class Code(object): | ||||||
|         source = os.path.join(self.local.object_path, cdist_object.code_remote_path) |         source = os.path.join(self.local.object_path, cdist_object.code_remote_path) | ||||||
|         destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) |         destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) | ||||||
|         # FIXME: BUG: do not create destination, but top level of destination! |         # FIXME: BUG: do not create destination, but top level of destination! | ||||||
|         # FIXME: BUG2: we are called AFTER the code-remote has been transferred already: |  | ||||||
|         # mkdir: cannot create directory `/var/lib/cdist/object/__directory/etc/acpi/actions/.cdist/code-remote': File exists |  | ||||||
|         # OR: this is from previous run -> cleanup missing! |  | ||||||
|         self.remote.mkdir(destination) |         self.remote.mkdir(destination) | ||||||
|         self.remote.transfer(source, destination) |         self.remote.transfer(source, destination) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||||
| # | # | ||||||
| # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | # 2011 Steven Armstrong (steven-cdist at armstrong.cc) | ||||||
| # 2011-2012 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. | ||||||
| # | # | ||||||
|  | @ -122,7 +122,8 @@ class Manifest(object): | ||||||
|         if not os.path.isfile(initial_manifest): |         if not os.path.isfile(initial_manifest): | ||||||
|             raise NoInitialManifestError(initial_manifest, user_supplied) |             raise NoInitialManifestError(initial_manifest, user_supplied) | ||||||
| 
 | 
 | ||||||
|         self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) |         message_prefix="initialmanifest" | ||||||
|  |         self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), message_prefix=message_prefix) | ||||||
| 
 | 
 | ||||||
|     def env_type_manifest(self, cdist_object): |     def env_type_manifest(self, cdist_object): | ||||||
|         type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) |         type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) | ||||||
|  | @ -141,5 +142,6 @@ class Manifest(object): | ||||||
| 
 | 
 | ||||||
|     def run_type_manifest(self, cdist_object): |     def run_type_manifest(self, cdist_object): | ||||||
|         type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) |         type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) | ||||||
|  |         message_prefix = cdist_object.name | ||||||
|         if os.path.isfile(type_manifest): |         if os.path.isfile(type_manifest): | ||||||
|            self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) |            self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ import logging | ||||||
| import tempfile | import tempfile | ||||||
| 
 | 
 | ||||||
| import cdist | import cdist | ||||||
|  | import cdist.message | ||||||
| from cdist import core | from cdist import core | ||||||
| 
 | 
 | ||||||
| class Local(object): | class Local(object): | ||||||
|  | @ -92,6 +93,7 @@ class Local(object): | ||||||
|         self.conf_path = os.path.join(self.base_path, "conf") |         self.conf_path = os.path.join(self.base_path, "conf") | ||||||
|         self.global_explorer_out_path = os.path.join(self.base_path, "explorer") |         self.global_explorer_out_path = os.path.join(self.base_path, "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") | ||||||
| 
 | 
 | ||||||
|         # Depending on conf_path |         # Depending on conf_path | ||||||
|         self.global_explorer_path = os.path.join(self.conf_path, "explorer") |         self.global_explorer_path = os.path.join(self.conf_path, "explorer") | ||||||
|  | @ -128,6 +130,7 @@ class Local(object): | ||||||
|     def create_files_dirs(self): |     def create_files_dirs(self): | ||||||
|         self._init_directories() |         self._init_directories() | ||||||
|         self._create_conf_path_and_link_conf_dirs() |         self._create_conf_path_and_link_conf_dirs() | ||||||
|  |         self._create_messages() | ||||||
|         self._link_types_for_emulator() |         self._link_types_for_emulator() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -150,7 +153,7 @@ class Local(object): | ||||||
|         self.log.debug("Local mkdir: %s", path) |         self.log.debug("Local mkdir: %s", path) | ||||||
|         os.makedirs(path, exist_ok=True) |         os.makedirs(path, exist_ok=True) | ||||||
| 
 | 
 | ||||||
|     def run(self, command, env=None, return_output=False): |     def run(self, command, env=None, return_output=False, message_prefix=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. | ||||||
| 
 | 
 | ||||||
|  | @ -163,6 +166,10 @@ class Local(object): | ||||||
|         # Export __target_host for use in __remote_{copy,exec} scripts |         # Export __target_host for use in __remote_{copy,exec} scripts | ||||||
|         env['__target_host'] = self.target_host |         env['__target_host'] = self.target_host | ||||||
| 
 | 
 | ||||||
|  |         if message_prefix: | ||||||
|  |             message = cdist.message.Message(message_prefix, self.messages_path) | ||||||
|  |             env.update(message.env) | ||||||
|  | 
 | ||||||
|         try: |         try: | ||||||
|             if return_output: |             if return_output: | ||||||
|                 return subprocess.check_output(command, env=env).decode() |                 return subprocess.check_output(command, env=env).decode() | ||||||
|  | @ -172,8 +179,11 @@ class Local(object): | ||||||
|             raise cdist.Error("Command failed: " + " ".join(command)) |             raise cdist.Error("Command failed: " + " ".join(command)) | ||||||
|         except OSError as error: |         except OSError as error: | ||||||
|             raise cdist.Error(" ".join(*args) + ": " + error.args[1]) |             raise cdist.Error(" ".join(*args) + ": " + error.args[1]) | ||||||
|  |         finally: | ||||||
|  |             if message_prefix: | ||||||
|  |                 message.merge_messages() | ||||||
| 
 | 
 | ||||||
|     def run_script(self, script, env=None, return_output=False): |     def run_script(self, script, env=None, return_output=False, message_prefix=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. | ||||||
| 
 | 
 | ||||||
|  | @ -181,7 +191,7 @@ class Local(object): | ||||||
|         command = ["/bin/sh", "-e"] |         command = ["/bin/sh", "-e"] | ||||||
|         command.append(script) |         command.append(script) | ||||||
| 
 | 
 | ||||||
|         return self.run(command, env, return_output) |         return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix) | ||||||
| 
 | 
 | ||||||
|     def save_cache(self): |     def save_cache(self): | ||||||
|         destination = os.path.join(self.cache_path, self.target_host) |         destination = os.path.join(self.cache_path, self.target_host) | ||||||
|  | @ -195,6 +205,11 @@ class Local(object): | ||||||
| 
 | 
 | ||||||
|         shutil.move(self.base_path, destination) |         shutil.move(self.base_path, destination) | ||||||
| 
 | 
 | ||||||
|  |     def _create_messages(self): | ||||||
|  |         """Create empty messages""" | ||||||
|  |         with open(self.messages_path, "w"): | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|     def _create_conf_path_and_link_conf_dirs(self): |     def _create_conf_path_and_link_conf_dirs(self): | ||||||
|         # Link destination directories |         # Link destination directories | ||||||
|         for sub_dir in [ "explorer", "manifest", "type" ]: |         for sub_dir in [ "explorer", "manifest", "type" ]: | ||||||
|  |  | ||||||
							
								
								
									
										76
									
								
								cdist/message.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								cdist/message.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | # 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 logging | ||||||
|  | import os | ||||||
|  | import shutil | ||||||
|  | import tempfile | ||||||
|  | 
 | ||||||
|  | import cdist | ||||||
|  | 
 | ||||||
|  | log = logging.getLogger(__name__) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Message(object): | ||||||
|  |     """Support messaging between types | ||||||
|  | 
 | ||||||
|  |     """ | ||||||
|  |     def __init__(self, prefix, messages): | ||||||
|  |         self.prefix = prefix | ||||||
|  |         self.global_messages = messages | ||||||
|  | 
 | ||||||
|  |         self.messages_in  = tempfile.mkstemp(suffix='.cdist_message_in')[1] | ||||||
|  |         self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out')[1] | ||||||
|  | 
 | ||||||
|  |         self._copy_messages() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def env(self): | ||||||
|  |         env = {} | ||||||
|  |         env['__messages_in']  = self.messages_in | ||||||
|  |         env['__messages_out'] = self.messages_out | ||||||
|  | 
 | ||||||
|  |         return env | ||||||
|  | 
 | ||||||
|  |     def _copy_messages(self): | ||||||
|  |         """Copy global contents into our copy""" | ||||||
|  |         shutil.copyfile(self.global_messages, self.messages_in) | ||||||
|  | 
 | ||||||
|  |     def _cleanup(self): | ||||||
|  |         """remove temporary files""" | ||||||
|  |         if os.path.exists(self.messages_in): | ||||||
|  |             os.remove(self.messages_in) | ||||||
|  |         if os.path.exists(self.messages_out): | ||||||
|  |             os.remove(self.messages_out) | ||||||
|  | 
 | ||||||
|  |     def _merge_messages(self): | ||||||
|  |         """merge newly written lines into global file""" | ||||||
|  |         with open(self.messages_out) as fd: | ||||||
|  |             content = fd.readlines() | ||||||
|  | 
 | ||||||
|  |         with open(self.global_messages, 'a') as fd: | ||||||
|  |             for line in content: | ||||||
|  |                 fd.write("%s:%s" % (self.prefix, line)) | ||||||
|  | 
 | ||||||
|  |     def merge_messages(self): | ||||||
|  |         self._merge_messages() | ||||||
|  |         self._cleanup() | ||||||
							
								
								
									
										82
									
								
								cdist/test/message/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								cdist/test/message/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | # 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 tempfile | ||||||
|  | 
 | ||||||
|  | from cdist import test | ||||||
|  | import cdist.message | ||||||
|  | 
 | ||||||
|  | class MessageTestCase(test.CdistTestCase): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.prefix="cdist-test" | ||||||
|  |         self.content = "A very short story" | ||||||
|  |         self.tempfile = tempfile.mkstemp()[1] | ||||||
|  |         self.message = cdist.message.Message(prefix=self.prefix, | ||||||
|  |             messages=self.tempfile) | ||||||
|  | 
 | ||||||
|  |     def tearDown(self): | ||||||
|  |         os.remove(self.tempfile) | ||||||
|  |         self.message._cleanup() | ||||||
|  | 
 | ||||||
|  |     def test_env(self): | ||||||
|  |         """ | ||||||
|  |         Ensure environment is correct | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         env = self.message.env | ||||||
|  | 
 | ||||||
|  |         self.assertIn('__messages_in', env) | ||||||
|  |         self.assertIn('__messages_out', env) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def test_copy_content(self): | ||||||
|  |         """ | ||||||
|  |         Ensure content copying is working | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         with open(self.tempfile, "w") as fd: | ||||||
|  |             fd.write(self.content) | ||||||
|  | 
 | ||||||
|  |         self.message._copy_messages() | ||||||
|  | 
 | ||||||
|  |         with open(self.tempfile, "r") as fd: | ||||||
|  |             testcontent = fd.read() | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(self.content, testcontent) | ||||||
|  | 
 | ||||||
|  |     def test_message_merge_prefix(self): | ||||||
|  |         """Ensure messages are merged and are prefixed""" | ||||||
|  | 
 | ||||||
|  |         expectedcontent = "%s:%s" % (self.prefix, self.content) | ||||||
|  | 
 | ||||||
|  |         out = self.message.env['__messages_out'] | ||||||
|  | 
 | ||||||
|  |         with open(out, "w") as fd: | ||||||
|  |             fd.write(self.content) | ||||||
|  | 
 | ||||||
|  |         self.message._merge_messages() | ||||||
|  | 
 | ||||||
|  |         with open(self.tempfile, "r") as fd: | ||||||
|  |             testcontent = fd.read() | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(expectedcontent, testcontent) | ||||||
|  | @ -4,12 +4,19 @@ Changelog | ||||||
| 	* Changes are always commented with their author in (braces) | 	* Changes are always commented with their author in (braces) | ||||||
| 	* Exception: No braces means author == Nico Schottelius | 	* Exception: No braces means author == Nico Schottelius | ||||||
| 
 | 
 | ||||||
| 2.3.7: | 
 | ||||||
|  | 3.0.0: | ||||||
|  | 	* Core: Messaging support added | ||||||
|  | 	* Type: __iptables_rule: Use default parameter | ||||||
|  | 	* Type __file: Do not generate code if mode is 0xxx | ||||||
|  | 
 | ||||||
|  | 2.3.7: 2013-12-02 | ||||||
| 	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong) | 	* Type __file: Secure the file transfer by using mktemp (Steven Armstrong) | ||||||
| 	* Type __file: Only remove file when state is absent (Steven Armstrong) | 	* Type __file: Only remove file when state is absent (Steven Armstrong) | ||||||
| 	* Type __link: Only remove link when state is absent (Steven Armstrong) | 	* Type __link: Only remove link when state is absent (Steven Armstrong) | ||||||
| 	* Type __directory: Only remove directory when state is absent (Steven Armstrong) | 	* Type __directory: Only remove directory when state is absent (Steven Armstrong) | ||||||
| 	* Type __directory: Fix newly introduced quoting issue | 	* Type __directory: Fix newly introduced quoting issue | ||||||
|  | 	* Type __package_zypper: Fix explorer and parameter issue (Daniel Heule) | ||||||
| 	* Core: Fix backtrace when cache cannot be deleted | 	* Core: Fix backtrace when cache cannot be deleted | ||||||
| 
 | 
 | ||||||
| 2.3.6: 2013-11-25 | 2.3.6: 2013-11-25 | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								docs/dev/logs/2013-01-20.notifications
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								docs/dev/logs/2013-01-20.notifications
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | Allow cross-type communication | ||||||
|  | 
 | ||||||
|  | Sending notifications is possible from | ||||||
|  | 
 | ||||||
|  |     - manifest | ||||||
|  |     - gencode-local | ||||||
|  |     - gencode-remote | ||||||
|  | 
 | ||||||
|  | Sending a notification from an object means writing to the file "notifications" into | ||||||
|  | its object: | ||||||
|  | 
 | ||||||
|  |     echo mytest >> "$__object/notifications" # a type reports something | ||||||
|  | 
 | ||||||
|  | Reading / Reacting on notifications works by accessing the file | ||||||
|  | referred to be "$__notifications". All notifications are prefixed with | ||||||
|  | the object name ($__object_name) and are appended into this file. | ||||||
|  | 
 | ||||||
|  | To find out, whether a file was copied, run: | ||||||
|  | 
 | ||||||
|  |     grep __file/etc/passwd:copy "$__notifications" | ||||||
							
								
								
									
										49
									
								
								docs/dev/logs/2013-01-20.triggers
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								docs/dev/logs/2013-01-20.triggers
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | An alternative / complementary approach to notifications: triggers (or actions?) | ||||||
|  | 
 | ||||||
|  | A type may support various actions by creating files in its subdirectory | ||||||
|  | "actions". Other types can trigger an action of a different type or object | ||||||
|  | by calling them (indirectly?): | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if grep "__file/etc/nginx/conf.d/.*:copy" "$__notifications"; then | ||||||
|  | 
 | ||||||
|  |     # Call action from a type | ||||||
|  |     cdist trigger __nginx/reload | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Not sure whether this approach (calling "actions" of other types) is sane, | ||||||
|  | as nginx should probably better know if it should be restarted "itself". | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | Alternate approach: | ||||||
|  | 
 | ||||||
|  | __nginx_vhost www.some-domain.ch --custom << eof | ||||||
|  | some custom code for __nginx_vhost inclusion | ||||||
|  | eof | ||||||
|  | 
 | ||||||
|  | __nginx_vhost: | ||||||
|  | 
 | ||||||
|  |     manifest: | ||||||
|  |         # __nginx_vhost requires __nginx: creates directories | ||||||
|  | 
 | ||||||
|  |         require"$__object_name" __nginx --require-only | ||||||
|  |          | ||||||
|  |         # Do WE or __file ... depend on nginx? | ||||||
|  |         cdist require __nginx | ||||||
|  | 
 | ||||||
|  |         # Create file that contains the giving code | ||||||
|  |         __file /etc/nginx/conf.d/www.some-domain.ch | ||||||
|  | 
 | ||||||
|  |         require="__nginx" __file /etc/nginx/conf.d/www.some-domain.ch | ||||||
|  | 
 | ||||||
|  | __nginx: | ||||||
|  |     manifest: | ||||||
|  |         __package nginx --state present | ||||||
|  | 
 | ||||||
|  |         __file some-custom-files | ||||||
|  | 
 | ||||||
|  |     gencode-remote: | ||||||
|  |         if first_install or file changed: | ||||||
							
								
								
									
										50
									
								
								docs/dev/logs/2013-11-25.notifications
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								docs/dev/logs/2013-11-25.notifications
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | ||||||
|  | Follow up from 2013-01-20: | ||||||
|  | 
 | ||||||
|  |     - (re-)create message file per object? | ||||||
|  |         - yes, but do not necessarily save in object space | ||||||
|  |         - save $anywhere | ||||||
|  | 
 | ||||||
|  |     - object_run | ||||||
|  |         - current notifications are imported into a file available at $__messages_in | ||||||
|  |         - after object run, everything that has been written to $__messages_out is merged into the $__messages file | ||||||
|  | 
 | ||||||
|  |         - functions: | ||||||
|  |             self.explorer.run_global_explorers(self.local.global_explorer_out_path) | ||||||
|  |             self.manifest.run_initial_manifest(self.local.initial_manifest) | ||||||
|  |                 self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) | ||||||
|  |             self.explorer.run_type_explorers(cdist_object) | ||||||
|  |             self.manifest.run_type_manifest(cdist_object) | ||||||
|  |                 self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) | ||||||
|  |             self.code.run_gencode_local(cdist_object) | ||||||
|  |                 self.local.run_script(script, env=env, return_output=True) | ||||||
|  |             self.code.run_gencode_remote(cdist_object) | ||||||
|  |                 self.local.run_script(script, env=env, return_output=True) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     - message support in ... | ||||||
|  |         - initialmanifest - yes | ||||||
|  |         - explorer - no | ||||||
|  |         - only locally - yes | ||||||
|  |          | ||||||
|  |     - how to use notification / messaging in cdist | ||||||
|  |         - can be used in all local scripts: | ||||||
|  |             - initial manifest | ||||||
|  |             - type manifest | ||||||
|  |             - type gencode-* | ||||||
|  |         - order of object exeution is random or as you requested using require="" | ||||||
|  | 
 | ||||||
|  |     - example use: | ||||||
|  | 
 | ||||||
|  | __file/gencode-local: | ||||||
|  |          if [ "$local_cksum" != "$remote_cksum" ]; then | ||||||
|  |             echo "$__remote_copy" "$source" "${__target_host}:${destination}" | ||||||
|  |             echo "copy" >> "$__messages_out" | ||||||
|  |          fi | ||||||
|  |   | ||||||
|  | __nginx/manifest: | ||||||
|  |     __file /etc/nginx/sites-enabled/myfile --source "$__type/files/nginx-config" | ||||||
|  | 
 | ||||||
|  | __nginx/gencode-remote: | ||||||
|  |     if grep -q "__file/etc/nginx/sites-enabled/myfile:copy" "$__messages_in"; then | ||||||
|  |         echo /etc/init.d/nginx restart | ||||||
|  |     fi | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| #!/bin/sh | #!/bin/sh | ||||||
| # | # | ||||||
| # 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) | # 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) | ||||||
| # | # | ||||||
| # This file is part of cdist. | # This file is part of cdist. | ||||||
| # | # | ||||||
|  | @ -191,6 +191,12 @@ __manifest:: | ||||||
| __global:: | __global:: | ||||||
|     Directory that contains generic output like explorer. |     Directory that contains generic output like explorer. | ||||||
|     Available for: initial manifest, type manifest, type gencode, shell |     Available for: initial manifest, type manifest, type gencode, shell | ||||||
|  | __messages_in:: | ||||||
|  |     File to read messages from | ||||||
|  |     Available for: initial manifest, type manifest, type gencode | ||||||
|  | __messages_out:: | ||||||
|  |     File to write messages | ||||||
|  |     Available for: initial manifest, type manifest, type gencode | ||||||
| __object:: | __object:: | ||||||
|     Directory that contains the current object. |     Directory that contains the current object. | ||||||
|     Available for: type manifest, type explorer, type gencode |     Available for: type manifest, type explorer, type gencode | ||||||
|  |  | ||||||
							
								
								
									
										72
									
								
								docs/man/man7/cdist-messaging.text
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								docs/man/man7/cdist-messaging.text
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | cdist-messaging(7) | ||||||
|  | ================== | ||||||
|  | Nico Schottelius <nico-cdist--@--schottelius.org> | ||||||
|  | 
 | ||||||
|  | NAME | ||||||
|  | ---- | ||||||
|  | cdist-messaging - How the initial manifest and types can communication | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | DESCRIPTION | ||||||
|  | ----------- | ||||||
|  | cdist has a simple but powerful way of allowing communication between | ||||||
|  | the initial manifest and types as well as types and types. | ||||||
|  | 
 | ||||||
|  | Whenever execution is passed from cdist to one of the | ||||||
|  | scripts described below, cdist generate 2 new temporary files | ||||||
|  | and exports the environment variables __messages_in and | ||||||
|  | __messages_out to point to them.  | ||||||
|  | 
 | ||||||
|  | Before handing over the control, the content of the global message  | ||||||
|  | file is copied into the file referenced by $__messages_in. | ||||||
|  | 
 | ||||||
|  | After cdist gained control back, the content of the file referenced | ||||||
|  | by $__messages_out is appended to the global message file. | ||||||
|  | 
 | ||||||
|  | This way overwriting any of the two files by accident does not  | ||||||
|  | interfere with other types. | ||||||
|  | 
 | ||||||
|  | The order of execution is not defined unless you create dependencies  | ||||||
|  | between the different objects (see cdist-manifest(7)) and thus you | ||||||
|  | can only react reliably on messages by objects that you depend on. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | AVAILABILITY | ||||||
|  | ------------ | ||||||
|  | Messaging is possible between all **local** scripts: | ||||||
|  | 
 | ||||||
|  | - initial manifest | ||||||
|  | - type/manifest | ||||||
|  | - type/gencode-local | ||||||
|  | - type/gencode-remote | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | EXAMPLES | ||||||
|  | -------- | ||||||
|  | When you want to emit a message use: | ||||||
|  | 
 | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | echo "something" >> "$__messages_out" | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | When you want to react on a message use: | ||||||
|  | 
 | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | if grep -q "^__your_type/object/id:something" "$__messages_in"; then | ||||||
|  |     echo "I do something else" | ||||||
|  | fi | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | SEE ALSO | ||||||
|  | -------- | ||||||
|  | - cdist(1) | ||||||
|  | - cdist-manifest(7) | ||||||
|  | - cdist-reference(7) | ||||||
|  | - cdist-type(7) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | COPYING | ||||||
|  | ------- | ||||||
|  | Copyright \(C) 2013 Nico Schottelius. Free use of this software is | ||||||
|  | granted under the terms of the GNU General Public License version 3 (GPLv3). | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue