cwd evaluated before onlyif in exec - puppet 5.5.12 - puppet

In Puppet 5.5.0 this worked fine, but in Puppet 5.5.12 it does no longer work:
exec { 'example' :
command => "date",
cwd => "/fu",
onlyif => "ls /fu",
path => ['/usr/bin', '/usr/sbin', '/bin', ],
}
Error message:
Could not evaluate: Working directory /fu does not exist!
So somehow cwd is now getting evaluated before the onlyif making the latter futile. Any idea where this comes from in this minor release from 5.5.0 to 5.5.12?
Is there a bug or intended behavior? I could not find anything so far.
Any input is appreciated :)

So somehow cwd is now getting evaluated before the onlyif making the
latter futile. Any idea where this comes from in this minor release
from 5.5.0 to 5.5.12?
This is Puppet issue PUP-9194, which they claim to be a fix for a regression. It was reported against Puppet 6, and it is documented in the release notes for Puppet 6.0.2. The comment thread on the ticket reports that the fix was also applied to the Puppet 5 codebase. No release note seems to have been added in the Puppet 5 series, but the timing is right for Puppet 5.5.7.
Is there a bug or intended behavior? I could not
find anything so far.
Evidently the behavior change was intentional; it is the old behavior that was considered buggy. I note here that that conclusion seems to be based on historic practice, not documentation (so the behavior you relied upon differed from even older behavior). The docs for onlyif specify several Exec attributes that apply both to the main command and to onlyif commands, and cwd is not among them.

This is intended behaviour I'm afraid. From https://puppet.com/docs/puppet/5.5/types/exec.html#exec-attribute-cwd:
cwd
The directory from which to run the command. If this directory does not exist, the command will fail.
Could you recode as something like this?
exec { 'example' :
command => "cd /fu && date",
onlyif => "[ -d /fu ]",
path => ['/usr/bin', '/usr/sbin', '/bin', ],
}

Related

Using glob in Yarn/NPM script

