0

Currently I fail to run an azure CLI command from Groovy because of the JSON Part in the Command.

There is an azure command to run custom scripts on a virtual machine. The CommandToExecute on the Machine is passes as JSON.

WORKING Example:

REQUEST-CALL in Console:az vm extension set -g demo --vm-name demo-cfg01 --name CustomScript --publisher Microsoft.Azure.Extensions --settings '{"commandToExecute":"ls"}'

RESPONSE: {
  "autoUpgradeMinorVersion": true,
  "forceUpdateTag": null,
  "id": "/subscriptions/xxxxxxxxxx-xxxxxx-xxxx-xxxx-xxxxxxxxxxxxx/resourceGroups/demo/providers/Microsoft.Compute/virtualMachines/demo-cfg01/extensions/CustomScript",
  "instanceView": null,
  "location": "germanycentral",
  "name": "CustomScript",
  "protectedSettings": null,
  "provisioningState": "Succeeded",
  "publisher": "Microsoft.Azure.Extensions",
  "resourceGroup": "demo",
  "settings": {
    "commandToExecute": "ls"
  },
  "tags": null,
  "type": "Microsoft.Compute/virtualMachines/extensions",
  "typeHandlerVersion": "2.0",
  "virtualMachineExtensionType": "CustomScript"
}

This script works fine.

"Same" Command executed with Groovy leads to following:

def process
        StopWatch.withTimeRecording("EXECUTING COMMAND '" + cargs + "'",_logger, Level.ALL) {
            process = (cargs).execute(null,null);
            process.waitForProcessOutput(sout, serr)
        }

Please notice the StopWatch which logs the StringArray containing the params:

EXECUTING COMMAND '[az, vm, extension, set, -g, demo, --vm-name, demo-cfg01, --name, CustomScript, --publisher, Microsoft.Azure.Extensions, --settings, '{"commandToExecute":"ls"}']'

The Params looks the same as in the console

The Response from Azure is:

VM has reported a failure when processing extension 'CustomScript'. Error message: "Enable failed: failed to get configuration: error reading extension configuration: error parsing settings file: error parsing json: json: cannot unmarshal string into Go value of type map[string]interface {}

I think groovy somehow escapes the characters before execution, i cannot figure out what went wrong. Any suggestion?

TheShadow
  • 581
  • 4
  • 10

3 Answers3

0

when you call execute on array groovy (actually java) doublequotes each parameter.

just build your command line as you need in a string

string in groovy has the same execute method as an array...

def cmd = """az vm extension set -g demo --vm-name demo-cfg01 --name CustomScript --publisher Microsoft.Azure.Extensions --settings '{"commandToExecute":"ls"}' """
def process = cmd.execute()

when you use execute on string groovy will execute the exact command you've provided

daggett
  • 26,404
  • 3
  • 40
  • 56
  • sadly that does not solve the issue - the same result – TheShadow Jul 20 '18 at 04:54
  • 1
    For the love of your sanity, don't use `"string".execute()` (ever) - rewrite it so you do `["az","vm","..."].execute()` and *don't* quote your params for a shell that is never involved. If you need shellisms, then use `["sh","-c","am vm ..."].execute()` – cfrick Jul 20 '18 at 05:07
  • @cfrick, i'm not agree. jut look at [ProcessImpl](http://www.docjar.com/html/api/java/lang/ProcessImpl.java.html) constructor with array of strings (line 151), that is finally called when you use `[].execute()`. It builds the single string command line and quotes some of array elements. in some cases especially in ms tools you don't need those quotes... – daggett Jul 20 '18 at 06:52
  • @daggett It does not in jdk8 and even it still does, this is not your problem. If you quote and the JDK quotes, then it's wrong again. Groovy splits a string with `.execute()` on whitespace and whatever quoting you do, it wont prevent it. – cfrick Jul 20 '18 at 14:03
0

Found a "workaround". The az command also accept an *.json file as settings parameter. Therefor i first create the command in a temporary json file and passes the json file as parameter. Works!

TheShadow
  • 581
  • 4
  • 10
0

You are quoting for an .execute() call. You dont need to quote there, because no shell or command parser is involved here.

Your command there gets '{"commandToExecute":"ls"}', which is a valid JSON String (no Map) and this is also what the error message states:

error parsing json: json: cannot unmarshal string into Go value of type map[string]interface

Just use {"commandToExecute": "ls"} (no surrounding ') as argument there.

cfrick
  • 35,203
  • 6
  • 56
  • 68
  • The Parsing issue is from Azure. if i leave the ' the command fails on client side because of the Json which is not recognized as correct parameter... – TheShadow Jul 23 '18 at 07:47
  • 1
    Then this tool is borked and you should create a ticket there. And if they claim it is not bugged, i whish them good luck with making unix users make sense of behaviour like this ;P – cfrick Jul 24 '18 at 04:59