-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ncm-metaconfig: support running arbitrary commands in various steps #1451
ncm-metaconfig: support running arbitrary commands in various steps #1451
Conversation
|
||
my ($err, $out); | ||
my %opts = ( | ||
shell => 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think allowing shell=>1 is a really bad idea as it allows all sorts of security risks to be introduced by template admins. I'm OK with arbitrary commands from the profile but arbitrary shell expansions and injection attacks is probably a step too far. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gombasg wanted filecopy powers 😉
what do you propose: we try to split the string in a command and run it without shell => 1
. you know any good libraries that do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the key question is: do we allow more than one command? If not, then make it a list and pass that through. If we want to allow multiple commands... but why? I am trying to remember what other (good) use cases we have for arbitrary commands in file copy. Mostly it's restarting daemons with custom scripts, which tbh should all be moving to systemd so it's a legacy use case.
Validation seems a valid use case for an arbitrary command, but is there a use use for multiple commands to execute validation? Seems unlikely? Probably best to wait for Gabor to chime in tomorrow but restricting this to the identified use cases to avoid abuse seems valid here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ned21 see also #1377 (comment) and comments below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I've also found cases in our templates when errors from restarting/reloading the service needs to be suppressed, so we use service foo reload || true
. A common reason is the initial build process, when the service is not expected to be operational yet, but we don't want the rest of the build process to fail. Changing every occurrence of restart
to condrestart
/try-restart
could help in some cases, but systemd
does not have try-reload
. Hmm, if there was a component-level flag which could in turn tell CAF::Service
to ignore all errors, then we could set that flag during the build...
Anyway, I'd like to repeat the idea of separating the definition of a command from triggering a command - @ned21, just like how startup actions work. So something like:
prefix "/software/components/metaconfig",
"commands/dconf_update" = "dconf update";
"services/{/etc/dconf/db/gdm.d/00-login-screen}" = dict(
"contents", ...,
"actions/post", "dconf_update",
);
This way, it would be more difficult to "hide" arbitrary commands in the noise, because all such commands would end up in a single block in the profile, suitable for reporting/auditing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just spotted this use of shell commands in our code base:
/usr/sbin/alternatives --set mta /usr/sbin/sendmail.sendmail; systemctl restart sendmail.service
But then with this code, I think we could still do that? The alternatives command would be run by the changed or post action, and then the restart would happen via the standard daemons attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the daemons are only triggered by a change, you can also run the alternatives in the pre section.
when is it triggered now? only on change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, on change only via file copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in that case, yes this would work (but only because you are lucky enough that last command is a daemon action).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but my point is that a lot of where we currently have shell "tricks" could be re-thought to be cleaner. But if we give people a $shell=>1 crutch they'll just port directly across from filecopy without trying to find a better way.
What we found with file copy is that once sites are using shell=1, there's now way to back out of it without risk of breakage. So it's much better to start with shell=0 and then only turn it on if we find a proper use case that can't be solved any other way.
@gombasg i tried to add it. the naming is now a total mess far beyond my capabilties |
f725f72
to
bad2f07
Compare
@@ -118,9 +130,26 @@ type ${project.artifactId}_config = { | |||
'contents' : ${project.artifactId}_extension | |||
@{Predefined conversions from EDG::WP4::CCM::TextRender} | |||
'convert' ? ${project.artifactId}_textrender_convert | |||
@{Actions (i.e. named registered commands) to run on pre, validation and/or post step. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actions (i.e. names found /software/components/metadata/commands) to run when processing the service. Refer to the ${project.artifactId}_actions type definition for the available hooks for when a command may be run.
} = dict(); | ||
|
||
type ${project.artifactId}_component = { | ||
include structure_component | ||
'services' : ${project.artifactId}_config{} with valid_absolute_file_paths(SELF) | ||
@{Command registry for allowed actions, keys should be used as action value} | ||
'commands' ? string{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to say something about how commands are executed. i.e. (depending on discussion below): The commands will be executed via CAF::Process without shell.
|
||
my ($err, $out); | ||
my %opts = ( | ||
shell => 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still vote for shell=>0. Looking at the docs, this should work just fine if we want the input to be strings?
my $cmd = CAF::Process->new(["ls -lh"], log => $self);
One of the reasons this structure is nice is that I can also nullify or replace any command I don't like with a central dict update:
'metaconfig/commands/not-for-me' = '/bin/true';
without having to loop through all services
to find the right one.
I could potentially also do that conditionally using Aquilon's build status to e.g. avoid running commands that I know won't work during anaconda and but allowing them to run fine once we've left buildstatus=build.
(yeah, that's a bit ugly but potentially less so than the cmd||/bin/true
hacks we have at the moment)
This is a long thread so let me try summarise. I think we're pretty close to a conclusion:
|
other question: can we force that all commands start with a absolute path to the executable? otherwsie, i have to invent my own path resolution too. |
@ned21 i'll use |
What about el6? :-( Do we need a splitter though? the CAF::Process doc says it accepts a string with shell=0. Or is that a mis-reading on my part?
I like that.
Yes, absolutely paths only. |
@ned21 for el6, i find no packages, and some sites seem to suggest it is part of perl 5.10 itself. can you check that? and where did you read that about CAF? |
Can't find any trace of Text-Parsewords on an EL6 system. However I tested:
Shows the contents of /.
So I think this confirms it's not necessary. |
@ned21 that splits on whitespace only, so no proper quote handling for args with space. |
On EL6, it is provided by “perl”. So if the Maven plugin uses the standard RPM macros to detect Perl dependencies, then everything should work. If not, then there’s a problem, because the dependency will need to be OS version specific – which needs to be implemented for RH8 support anyway…
From: Stijn De Weirdt <[email protected]>
Sent: 12 June 2020 22:15
To: quattor/configuration-modules-core <[email protected]>
Cc: Gombas, Gabor (Enterprise Infrastructure) <[email protected]>; Mention <[email protected]>
Subject: Re: [quattor/configuration-modules-core] ncm-metaconfig: support running arbitrary commands in various steps (#1451)
@ned21<https://github.com/ned21> that splits on whitespace only, so no proper quote handling for args with space.
so perl -e 'use Text::ParseWords' fails on el6? what about repoquery --whatprovides "perl(Text::ParseWords)"
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#1451 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABNYSMHBKLKHZI5JNVNL2N3RWKEFXANCNFSM4N2V7VTA>.
…________________________________
NOTICE: Morgan Stanley is not acting as a municipal advisor and the opinions or views contained herein are not intended to be, and do not constitute, advice within the meaning of Section 975 of the Dodd-Frank Wall Street Reform and Consumer Protection Act. If you have received this communication in error, please destroy all electronic and paper copies and notify the sender immediately. Mistransmission is not intended to waive confidentiality or privilege. Morgan Stanley reserves the right, to the extent required and/or permitted under applicable law, to monitor electronic communications, including telephone calls with Morgan Stanley personnel. This message is subject to the Morgan Stanley General Disclaimers available at the following link: http://www.morganstanley.com/disclaimers. If you cannot access the links, please notify us by reply message and we will send the contents to you. By communicating with Morgan Stanley you acknowledge that you have read, understand and consent, (where applicable), to the foregoing and the Morgan Stanley General Disclaimers.
You may have certain rights regarding the information that Morgan Stanley collects about you. Please see our Privacy Pledge https://www.morganstanley.com/privacy-pledge for more information about your rights.
|
@gombasg only when the maven config has the dependecies explicitly set. otherwise, it's the usual perl.req script that adds them (in the |
85e443c
to
5ca3913
Compare
ah, yep: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes. Just a few questions about docs, fixing some typos, etc.
type ${project.artifactId}_actions = { | ||
@{Always run, happens before possible modifications} | ||
'pre' ? string | ||
@{Always run, happens before possible modifications, the file content is passed om stdin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@{Always run, happens before possible modifications, the file content is passed om stdin. | |
@{Always run, happens before possible modifications, the new file content is passed on stdin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@{Always run, happens before possible modifications, the file content is passed om stdin. | |
@{Always run before possible modifications with the new (or unchanged) file content is passed on stdin. A failure will cancel any file modification, unless the command is prefixed with -. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i find new (or unchanged)
confusing. i would expect new/changed (or unchanged)
,but maybe i need some sleep ;)
this is actually the generated content, and this runs before anything is written. on failure, it just stops, writing to disk or even comparing with previous content is not attempted (i think, i would have to look at the code in FileWriter).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unsure about "unchanged", if it clouds the situation then let's just go for:
Always run before possible modifications with the generated file content is passed on stdin. A failure will cancel any file modification, unless the command is prefixed with -.
type ${project.artifactId}_actions = { | ||
@{Always run, happens before possible modifications} | ||
'pre' ? string | ||
@{Always run, happens before possible modifications, the file content is passed om stdin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@{Always run, happens before possible modifications, the file content is passed om stdin. | |
@{Always run before possible modifications with the new (or unchanged) file content is passed on stdin. A failure will cancel any file modification, unless the command is prefixed with -. |
@@ -86,6 +86,18 @@ type ${project.artifactId}_textrender_convert = { | |||
|
|||
type caf_service_action = string with match(SELF, '^(restart|reload|stop_sleep_start)$'); | |||
|
|||
type ${project.artifactId}_actions = { | |||
@{Always run, happens before possible modifications} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe also add A failure will cancel any file modification, unless the command is prefixed with -.
here (because it's the case)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good idea.
5ca3913
to
c4a029d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I have missed something, I think my documentation suggestions are still pending?
@ned21 please check again, i think it's ok now |
@ned21 changes pushed |
Co-authored-by: Nathan Dimmock <[email protected]>
51f7b3f
to
1a391bc
Compare
@jrha conflicts resolved |
Anything else that's needed here? We are really keen to have #1452 which depends on this. |
@ned21 i'm happy with it 😉 |
No description provided.