apenella / go-ansible

Go-ansible is a Go package that enables the execution of ansible-playbook or ansible commands directly from Golang applications. It supports a wide range of options for each command, enabling smooth integration of Ansible functionality into your projects.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

Hi @mateo08c!
Although I haven't merged this yet, I wanted to give you a heads up about the following commit with the fix: 1b7af13.