Shell selection support via shebang #249
Labels
No Label
bugfix
cleanup
discussion
documentation
doing
done
feature
improvement
packaging
Stale
testing
TODO
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: ungleich-public/cdist#249
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Created by: dheule
On the local host, it would be cool to allow the user
to select which shell cdist uses to execute the manifests and gencode-* instead of /bin/sh.
Background: I don't want to replace /bin/sh with dash, but want test if my scripts are working faster with dash.
I think it would be the best way to make cdist look for the shebang line in the manifest/init file and use the selected shell for execution.
So the admin can leave the system untouched and only cdist uses a special shell.
examples:
Created by: dheule
This bug is fixed not via shebang, but via ENV variables:
CDIST_LOCAL_SHELL for local scripts
CDIST_REMOTE_SHELL for remote scripts
So i close this issue.
Created by: dheule
Hello Nico,
2013/12/18 Nico Schottelius notifications@github.com
Another solution is to have a config file on wich the now hard coded shell
can be selected.
But your idea has also some advantages,
if correctly implemented gencode and all manifests
could be written in every aviable script language ...
Created by: telmich
Shebang would definitely be possible (we could probably use a python function to figure this out), but I am not sure if this is a good idea, as most manifest/gencode-* scripts are coming without the header.
Let's put it that way: I think it's a good idea to support it, but I would be cautious to not break something for the moment (although the 3.x.x release could break things, which is upcoming this year...)
Hi,
Well, I am not a fan of the solution involving the
CDIST_LOCAL_SHELL
andCDIST_REMOTE_SHELL
environment variables, because of the all-or-nothing nature.The shebang mecanism is directly supported by Unix/Linux kernels. Therefore, in order to support it,
cdist
doesn't really need to parse or do anything clever with it. On the contrary,cdist
would need to abstain from doing too much... Just sticking with KISS will do.BTW, the current
cdist
version (v7.0.0) appears to actually support the shebang line whenever it runs a script locally, as long the script file has EXECUTE permissions set, without a need to set the CDIST_LOCAL_SHELL environment variable.This appears to work fine for
manifests
andgencode-*
scripts. You just need to make sure the shebang (#!...
) line is there and the EXECUTE bit is set on the script file.Below is an excerpt from
local.py
. When the file has EXECUTE permissions (i.e.if os.access(script, os.X_OK):
, the given script is directly executed (instead of being pass as an argument to/bin/sh
).The simple and direct for of execution (of the given script) is actually what enables the native shebang* support of the Kernel itself.
When the script is fed into
/bin/sh
(without the-c
option), the shell, by design, won't honor the shebang line. It's basically forced to interpret the script itself in that case...Unfortunately, this doesn't currently work for remote execution, which appears to systematically pass the given script to '/bin/sh' without any regard to the EXECUTE permissions, as below :
Here's how
run_script
is defined inremote.py
:The solution is actually quite simple: Just mimic the way
local.py
handles the situation (except that the check for the EXECUTE bit needs to happen on the remote side as well).I have cooked up a solution does just that, with quite minimal changes... And it appears to work fine on my end. If desired, I can submit a PR for the change.
To be on the safe side, I can try to guard the change with the BETA setting and perhaps yet another environment variable.
Note that this preliminary PR would NOT cover setting the EXECUTABLE bit on
code-local
andcode-remote
(which need to happen elsewhere, upon code generattion), but it would work wherever it is already set...explorers work, be it global or type explorers.
I am jotting down the gist of the involved change in
remote.py
below, for eventual comments :For future reference (to self and others), here are two ugly workarounds that one can resort to within the script files themselves even in the absence of a proper fix on the
cdist
side.The given examples are for
perl
, but the same conceptual mecanisms should be applicable also elsewhere... Your mileage may vary.a) Just feed a HEREDOC to your favorite interpreter
b) Resort to UGLY ancient woodoo
The below is a very UGLY HACK unfortunately needed to get this script to be interpreted by perl (instead of 'sh') with the current version (7.00) of cdist, which does the following for remote invocation :
When the script is passed as a direct argument, /bin/sh effectively ignores the shebang line... BUMMER.
So we resort to a very ancient trick...
For a detailed explanation, SEE:
Good morning @tabulon !
I think having identical behaviour on both sites makes a lot of sense.
I remember that the motivation for always using /bin/sh on the remote side was that in any case we generate the code locally and thus the assumption is that "it is always shell code".
Motivation behind that again is to only rely on the shell remotely.
Now you can argue, and it might be a good argument, to say that you can generate anything you want, including things that are interpreted by other shells.
And honestly, I don't think we should stop the user from doing that.
So +1 for making it a) consistent and b) allow the user to shoot themselves into the foot in case they generate something for which there is no interpreter. Like it, please submit a PR.
Hi @nico,
Thank you for your prompt reaction and my apologies for the late reply.
It is certainly quite wise to keep assumptions about the remote host to a bare minimum.
And yes, you are absolutely right to point out that this sort of thing is a potential footgun, especially when the intended interpreter is not present on the target system.
On the bright side, even beyond the question of consistency, it opens up a whole new range of possibilities... when ubuiquity can be traded off for more power.
Besides :
some interpreters (like
bash
andperl
) are pretty much guaranteed to be shipped with the base OS on many Unix/Linux flavors where the system plumming itself still relies on scripts written in those languages;some tools such as
awk
andsed
can be fed quite complex instructions that may be considered as a form of scripting;for those interpreters that are less certain to be shipped with the base OS, it should be quite easy to declare a dependency in cdist (via require=), ensuring their presence before attempting to make any use of the corresponding language.
On the other hand, it is important that
cdist
itself (and the global explorers shipped with it) remain free of any additional assumptions beyond the presence of/bin/sh
and a few rudimentary programs on the target system, though.I understand you are already sold on the concept, for which I am very glad :-) Still jotted down the above as a future reference for at least part of the motivation/rationale for wanting this.
Yes, I will happily put together PR or two. It might take a while tough, since I am on quite a busy schedule these days.
Meanwhile, do you mind using this issue for a few questions that may rise ?
Hi @nico,
At this point, I have got 3 branches, covering changes in different areas:
exec/remote.py
for honoring "execute" permissions on remote scriptsrelated tests
(solution as outlined above in this issue)
This, by itself, allows shebang support for explorers.
(a relatively clean solution which introduces a new class
FileScriptProperty
(infsproperty.py
), that detects the presence of a shebang and sets "execute" bits on the persisted file)Would you prefer 1 or 2 PRs ?
I guess the best would be 2 PRs... since the the first change lays the ground and allows for shebang support on any executable remote script...
But the documentation changes already assume both changes... So it would be easier for me to package all of it in one PR... :-)
Also : does the project prefer the tests to be commited before code changes (as is usually the case) or the other way around (as is sometimes preferred) ?
Finally, at least for the time being, I have not protected any of this with a beta switch or any other configuration option, as I tend to think the risks are pretty low.
Let's see how we go about that after your review. OK?
Cheers,
Tabulo[n]
Hell @tabulon !
Sorry for the late reply, a lot of things going on atm.
In regards to PRs: 1 would be preferred, including tests (where appropriate).
I just skimmed above comments and I think the direction is good, I'll need an evening tea and a bit of quiet time to fully review the changes so far.
Hi @nico,
Tell me about it... I am quite swamped on my end, too.
Just created the PR (#365) to make sure the ball is no longer on my court... :-)
No rush; whenever you can get to it.
Cheers,
Tabulon
Hi @nico (or other maintainers of cdist),
Is there anything I can do expedite the review process around PR #365 which I had submitted about a year ago, following your initial encouragement on the fringes of this issue ?
FYI: Just in case the WIP prefix causes some notifications to be filtered out on your end, I have just removed that prefix and renamed the PR, which has anyhow been ready for review from the begining.
At this point in time, it will probably be necessary to rebase the PR on current master before it can be merged. I can take care of that once you complete the review -- or beforehand, if you really prefer.
Or else, if you see any issues with the feature or its implementation in the PR, please let me know.
(I am cross-posting this comment on #365 in order to increase its chances to get noticed).
@tabulon Just wrapping my head around it, motivation looks great, now starting the review on #365.
This is great news, @nico. Thank you.
Let me know if you have any comments / questions.
Note that the changes may appear vast at first : 22 files, many lines, ... as reported by
git
.In fact, as you will notice, the actual changes to code are quite minimal. The bulk of it concerns the docs and tests.
Then again, for the tests, the change reported by
git / diff
appear to be much more than what it really is, mainly because I had to resort to burrying the original test class (CodeTestCase
) in one of the test modules (/cdist/test/code/__init__.py
), so as to be able to subclass it safely. This seems to have confused thediff
algorithm.@tabulon sorry it took so long for this to go forward. I can take over if @nico doesn't have enough bandwidth / times out.
Sure @fnux, I would be glad.
@nico said he was starting the review last week, but perhaps he got caught up in the mean time.
@nico, what say you?
Meanwhile, I took a look at the changes myself and spotted a few things that could be improved.
On the documentation side, I had probably taken too much liberty, both in terms of tone and content.
Please let me know what you folks think about that. Will happily trim down if needed.
In terms of code,
util/filesystem.py
could be improved or else reorganized to expose less API, especiallyensure_file_permissions()
, whose name promises more than what is actually implemented.