Error decoding results stdout_lines
mateo08c opened this issue · comments
ansible [core 2.16.5]
config file = None
configured module search path = ['/home/mateo/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/mateo/.local/lib/python3.10/site-packages/ansible
ansible collection location = /home/mateo/.ansible/collections:/usr/share/ansible/collections
executable location = /home/mateo/.local/bin/ansible
python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
jinja version = 3.0.3
libyaml = True
Error parsing results: Error decoding results json: cannot unmarshal array into Go struct field AnsiblePlaybookJSONResultsPlayTaskHostsItem.plays.tasks.hosts.stdout_lines of type string
"github.com/apenella/go-ansible/v2/pkg/execute"
"github.com/apenella/go-ansible/v2/pkg/execute/measure"
results "github.com/apenella/go-ansible/v2/pkg/execute/result/json"
"github.com/apenella/go-ansible/v2/pkg/execute/stdoutcallback"
"github.com/apenella/go-ansible/v2/pkg/playbook"
var err error
var res *results.AnsiblePlaybookJSONResults
buff := new(bytes.Buffer)
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
ExtraVars: map[string]interface{}{
"ansible_network_os": "ios",
"ansible_user": "xxx",
"ansible_password": "xxx",
"ansible_connection": "network_cli",
"ansible_become": "yes",
"ansible_become_pass": "xxx",
"ansible_become_method": "enable",
},
Inventory: "192.168.1.18,",
}
p := &playbook.AnsiblePlaybookCmd{
Playbooks: []string{"playbooks/test.yml"},
PlaybookOptions: ansiblePlaybookOptions,
}
exec := measure.NewExecutorTimeMeasurement(
stdoutcallback.NewJSONStdoutCallbackExecute(
execute.NewDefaultExecute(
execute.WithCmd(p),
execute.WithWrite(io.Writer(buff)),
),
),
)
err = exec.Execute(context.TODO())
if err != nil {
c.String(500, "Error executing playbook: %s", err.Error())
return
}
res, err = results.ParseJSONResultsStream(io.Reader(buff))
if err != nil {
c.String(500, "Error parsing results: %s", err.Error())
return
}
---
- name: Cisco show version example
hosts: all
gather_facts: false
tasks:
- name: run show version on the routers
ios_command:
commands: show version | incl Version
register: output
- name: print output
debug:
var: output.stdout_lines
PLAY [Cisco show version example] **********************************************
TASK [run show version on the routers] *****************************************
ok: [192.168.1.18]
TASK [print output] ************************************************************
ok: [192.168.1.18] => {
"output.stdout_lines": [
[
"Cisco IOS Software, C2960 Software (C2960-LANLITEK9-M), Version 12.2(52)SE, RELEASE SOFTWARE (fc3)",
"BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(53r)SEY3, RELEASE SOFTWARE (fc1)",
"Version ID : V04",
"Switch Ports Model SW Version SW Image"
]
]
}
PLAY RECAP *********************************************************************
192.168.1.18 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
{
"custom_stats": {},
"global_custom_stats": {},
"plays": [
{
"play": {
"duration": {
"end": "2024-04-01T03:08:28.359220Z",
"start": "2024-04-01T03:08:25.115857Z"
},
"id": "ff523e0a-84a7-e3d6-229a-000000000006",
"name": "Cisco show version example"
},
"tasks": [
{
"hosts": {
"192.168.1.18": {
"_ansible_no_log": false,
"action": "ios_command",
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"invocation": {
"module_args": {
"commands": [
"show version | incl Version"
],
"interval": 1,
"match": "all",
"provider": null,
"retries": 10,
"wait_for": null
}
},
"stdout": [
"Cisco IOS Software, C2960 Software (C2960-LANLITEK9-M), Version 12.2(52)SE, RELEASE SOFTWARE (fc3)\nBOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(53r)SEY3, RELEASE SOFTWARE (fc1)\nVersion ID : V04\nSwitch Ports Model SW Version SW Image"
],
"stdout_lines": [
[
"Cisco IOS Software, C2960 Software (C2960-LANLITEK9-M), Version 12.2(52)SE, RELEASE SOFTWARE (fc3)",
"BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(53r)SEY3, RELEASE SOFTWARE (fc1)",
"Version ID : V04",
"Switch Ports Model SW Version SW Image"
]
]
}
},
"task": {
"duration": {
"end": "2024-04-01T03:08:27.896416Z",
"start": "2024-04-01T03:08:25.148062Z"
},
"id": "ff523e0a-84a7-e3d6-229a-000000000008",
"name": "run show version on the routers"
}
},
{
"hosts": {
"192.168.1.18": {
"_ansible_no_log": false,
"_ansible_verbose_always": true,
"action": "debug",
"changed": false,
"output.stdout_lines": [
[
"Cisco IOS Software, C2960 Software (C2960-LANLITEK9-M), Version 12.2(52)SE, RELEASE SOFTWARE (fc3)",
"BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(53r)SEY3, RELEASE SOFTWARE (fc1)",
"Version ID : V04",
"Switch Ports Model SW Version SW Image"
]
]
}
},
"task": {
"duration": {
"end": "2024-04-01T03:08:28.359220Z",
"start": "2024-04-01T03:08:27.914296Z"
},
"id": "ff523e0a-84a7-e3d6-229a-000000000009",
"name": "print output"
}
}
]
}
],
"stats": {
"192.168.1.18": {
"changed": 0,
"failures": 0,
"ignored": 0,
"ok": 2,
"rescued": 0,
"skipped": 0,
"unreachable": 0
}
}
}
Hi @mateo08c!
Thank you for opening that issue. I have analyzed what you shared and the error was produced because the stdout_lines returns a slice of slices, while the struct used to handle that output expects a slice of string
"output.stdout_lines": [
[
"Cisco IOS Software, C2960 Software (C2960-LANLITEK9-M), Version 12.2(52)SE, RELEASE SOFTWARE (fc3)",
"BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(53r)SEY3, RELEASE SOFTWARE (fc1)",
"Version ID : V04",
"Switch Ports Model SW Version SW Image"
]
]
That is the struct I referred:
type AnsiblePlaybookJSONResultsPlayTaskHostsItem struct {
Action string `json:"action"`
Changed bool `json:"changed"`
Msg interface{} `json:"msg"`
AnsibleFacts map[string]interface{} `json:"ansible_facts"`
Stdout interface{} `json:"stdout"`
StdoutLines []string `json:"stdout_lines"`
Stderr interface{} `json:"stderr"`
StderrLines []string `json:"stderr_lines"`
Cmd interface{} `json:"cmd"`
Failed bool `json:"failed"`
FailedWhenResult bool `json:"failed_when_result"`
Skipped bool `json:"skipped"`
SkipReason string `json:"skip_reason"`
Unreachable bool `json:"unreachable"`
}
I will adapt the struct to be more flexible when handling the generated output.
I keep you updated.
Thanks again.
The fix is available in https://github.com/apenella/go-ansible/releases/tag/v2.0.0