allow using proxy minion from cli#48344
Conversation
|
@mirceaulinic you will be interested in this. |
isbm
left a comment
There was a problem hiding this comment.
@gtmanfred great work! And tests?.. 😉
salt/cli/caller.py
Outdated
| allow_missing_funcs = any([ | ||
| self.minion.executors['{0}.allow_missing_func'.format(executor)](function_name) | ||
| for executor in executors | ||
| if '{0}.allow_missing_func' in self.minion.executors |
There was a problem hiding this comment.
Nitpick: I would still put this into one line with for loop, as it looks a bit odd, sort of wrong syntax. 😉
There was a problem hiding this comment.
Yeah, most of this still needs to be cleaned up, a lot of it is copied from elsewhere, and just needs to be made into functions in salt.utils, so they can be used in both places.
salt/minion.py
Outdated
|
|
||
| if 'proxy' not in self.opts['pillar'] and 'proxy' not in self.opts: | ||
| errmsg = 'No proxy key found in pillar or opts for id ' + self.opts['id'] + '. ' + \ | ||
| 'Check your pillar/opts configuration and contents. Salt-proxy aborted.' |
There was a problem hiding this comment.
Ermm... why not:
errmsg = 'No proxy key found in pillar or opts for id {id}. ' \
'Check your pillar/options configuration and contents. ' \
'Salt-proxy aborted.'.format(id=self.opts['id'])But this is about formatting. The message itself is cryptic and misleading. Users, who has no idea of the Salt internals and programming will start thinking about AES keys. Please rephrase it for them.
salt/minion.py
Outdated
| 'Check your pillar/opts configuration and contents. Salt-proxy aborted.' | ||
| log.error(errmsg) | ||
| self._running = False | ||
| raise SaltSystemExit(code=-1, msg=errmsg) |
There was a problem hiding this comment.
What is -1? We have our own exit codes and we should stick to that, reusing constants.
import salt.defaults.exitcodes
raise SaltSystemExit(salt.defaults.exitcodes.EX_GENERIC, msg=errmsg)Or add to exit codes new constant and reuse it above, e.g.:
EX_PROXY_RELOAD = 200 # All proxy-related errors can be 200-255, for example| raise SaltSystemExit(code=-1, msg=errmsg) | ||
|
|
||
| if 'proxy' not in self.opts: | ||
| self.opts['proxy'] = self.opts['pillar']['proxy'] |
There was a problem hiding this comment.
Hmm, this check if... will make __opts__ more important than pillars, which isn't right thing. Meaning, you cannot push proxy data to the running minion without it being restarted.
@terminalmage we wanted to change that also in config getter, right?
There was a problem hiding this comment.
The proxy block into the Pillar is mandatory for the Proxy Minion to start (i.e., it won't be able to start without). With this in mind, the Proxy Minion startup is different than the regular Minion, as the data is compiled twice: once to be able to get it up and running, then to make it available and re-compiled after the Grains are collected. It's a very complex process, as the Grains require the Proxy to be up (which needs the Pillar data in order to know where to connect to), and some other Pillars may require Grains. So please bear in mind that this is a different story.
salt/minion.py
Outdated
| self.opts = salt.utils.dictupdate.merge(self.opts, | ||
| self.opts['pillar'], | ||
| strategy=self.opts.get('proxy_merge_pillar_in_opts_strategy'), | ||
| merge_lists=self.opts.get('proxy_deep_merge_pillar_in_opts', False)) |
There was a problem hiding this comment.
I actually never understand why static, firm, rigid, rarely changed opts are over dynamic, volatile, flexible, often changed pillars. It just makes no sense. Imagine you could just push temporarily to your minion's config, do something and return back to the default state. But here now you have it totally stuck, unless you reconfigure it and restart it.
I would propose here to do the other way around: always merge pillars over opts. And add a special opt (again, you can deliver it over pillars and even control that remotely!!!) that would disable that.
But this is probably a subject to discuss...
salt/minion.py
Outdated
| if not HAS_PSUTIL: | ||
| log.error('Unable to enforce modules_max_memory because psutil is missing') | ||
| if not HAS_RESOURCE: | ||
| log.error('Unable to enforce modules_max_memory because resource is missing') |
There was a problem hiding this comment.
Can we rephrase these messages to be user-compatible? ".....psutil Python package dependency is not installed". Same to "resource".
There was a problem hiding this comment.
Yeah, this isn't going to survive the cleanup, because it is a one off process, and this stuff is not needed.
salt/client/__init__.py
Outdated
| } | ||
| data.update(kwargs) | ||
| executors = getattr(self.sminion, 'module_executors', []) or \ | ||
| opts.get('module_executors', ['direct_call']) |
There was a problem hiding this comment.
It also can be cleaner here as well:
executors = getattr(self.sminion, 'module_executors',
opts.get('module_executors', ['direct_call']))UPDATE:
Ah, I wasn't correct. This won't work (as the other place too) if there is module_executors attribute to the sminion, but is empty. However, your version will also omit module_executors from opts, if there are any in both cases.
So just pointing this out, the rest is up to you. 😉
There was a problem hiding this comment.
So, there are certain instances when module_executors is specified on the proxy minion, and that is the module_executor that needs to be used. If that is not specified, then the user is free to specify their own module_executors.
So this is in the correct order.
There was a problem hiding this comment.
That's clear, but if module_executor is specified in both places, then the opts are discarded. Shouldn't we have to merge that instead (simply + instead of or)?
salt/client/__init__.py
Outdated
| if mopts: | ||
| self.opts = mopts | ||
| else: | ||
| self.opts = salt.config.proxy_config(c_path) |
There was a problem hiding this comment.
You use this idiom already, so why not here too:
self.opts = mopts or salt.config.proxy_config(c_path)| } | ||
| data.update(kwargs) | ||
| executors = getattr(self.minion, 'module_executors', []) or \ | ||
| self.opts.get('module_executors', ['direct_call']) |
salt/client/__init__.py
Outdated
| allow_missing_funcs = any([ | ||
| self.sminion.executors['{0}.allow_missing_func'.format(executor)](function_name) | ||
| for executor in executors | ||
| if '{0}.allow_missing_func' in self.sminion.executors |
There was a problem hiding this comment.
This actually shouldn't be needed at all, just a result of copying everything over.
This is the output of the added tests when running proxy tests. |
isbm
left a comment
There was a problem hiding this comment.
Great cleanup! I still have few little nitpicks, if you don't mind.
salt/cli/caller.py
Outdated
| # nasty sys.exit() and tick off our developer users | ||
| try: | ||
| self.minion = salt.minion.SMinion(opts) | ||
| if self.opts.get('proxyid', None) is not None: |
There was a problem hiding this comment.
Let's hope nothing can set proxyid as 0 or "".
| executors = getattr(self.sminion, 'module_executors', []) or \ | ||
| opts.get('module_executors', ['direct_call']) | ||
| if isinstance(executors, six.string_types): | ||
| executors = [executors] |
There was a problem hiding this comment.
Well, that's an interesting question. Shouldn't we just disallow wrong syntax in config and also make sure that executors are always a list? The variable name suggests it though. Personally I am not very much into favour of auto-fixing shoddy configs, because it will also grow problems like "oh, I was writing config also in that way and it worked before, but now not, fixitpls!".
I'd propose to actually crash here and politely ask to write a proper config. 😉
There was a problem hiding this comment.
This is here because it is easier to pass in --module-executors direct_call, then to have to pass it as a list on the commandline.
Also, this is the same format it is for the salt command.
There was a problem hiding this comment.
Hmm, but you actually can pass a list in command line (comma-separated or so). That's why I would propose to always convert it to the list at the very beginning, even if it is just one element there. Otherwise we will have this kinda spaghetti everywhere.
salt/utils/platform.py
Outdated
| # to support the testsuite's temp script that is called 'cli_salt_proxy' | ||
| if 'proxy' in main.__file__: | ||
| # | ||
| # (gtmanfred) Add '--proxyid' in sys.argv so that salt-call --proxyid |
There was a problem hiding this comment.
But Git blame says who wrote this comment, no need to extra-add it. 😉
| @@ -0,0 +1,65 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ''' | |||
| :codeauthor: Thayne Harbaugh (tharbaug@adobe.com) | |||
There was a problem hiding this comment.
The test_proxy.py copypaste leftovers. 😉
rallytime
left a comment
There was a problem hiding this comment.
This is neat!
I have a couple of small requests.
doc/ref/clients/index.rst
Outdated
| :members: cmd | ||
|
|
||
| Salt Proxy Caller | ||
| ----------- |
There was a problem hiding this comment.
The dashed line needs to match the length of the line above, or we'll get an RST warning.
salt/minion.py
Outdated
| class SProxyMinion(SMinion): | ||
| ''' | ||
| Create an object that has loaded all of the minion module functions, | ||
| grains, modules, returners etc. The SMinion allows developers to |
There was a problem hiding this comment.
Copy/Paste error? SMinion --> SProxyMinion?
|
|
||
| .. code-block:: bash | ||
|
|
||
| salt '*' sys.reload_modules |
There was a problem hiding this comment.
gen_modules here instead of reload_modules?
There was a problem hiding this comment.
Nah, reload_modules is correct, let me fix the code so that gen_modules overwrites reload_modules like it does in the regular salt-call
mirceaulinic
left a comment
There was a problem hiding this comment.
That's awesome! Thanks @gtmanfred!
cachedout
left a comment
There was a problem hiding this comment.
Request for additional documentation before we merge this.
|
|
||
| def _mixin_setup(self): | ||
| self.add_option( | ||
| '--module-executors', |
There was a problem hiding this comment.
IMHO we need more documentation than this about what's happening here. I'm certain that I couldn't figure out what this does from the perspective of the average Salt user.
There was a problem hiding this comment.
This is already documented for the salt command, it would be the same thing.
https://docs.saltstack.com/en/latest/ref/executors/index.html
I can add an example with salt-call --module-executors in here?
There was a problem hiding this comment.
Looking for feedback on my response.
There was a problem hiding this comment.
That's fine. We can rethink this down the road because it's a larger problem than just this particular flag.
Pull saltstack#48344 added logic to salt-call which runs the desired function using all of the executors, or just the direct_call one if none are configured. However, the previous code which ran the function was not removed, which results in the function being run twice. This removes the (now) redundant function call.
What does this PR do?
This allows using proxy minions from the minion box, for troubleshooting, and also not needing a master.
Tests written?
Not Yet
Commits signed with GPG?
Yes