From 78d16a80570ee0db2a25940c0ba3cf3b1ded1391 Mon Sep 17 00:00:00 2001 From: Denys Havrysh Date: Tue, 23 Aug 2016 11:02:23 +0300 Subject: [PATCH 01/12] [BACKPORT] Fix empty `fun_agrs` field in Reactor generated events --- salt/client/mixins.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/salt/client/mixins.py b/salt/client/mixins.py index dcb7fc24e4b..c1bd08028d8 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -256,11 +256,7 @@ class SyncClientMixin(object): jid = low.get('__jid__', salt.utils.jid.gen_jid()) tag = low.get('__tag__', tagify(jid, prefix=self.tag_prefix)) - # This avoids including kwargs dict as args list in low data. - # We only need to update event data. - fun_args = low.get('args', []) data = {'fun': '{0}.{1}'.format(self.client, fun), - 'fun_args': fun_args + ([low['kwargs']] if low.get('kwargs', False) else []), 'jid': jid, 'user': low.get('__user__', 'UNKNOWN'), } @@ -280,11 +276,13 @@ class SyncClientMixin(object): # Suppress printing of return event (this keeps us from printing # runner/wheel output during orchestration). print_func = None + namespaced_event = salt.utils.event.NamespacedEvent( event, tag, print_func=print_func ) + # TODO: document these, and test that they exist # TODO: Other things to inject?? func_globals = {'__jid__': jid, @@ -295,8 +293,6 @@ class SyncClientMixin(object): '__jid_event__': weakref.proxy(namespaced_event), } - func_globals['__jid_event__'].fire_event(data, 'new') - try: verify_fun(self.functions, fun) @@ -332,6 +328,7 @@ class SyncClientMixin(object): args = f_call.get('args', ()) else: args = low['args'] + if 'kwargs' not in low: if f_call is None: f_call = salt.utils.format_call( @@ -351,6 +348,10 @@ class SyncClientMixin(object): else: kwargs = low['kwargs'] + # Update the event data with loaded args and kwargs + data['fun_args'] = args + ([kwargs] if kwargs else []) + func_globals['__jid_event__'].fire_event(data, 'new') + # Initialize a context for executing the method. with tornado.stack_context.StackContext(self.functions.context_dict.clone): data['return'] = self.functions[fun](*args, **kwargs) @@ -360,26 +361,30 @@ class SyncClientMixin(object): data['return'] = str(ex) else: data['return'] = 'Exception occurred in {0} {1}: {2}'.format( - self.client, - fun, - traceback.format_exc(), - ) + self.client, + fun, + traceback.format_exc(), + ) data['success'] = False namespaced_event.fire_event(data, 'ret') + try: salt.utils.job.store_job( self.opts, - {'id': self.opts['id'], - 'tgt': self.opts['id'], - 'jid': data['jid'], - 'return': data, - }, + { + 'id': self.opts['id'], + 'tgt': self.opts['id'], + 'jid': data['jid'], + 'return': data, + }, event=None, mminion=self.mminion, ) except salt.exceptions.SaltCacheError: - log.error('Could not store job cache info. Job details for this run may be unavailable.') + log.error('Could not store job cache info. ' + 'Job details for this run may be unavailable.') + # if we fired an event, make sure to delete the event object. # This will ensure that we call destroy, which will do the 0MQ linger log.info('Runner completed: {0}'.format(data['jid'])) From 2558dcc100c9f609086d55865a78584d7f0a6770 Mon Sep 17 00:00:00 2001 From: Thomas S Hatch Date: Thu, 25 Aug 2016 14:17:39 -0600 Subject: [PATCH 02/12] follow up on the re-deploy if there is a checksum missmatch --- salt/client/ssh/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index 2ca83a6fcd8..5c0fdf0f39a 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -1044,11 +1044,12 @@ ARGS = {10}\n'''.format(self.minion_config, if not self.tty: # If RSTR is not seen in both stdout and stderr then there # was a thin deployment problem. - return 'ERROR: Failure deploying thin: {0}\n{1}'.format(stdout, stderr), stderr, retcode + log.error('ERROR: Failure deploying thin, retrying: {0}\n{1}'.format(stdout, stderr), stderr, retcode) + return self.cmd_block() elif not re.search(RSTR_RE, stdout): # If RSTR is not seen in stdout with tty, then there # was a thin deployment problem. - return 'ERROR: Failure deploying thin: {0}\n{1}'.format(stdout, stderr), stderr, retcode + log.error('ERROR: Failure deploying thin, retrying: {0}\n{1}'.format(stdout, stderr), stderr, retcode) stdout = re.split(RSTR_RE, stdout, 1)[1].strip() if self.tty: stderr = '' From ea8e1385c1e99eb53f0f0d36abd457728a8944c5 Mon Sep 17 00:00:00 2001 From: Dmitry Kuzmenko Date: Fri, 26 Aug 2016 11:33:14 +0300 Subject: [PATCH 03/12] Fixed syndic unhandled future exception if master is stopped. --- salt/transport/ipc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py index f3e140a7181..bd5cb307151 100644 --- a/salt/transport/ipc.py +++ b/salt/transport/ipc.py @@ -270,6 +270,9 @@ class IPCClient(object): if hasattr(self, '_connecting_future') and not self._connecting_future.done(): # pylint: disable=E0203 future = self._connecting_future # pylint: disable=E0203 else: + if hasattr(self, '_connecting_future'): + # read previous future result to prevent the "unhandled future exception" error + self._connecting_future.exc_info() # pylint: disable=E0203 future = tornado.concurrent.Future() self._connecting_future = future self._connect(timeout=timeout) From ab1afd002e04149f4ae2798fa371754f65c716d3 Mon Sep 17 00:00:00 2001 From: Dmitry Kuzmenko Date: Fri, 26 Aug 2016 11:34:59 +0300 Subject: [PATCH 04/12] Fixed syndic event bus connection. Connect syndic to master event bus in a coroutine. This fixes connection timeout handling and prevents CPU utilization by connect loop if no master is running. --- salt/transport/ipc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py index bd5cb307151..3b88399de9a 100644 --- a/salt/transport/ipc.py +++ b/salt/transport/ipc.py @@ -687,6 +687,7 @@ class IPCMessageSubscriber(IPCClient): except Exception as exc: log.error('Exception occurred while Subscriber handling stream: {0}'.format(exc)) + @tornado.gen.coroutine def read_async(self, callback): ''' Asynchronously read messages and invoke a callback when they are ready. @@ -695,13 +696,14 @@ class IPCMessageSubscriber(IPCClient): ''' while not self.connected(): try: - self.connect() + yield self.connect(timeout=5) except tornado.iostream.StreamClosedError: log.trace('Subscriber closed stream on IPC {0} before connect'.format(self.socket_path)) + yield tornado.gen.sleep(1) except Exception as exc: log.error('Exception occurred while Subscriber connecting: {0}'.format(exc)) - - self.io_loop.spawn_callback(self._read_async, callback) + yield tornado.gen.sleep(1) + yield self._read_async(callback) def close(self): ''' From 9afdbb0e971e6a531bdebf75b5f84518403261ab Mon Sep 17 00:00:00 2001 From: Dmitry Kuzmenko Date: Fri, 26 Aug 2016 11:37:11 +0300 Subject: [PATCH 05/12] Reconnect syndic to master event bus if master disappears. --- salt/minion.py | 14 ++++++++++++-- salt/utils/event.py | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/salt/minion.py b/salt/minion.py index 2bffa7ee39c..49660c605b1 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -2209,6 +2209,10 @@ class Syndic(Minion): sync=False, ) + def reconnect_event_bus(self, something): + future = self.local.event.set_event_handler(self._process_event) + self.io_loop.add_future(future, self.reconnect_event_bus) + # Syndic Tune In @tornado.gen.coroutine def tune_in(self, start=True): @@ -2231,7 +2235,8 @@ class Syndic(Minion): # register the event sub to the poller self._reset_event_aggregation() - self.local.event.set_event_handler(self._process_event) + future = self.local.event.set_event_handler(self._process_event) + self.io_loop.add_future(future, self.reconnect_event_bus) # forward events every syndic_event_forward_timeout self.forward_events = tornado.ioloop.PeriodicCallback(self._forward_events, @@ -2555,6 +2560,10 @@ class MultiSyndic(MinionBase): self.job_rets = {} self.raw_events = [] + def reconnect_event_bus(self, something): + future = self.local.event.set_event_handler(self._process_event) + self.io_loop.add_future(future, self.reconnect_event_bus) + # Syndic Tune In def tune_in(self): ''' @@ -2570,7 +2579,8 @@ class MultiSyndic(MinionBase): # register the event sub to the poller self._reset_event_aggregation() - self.local.event.set_event_handler(self._process_event) + future = self.local.event.set_event_handler(self._process_event) + self.io_loop.add_future(future, self.reconnect_event_bus) # forward events every syndic_event_forward_timeout self.forward_events = tornado.ioloop.PeriodicCallback(self._forward_events, diff --git a/salt/utils/event.py b/salt/utils/event.py index 7e981996f6a..628eccee90d 100644 --- a/salt/utils/event.py +++ b/salt/utils/event.py @@ -733,7 +733,7 @@ class SaltEvent(object): if not self.cpub: self.connect_pub() # This will handle reconnects - self.subscriber.read_async(event_handler) + return self.subscriber.read_async(event_handler) def __del__(self): # skip exceptions in destroy-- since destroy() doesn't cover interpreter From 805d43598e6c98abe5dbcd8ff9b6934831da2a8b Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Fri, 26 Aug 2016 11:06:39 -0500 Subject: [PATCH 06/12] list_nodes_min should return a minimum dictionary Not true or False --- salt/cloud/clouds/vmware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index d74c05732ec..610edb8a9a8 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -1261,7 +1261,7 @@ def list_nodes_min(kwargs=None, call=None): vm_list = salt.utils.vmware.get_mors_with_properties(_get_si(), vim.VirtualMachine, vm_properties) for vm in vm_list: - ret[vm["name"]] = True + ret[vm['name']] = {'state': 'Running', 'id': vm['name']} return ret From e9e6ea8485c0fc7f7e1e693f51fba76622cf2f4e Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Sat, 27 Aug 2016 14:30:14 -0500 Subject: [PATCH 07/12] One more tweak to top file merging docs This catches one more inaccuracy that wasn't fixed in https://github.com/saltstack/salt/pull/35774 --- doc/ref/states/top.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/ref/states/top.rst b/doc/ref/states/top.rst index 447f29f9ec5..db65740c008 100644 --- a/doc/ref/states/top.rst +++ b/doc/ref/states/top.rst @@ -437,9 +437,8 @@ Scenario 2 - No Environment Specified, :conf_minion:`top_file_merging_strategy` In this scenario, assuming that the ``base`` environment's top file was evaluated first, the ``base1``, ``dev1``, and ``qa1`` states would be applied to all minions. If, for instance, the ``qa`` environment is not defined in -**/srv/salt/base/top.sls**, then the ``qa`` section in -**/srv/salt/dev/top.sls** would be used and the ``qa2`` states would be applied -to all minions. +**/srv/salt/base/top.sls**, then because there is no top file for the ``qa`` +environment, no states from the ``qa`` environment would be applied. Scenario 3 - No Environment Specified, :conf_minion:`top_file_merging_strategy` is "same" ----------------------------------------------------------------------------------------- From c534d88280dafeef9f3b85e86778b454976213bf Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Sat, 27 Aug 2016 15:18:06 -0500 Subject: [PATCH 08/12] More clarification/correction in minion docs --- doc/ref/configuration/minion.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/ref/configuration/minion.rst b/doc/ref/configuration/minion.rst index 4660b31b3d8..fe780a940bf 100644 --- a/doc/ref/configuration/minion.rst +++ b/doc/ref/configuration/minion.rst @@ -1024,8 +1024,6 @@ enabled and can be disabled by changing this value to ``False``. ``environment`` --------------- -Default: ``None`` - Normally the minion is not isolated to any single environment on the master when running states, but the environment can be isolated on the minion side by statically setting it. Remember that the recommended way to manage @@ -1040,14 +1038,22 @@ environments is to isolate via the top file. ``state_top_saltenv`` --------------------- -Default: not set +This option has no default value. Set it to an environment name to ensure that +*only* the top file from that environment is considered during a +:ref:`highstate `. -Set this option to an environment name, to ensure that *only* the top file from -that environment is considered during a :ref:`highstate `. +.. note:: + Using this value does not change the merging strategy. For instance, if + :conf_minion:`top_file_merging_strategy` is left at its default, and + :conf_minion:`state_top_saltenv` is set to ``foo``, then any sections for + environments other than ``foo`` in the top file for the ``foo`` environment + will be ignored. With :conf_minion:`top_file_merging_strategy` set to + ``base``, all states from all environments in the ``base`` top file will + be applied, while all other top files are ignored. .. code-block:: yaml - state_top_saltenv: base + state_top_saltenv: dev .. conf_minion:: top_file_merging_strategy From 86d5398b28749b9badbc4eb3b3864acafa6b206d Mon Sep 17 00:00:00 2001 From: Nathan Delhaye Date: Mon, 29 Aug 2016 10:30:58 +0200 Subject: [PATCH 09/12] Fix potential infinite loop with no error when using recursive makedirs --- salt/modules/file.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/salt/modules/file.py b/salt/modules/file.py index 0294a39b658..5cb27bedb9c 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -4609,8 +4609,15 @@ def makedirs_(path, break directories_to_create.append(dirname) + current_dirname = dirname dirname = os.path.dirname(dirname) + if current_dirname == dirname: + raise SaltInvocationError( + 'Recursive creation for path \'{0}\' would result in an ' + 'infinite loop. Please use an absolute path.'.format(dirname) + ) + # create parent directories from the topmost to the most deeply nested one directories_to_create.reverse() for directory_to_create in directories_to_create: From ee45a88bc8d4ff8efdaecbc3ebe4ed921beead7c Mon Sep 17 00:00:00 2001 From: Nicole Thomas Date: Mon, 29 Aug 2016 12:21:28 -0600 Subject: [PATCH 10/12] Fix doc formatting for sqs_events engine example config (#35860) Fixes #35834 --- salt/engines/sqs_events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/engines/sqs_events.py b/salt/engines/sqs_events.py index 13dcdc2d1ba..b571335183c 100644 --- a/salt/engines/sqs_events.py +++ b/salt/engines/sqs_events.py @@ -19,8 +19,8 @@ Example Config: engines: - sqs_events: - queue: test - profile: my-sqs-profile #optional + queue: test + profile: my-sqs-profile # optional Explicit sqs credentials are accepted but this engine can also utilize IAM roles assigned to the instance through Instance Profiles. Dynamic From 40bcb7daedfab8e3c43f1ca7b7eda4aeb243d26a Mon Sep 17 00:00:00 2001 From: Nicole Thomas Date: Mon, 29 Aug 2016 12:22:16 -0600 Subject: [PATCH 11/12] Fix IAM roles statement to be boto version specific in sqs_events (#35861) Fixes #35835 --- salt/engines/sqs_events.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/engines/sqs_events.py b/salt/engines/sqs_events.py index b571335183c..5921242aaa4 100644 --- a/salt/engines/sqs_events.py +++ b/salt/engines/sqs_events.py @@ -29,8 +29,9 @@ configuration is necessary. More Information available at:: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html -If IAM roles are not used you need to specify them either in a pillar or -in the config file of the master or minion, as appropriate: +If IAM roles are not (or for ``boto`` version < 2.5.1) used you need to +specify them either in a pillar or in the config file of the master or +minion, as appropriate: .. code-block:: yaml From 96792663da0405fab8cb8e0992af2c2dc3fb50b3 Mon Sep 17 00:00:00 2001 From: Nicole Thomas Date: Mon, 29 Aug 2016 12:22:30 -0600 Subject: [PATCH 12/12] Add engines to list of extension module options in master config docs (#35864) Fixes #35837 --- conf/master | 2 +- doc/ref/configuration/master.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/master b/conf/master index 51ff73a9e23..874a76eed31 100644 --- a/conf/master +++ b/conf/master @@ -57,7 +57,7 @@ # Directory for custom modules. This directory can contain subdirectories for # each of Salt's module types such as "runners", "output", "wheel", "modules", -# "states", "returners", etc. +# "states", "returners", "engines", etc. # Like 'extension_modules' but can take an array of paths #module_dirs: # - /var/cache/salt/minion/extmods diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index dcafe35ea1f..6f6d1bac3d8 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -237,7 +237,7 @@ The directory to store the pki authentication keys. Directory for custom modules. This directory can contain subdirectories for each of Salt's module types such as ``runners``, ``output``, ``wheel``, -``modules``, ``states``, ``returners``, etc. This path is appended to +``modules``, ``states``, ``returners``, ``engines``, etc. This path is appended to :conf_master:`root_dir`. .. code-block:: yaml