Saltstack cloud.map with Bash variables - bash

I'm trying to provision a Windows virtual machine in VMWare using Salt Cloud wrapped in a bash script so that I can parameterise it but I'm having a problem with the escaping of the map_data.
my command is:
#!/bin/bash
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"HOSTNAME":{"folder":"FOLDER","devices":{"network":{"Network adapter 1":{"ip":"MYIP"}}}}}]}'
This works fine however I would like HOSTNAME, FOLDER and MYIP to be variables ($hostname $folder and $ip) and I'm struggling a bit with the escaping so that the variables are expanded and passed correctly to salt.
I have tried putting the variable inline in the command:
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"$hostname":{"folder":"$folder,"devices":{"network":{"Network adapter 1":{"ip":"$ip"}}}}}]}'
This gets as far as copying the template in the profile before bombing out with a vmware error about the variblised elements being incorrect
I have also tried to encapsulate the whole map data in a variable, escaping the double quotes and passing that, e.g,
data="'{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}'"
This appears to expand correctly if I echo it out but when I add it to my command:
salt salt-cloud cloud.map_run map_data=$data
I get the following error:
Passed invalid arguments to cloud.map_run: map_run() takes at most 1 argument (10 given)
I know that this is probably not strictly Salt's problem but I wondered if anyone out there could give me some pointers on how to proceed?

Did you try the concatenation of strings like that :
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"'$hostname'":{"folder":"'$folder',"devices":{"network":{"Network adapter 1":{"ip":"'$ip'"}}}}}]}'

I don't use the cloud app myself, so I can't test it but looking at the first command you give:
salt salt-cloud cloud.map_run map_data='{"PROFILE":[{"$hostname":{"folder":"$folder,"devices":{"network":{"Network adapter 1":{"ip":"$ip"}}}}}]}'
Because the variables are in single quotes, they won't expand. So that won't work.
The second command you gave:
data="'{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}'"
Looks correct, it will expand the variables, but compared to the first command it will also add single quotes to the string (I think you forgot to remove those?).
Also in your first command a " seems to be missing after $folder.
Fixing those mistakes gives me the command:
salt salt-cloud cloud.map_run map_data="{\"PROFILE\":[{\"$hostname\":{\"folder\":\"$folder\",\"devices\":{\"network\":{\"Network adapter 1\":{\"ip\":\"$ip\"}}}}}]}"
which I think would work. If you put an echo in front of your command, and just copy your json, you can copy/paste it into a json formatter like https://jsonformatter.curiousconcept.com/ and it will tell you if the json you used is correct. This will help you find things like missing quotes.

Related

How to get a .BIN extension for a file name in a cmd, obtained from a variable off a text file (using powershell) [duplicate]

Test-NetConnection returns TRUE when run manually but when in a looping script, only some of the ports returns TRUE.
I wrote a powershell script that loops through port numbers to do a Test-NetConnection:
$machine = '[targetmachinename]'
$this_machine = $env:COMPUTERNAME
$port_arr = #(8331, 8332, 8333, 8334, 8335, 8310, 8311)
foreach ($port in $port_arr) {
Test-NetConnection $machine.domain.name.com -port $port -InformationLevel Quiet
}
When I run the script, it always returns TRUE on the same two port numbers and returns FALSE on the other ports.
When I manually run the code for each port, they each come back as TRUE for all ports.
I have tried messing around with the port numbers by removing, adding, and moving them around but it always gives the same results with only the same two port numbers returning TRUE.
I suspected maybe the variable, array, foreach loop or something might be bad, but if that was the case, why would it work for the same two ports and not for the others even when I change up the array?
I was thinking about putting a delay or wait in between loops but have not tested it yet.
This script works fine when run locally from the target machine. Having this issue when running the script from another machine.
UPDATE:
Looking at the powershell log:
Command start time: 20191111121539
**********************
PS>TerminatingError(New-Object): "Exception calling ".ctor" with "2" argument(s): "No connection could be made because the target machine actively refused it [IPADDRESS]:[PORT]""
I noticed that the IPADDRESS does not match up with the target machine name, but instead matches up with the source machine.
I replaced the $machine.domain.name.com to the actual ip address of the machine and that got the script working as expected.
Why does $machine.domain.name.com resolve to the source machine? Even if I concatenate that incorrectly, wouldn't that normally become an unresolved address and error? Shouldn't all port checks have failed at that point?
tl;dr
Replace argument
$machine.domain.name.com
with
"$machine.domain.name.com"
While unquoted command arguments in PowerShell are typically treated as expandable strings - i.e., as if they were implicitly enclosed in "...", this is not the case if your argument starts with a variable reference such as $machine.
In that case, PowerShell tries to evaluate the argument as an expression, and since [string] variable $machine has no .domain property (and subsequent nested properties), the entire argument effectively evaluates to $null[1] - resulting in inadvertent targeting of the local machine by Test-NetConnection.
The subtleties around how PowerShell parses unquoted command arguments:
are explored in this answer.
what the design rationale behind these subtleties may be is the subject of this GitHub issue.
Conversely, to learn about how expandable strings (string interpolation) - variable references and expressions embedded in "..." - work in PowerShell,
see this answer.
Additionally, BACON observes the following regarding the use of -InformationLevel Quiet with Test-NetConnection:
I think passing -InformationLevel Quiet was actively impairing debugging in this case. Given $machine = 'foo', compare the output (particularly the ComputerName property) of:
Test-NetConnection $machine.domain.name.com -InformationLevel Quiet
vs.
Test-NetConnection $machine.domain.name.com
vs.
Test-NetConnection "$machine.domain.name.com".
In other words, [it's best to] ensure that the cmdlet (and its parameters) is behaving as expected before passing the parameter that says "I don't care about all that information. Just tell me if it passed or failed."
[1] $null is the effective result by default or if Set-StrictMode -Version 1 is in effect; with Set-StrictMode -Version 2 or higher, you would actually get an error.
A common mistake I've seen people make (myself included) is in your variable name and usage in powershell. For example I forgot $ all the time. This is just looping through my machine as an example, but it tests all these ports correctly.
$port_arr = #(139,3389,5040)
$mac = #("myComputer")
foreach ($mc in $mac){
foreach ($i in $port_arr) {
Test-NetConnection $mc -port $i
}
}
Do you have an example of your powershell code? Also, have you stepped through to determine that it's working as expected?

In bash, how to convert this hexa character to readable?

Duplicate of https://unix.stackexchange.com/questions/159253/decoding-url-encoding-percent-encoding, but SO does not understand url from different stack.
Inside a docker container, I use environment variables (that I do not manage initialy, so I cannot act on them) inside a bash script.
One of the environement variable has one hexa character, but the rest of the string is OK.
Original string is: toto#t.
It is recuperated as toto%40t in the script with the following command:
echo "$VAR"
Note the # that is transformed into %40
With "minimal Ubuntu 20" (Installation of additionnal tools is possible, but I want to avoid it), pure bash if possible, how can I format the variable to get the original format ?

How to combine ssh and server variables

Please note that I'm trying to create a ssh connection using variables and I getting the below:
SSH_USR=test
SSH_HOST=1.1.1.1
ssh $SSH_USR#SSH_HOST
I get the below output:
#1.1.1.1 - instead of the user and host.
Any ideas on how I can get the values parsed?
Thibo
In order to use the variables you initialized you must precede the variable name with a dollar sign $ whenever you reference the value it contains.
Since you used it correctly before SSH_USR I think you just made a typo and missed it for SSH_HOST:
SSH_USR=test
SSH_HOST=1.1.1.1
echo SSH_USR is $SSH_USR
echo SSH_HOST is $SSH_HOST
echo final statement is ssh $SSH_USR#$SSH_HOST
ssh $SSH_USR#$SSH_HOST

Ruby system arguments

I'm trying to use system to run nmap from a ruby program. I want to escape some of the arguments to prevent shell injection so I'm using the following form:
system('nmap', '-sn', hostname)
This works fine, however I want to use the -oX - option to output xml to stdout. The following code doesn't seem to work though:
system('nmap', '-sn', '-oX -', hostname)
The -oX - argument seems to be ignored, can anyone suggest a workaround?
As system also escapes spaces in arguments, your system call with -oX - will effectively be called as
nmap "-sn" "-oX -" "example.com"
with the space being part of a single argument. It will thus not be considered a valid argument for nmap. To fix this, you actually have to pass it as two arguments. Here, the space in the single argument will not be escaped:
system('nmap', '-sn', '-oX', '-', hostname)

bash find if a variable contains a symbol and escape it

I have written a bash script for Mac OS X that gathers a lot of computer information and writes it to a MySQL database. Everything works fine except one thing. One of the pieces of information I gather is the Computer Name. Probably around 90% of the computers have an apostrophe in their names. The problem is that when I try to write the variable to MySQL it errors out due to the apostrophe.
Is there a way to find if a variable contains an apostrophe and if it does rewrite the variable with the escape character? I am sure I need to use sed but I am still pretty new to this.
For example if I have the following variable:
COMPUTER_NAME="Fred Flintstone's MacBook Air"
How can I change the variable to:
COMPUTER_NAME="Fred Flintstone\'s MacBook Air"
I can pass this off to perl of I need to but I would rather keep it in BASH.
I also don't want to rename the computers because there are over 300 of them.
This will escape apostrophes that are not already escaped:
${COMPUTER_NAME/[^\\]\'/\\\'}
Try doing this to escape what you want :
string="Hello, c'est bientôt l'été ?"
printf '%q\n' "$string"
Output
$'Hello, c\'est bient\303\264t l\'\303\251t\303\251 ?'
You can use Parameter expansion with substitution:
COMPUTER_NAME="${COMPUTER_NAME//\'/\'}"

Resources