I'm using a script to run multiple files with Node.js using a glob pattern to capture the files:
node build/**/*.spec.js
This seems to work fine, but when I put the same command in the scripts object as follows
"scripts": {
"test": "node build/**/*.spec.js"
}
and try to run it with yarn test or npm run test I get the following error:
Error: Cannot find module '/path/to/project/build/**/*.spec.js'
indicating that it's treating the glob pattern as a literal filename.
How can I achieve the glob behaviour in a Yarn/NPM script?
A couple of things to note here:
The behaviour of node build/**/*.js depends on your shell.
In zsh (the current default on macOS), it does what you expect; expanding the glob to all matching files and passing them to Node.
In bash and sh, it tries to run the literal file build/**/*.js with Node, which gives the "Cannot find module" error in your post.
The default shell used by npm run-script is, per the docs:
'/bin/sh' on POSIX systems
Even if you're using zsh, when you run the test script it uses sh. You can configure this with the script-shell option, e.g.:
in .npmrc (which you can update with npm config set script-shell=/bin/zsh); or
inline (by running npm --script-shell=/bin/zsh test).
However you get it running, note that only one of the matched files actually gets executed; the paths to the other two are passed as command line arguments. With three files foo.spec.js, bar.spec.js and baz.spec.js containing the following (adjusted to log each file's own name) in build/:
console.log(process.argv);
console.log("foo");
running the globbed version gives:
$ node build/**/*.spec.js
[
'<path/to>/bin/node',
'<path/to>/build/bar.spec.js',
'build/baz.spec.js',
'build/foo.spec.js'
]
bar

Unable to run node from git bash

I am no longer able to run node from the git bash terminal. It works from Git CMD and the standard windows CLI. If I try to run a file (e.g. node index.js) or even just start node via node, I go back to the input prompt except now I can't see any of my character inputs.
This is not a result of PATH not being set, as where node gives me C:\Program Files\nodejs\node.exe and which node gives me /c/Program Files/nodejs/node and echo $PATH does have /c/Program Files/nodejs included.
If I type another command (such as ls), it actually will work even though I will continue to not be able to see my input.
I think this problem arose after the latest Windows 10 OS update was pushed to my system (10.0.17763). I've tried reinstalling Git for Windows and Node, and neither have resolved the issue. I can't find any other settings that might be affecting this.
Using Git CMD or Windows CLI is a workaround, but neither of those have a "Git Bash Here" option, which is the #1 thing I want this for. It is also nice that I get the visual indication of branch in Git Bash where I do not get that with Git CMD or the Windows CLI.
I don't need or want to use Git GUI, and besides that won't allow me to run local node files which I need to do for testing.
Does anyone have any ideas on how I can get Git Bash working with node again?
UPDATE: By running stty -a after node fails, I see that echo has flipped to -echo, which is why I can't see the input anymore. But that doesn't explain why node isn't loading and echo is getting turned off. Hoping that gives someone some additional context to figure out what's going on here. brkint, icrnl, ixon, opost, isig, and icanon are also getting flipped to the - versions after attempting to run node.
There are 2 possible workarounds (based on what your problem is) that I have tried-
Enter node first of all:
1) Try typing in reset and hit enter. You may not be able to see the input logging in, in the bash terminal window, but it works after that.
2) Or try typing any random alphabet and hit enter(again you won't see it on the screen),it will throw a 'command not found' error but you will have node working after this.
I am afraid these aren't exactly proper fixes, but they get the job done.
More information can be found here: https://askubuntu.com/questions/171449/shell-does-not-show-typed-in-commands-reset-works-but-what-happened/172747#172747

How do I use puppet to execute a script on a linux VM

I need puppet to execute a script that is inside an installed app. In addition I need to run only if it detects an older version of the and is not on a certain server and then install the new version
I have tried a bunch of stuff and I am losing track. First I tried to use a cd to go to the where the script and then tried running the script directly but I keep getting the same error.
install.pp
# Install required packages
class tripwire::install {
exec { 'uninstall_tripwire':
command => './usr/local/tripwire/te/agent/bin/uninstall.sh',
cwd => '/usr/local/tripwire/te/agent/bin',
path => '/usr/bin/sh',
onlyif => [
"${::fqdn} != 'server.com'",
'/usr/bin/test -f
/usr/local/tripwire/te/agent/bin/uninstall.sh',
"grep -c '8.6.0' /usr/local/tripwire/te/agent/data/version",
],
notify => Exec['install_tripwire'],
I would think this would it would execute the script but all I get is:
Error: /Stage[main]/Tripwire::Install/Exec[uninstall_tripwire]: Could not evaluate: Could not find command 'server.com'
I need puppet to execute a script that is inside an installed app. In
addition I need to run only if it detects an older version of the and
is not on a certain server and then install the new version
The particular task you seem to be trying to perform with your Exec duplicates standard behavior of the Package resource. You really, really ought to manage software via packages, even if you have to do some packaging yourself and maintain a local package repository. The time spent on packaging is easily offset by the time saved managing software, even with Puppet in the mix.
Additionally, as far as controlling which machines to operate upon goes, you ought to be treating that as a matter of classification. If that class should not be applied to machine server.com then it should not be declared into that machine's catalog. If it should be applied differently to that machine than to others, then it should be appropriately parameterized, and those parameters used (at classification time, maybe with the help of Hiera) to select the appropriate behavior for each target machine.
Nevertheless, with respect to the code actually presented, the error message
Could not evaluate: Could not find command 'server.com'
reflects that this element of your onlyif array ...
"${::fqdn} != 'server.com'",
... is not a command. onlyif requires a command or an array of them that can be executed on the target system, so maybe this, instead:
"test ${::fqdn} != server.com",
Additionally, this looks wrong:
command => './usr/local/tripwire/te/agent/bin/uninstall.sh',
Remove the leading ., unless you really intend to resolve that path against the working directory. And if you do intend to resolve it as a relative path then I urge you to instead expand it to an absolute one.
Furthermore, this probably doesn't do what you intend:
path => '/usr/bin/sh',
The path attribute names a binary search path, like the PATH environment variable. You may indeed want to specify one, such as maybe '/bin:/usr/bin:/sbin:/usr/sbin', but if the intention of what you did put was for the commmand to be executed via a shell, then you were looking for
provider => 'shell',

Puppet "onlyif" attribute cannot find not(!) operator

I am trying to figure out if Node package PM2 is installed in the path and executable or not with the following puppet code.
exec { "create symbolic link for pm2":
cwd => "${pm2_link_dir}",
path => ['/usr/bin','/bin','/usr/sbin','/sbin'],
onlyif => "! which node &> /dev/null",
command => "ln -s ../lib/node_modules/pm2/bin/pm2 pm2"
}
It is telling me cannot find command "!". Is this the right way to find out if some program is installed and executable?? And why puppet cannot understand The not operator?? I am working on Redhat master and slave.
And why puppet cannot understand The not operator?
The ! operator is provided by the shell; it is not a command. You are using Exec's default provider (posix) which runs your commands directly rather than via a shell. (Or so it is documented to do. It has recently come to light that sometimes the posix provider runs commands via the shell, in apparent contradiction of its docs.)
It is anyway a bit silly to use ! in an Exec's onlyif attribute, when you could instead drop the ! and switch to an unless attribute instead. And drop the redirection, which also relies on the shell.
Is this the right way to find out if some program is installed and executable?
It is usually better to know whether the program should be available on the specific target node, and where necessary to ensure that it is available. If you must inquire about node state, then it is usually better to do that via a custom fact.
With that said, I don't think your approach is inherently wrong, though of course it will only look for the requested program in the path you specify in the Exec.

How to use curly brackets in npm scripts?

I want to run this simple command in an npm script called prepare_build:
...
scripts: {
"prepare_build" : "mkdir -p dist/lib/{js,css}"
}
...
running npm run prepare_build would create a single directory dist/lib/{js,css} whereas running the command in the console would create both dist/lib/js and dist/lib/css.
What am I doing wrong here?
Note:
I am aware of Gulp, Grunt, and other build systems WHICH I don't want to use
OS Interoperability is not of concern here. Linux is the main target.
The {js,css} syntax is neither a feature of mkdir, nor is it a feature of the OS. It is a feature of your shell (probably bash). So in order to interpret it you need to execute a shell that can understand that syntax.
The following will probably work but is untested:
scripts: {
"prepare_build" : "bash -c 'mkdir -p dist/lib/{js,css}'"
}
This executes bash which transforms the command into:
mkdir -p dist/lib/js dist/lib/css
before executing it.
When using the npm scripts there tend to be certain quirks that occur, especially when trying to create npm scripts that work on Win, Linux and Mac. It is often most pragmatic to find workarounds. In your case I would recommend installing the mkdirp package npm install mkdirp --save-dev and then the following will work:
scripts: {
"prepare_build" : "mkdirp dist/lib/js dist/lib/css"
}

Resources