GithubHelp home page GithubHelp logo

Comments (7)

apenella avatar apenella commented on June 11, 2024

Hi @nguyenphituan
Are you aware if it happens with ansible 5?
I haven't check go-ansible with ansible 6 yet. I would like to discard if it is related to ansible 6.
Thanks

from go-ansible.

apenella avatar apenella commented on June 11, 2024

Hi @nguyenphituan
Which go-ansible version are you using?
I have been testing it with go-ansible 1.1.6 and ansible 6.2.0 (ansible-core 2.13.2) and it seems that is working.

I updated the example ansibleadhoc-simple to use the module shell and to use extra-vars as well. You could find the update below:

ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
	Inventory:  "127.0.0.1,",
	ModuleName: "ansible.builtin.shell",
	Args:       "echo {{ myvar }}",
	ExtraVars:  map[string]interface{}{"myvar": "myvalue"},
}

The command generated by the String method is: ansible all --args 'echo {{ myvar }}' --extra-vars '{"myvar":"myvalue"}' --inventory 127.0.0.1, --module-name ansible.builtin.shell --connection local

The adapted example output is the following one:

❯ go run ansibleadhoc-simple.go 
Command:  ansible all  --args 'echo {{ myvar }}' --extra-vars '{"myvar":"myvalue"}' --inventory 127.0.0.1, --module-name ansible.builtin.shell  --connection local
127.0.0.1 | CHANGED | rc=0 >>
myvalue

When I execute the command manually, it also works:

❯ ansible all  --args 'echo {{ myvar }}' --extra-vars '{"myvar":"myvalue"}' --inventory 127.0.0.1, --module-name ansible.builtin.shell  --connection local

PLAY [Ansible Ad-Hoc] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************

TASK [ansible.builtin.shell] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************
changed: [127.0.0.1]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************************************************************************************************************************************
127.0.0.1                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

You could solve it updating to latest go-ansible version. In case I am not going to the right direction, could you give some example to reproduce it?

Thanks!

from go-ansible.

nguyenphituan avatar nguyenphituan commented on June 11, 2024

I think the problem is not Ansible, it's Go problem since Go create command line and execute it:
Testing enviroment:

go version go1.16.12 linux/amd64

ansible [core 2.11.12]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.6.9 (default, Jun 29 2022, 11:45:57) [GCC 8.4.0]
jinja version = 2.10
libyaml = True

Code:

   ansibleConnectionOptions := &options.AnsibleConnectionOptions{
           Connection: "ansible.netcommon.network_cli",
   }

   ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
           Inventory:  "1.2.3.4" + ",",
           ModuleName: "arista.eos.eos_config",
           Args:       "\"backup=yes backup_options={{ backup_opts }} defaults=true\"",
           ExtraVars:  map[string]interface{}{"backup_opts": map[string]interface{}{"dir_path": "/backup"}, "ansible_user": >"username", "ansible_password": "Password", "ansible_connection": "ansible.netcommon.network_cli", "ansible_network_os": >"eos", "ansible_become": "yes", "ansible_become_method": "enable"},
   }

   adhoc := &adhoc.AnsibleAdhocCmd{
           Pattern:           "all",
           Options:           ansibleAdhocOptions,
           ConnectionOptions: ansibleConnectionOptions,
           StdoutCallback:    "oneline",
   }
   // DEBUG
   command, err := adhoc.Command()
   log.Println("Command to run: ", command)
   err = adhoc.Run(context.TODO())
   if err != nil {
           fmt.Println(err)
   }
   return

Result:

Command to run: [ansible all --args "backup=yes backup_options={{ backup_opts }} defaults=true" --extra-vars >{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_net>work_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}} --inventory >1.2.3.4, --module-name arista.eos.eos_config --connection ansible.netcommon.network_cli]
[DEPRECATION WARNING]: Ansible will require Python 3.8 or newer on the
controller starting with Ansible 2.12. Current version: 3.6.9 (default, Jun 29
2022, 11:45:57) [GCC 8.4.0]. This feature will be removed from ansible-core in
version 2.12. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.
1.2.3.4 | FAILED! => {
"changed": false,
"msg": "Unsupported parameters for (arista.eos.eos_config) module: "backup. Supported parameters include: diff_against, >save_when, provider, before, running_config (config), defaults, match, src, backup, after, intended_config, replace, >diff_ignore_lines, parents, backup_options, lines (commands)."
}
Error during command execution: ansible-playbook error: one or more host failed

Command executed:
/usr/local/bin/ansible all --args "backup=yes backup_options={{ backup_opts }} defaults=true" --extra-vars >{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_net>work_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}} --inventory >1.2.3.4, --module-name arista.eos.eos_config --connection ansible.netcommon.network_cli

Running Ansible command with single quote works as expected.

from go-ansible.

apenella avatar apenella commented on June 11, 2024

@nguyenphituan
I may be wrong, but I suspect that you are using an older go-ansible version.
When I reviewed your output I missed the quotes either on args and extra-vars.
Check you go.mod file in order to know which go-ansible version are you using, and update it to latest version, v1.1.7.

If you check the code, you will see that both arguments are delimited by single quote.
Here you have the args and extra-vars arguments, and those single quotes are not shown on you results.

On the other hand, it is no need to add the double quote when you define Args attribute on AnsibleAdhocOptions. That is already provided by go-ansible.
Take a look at this snipped:

func main() {

	ansibleConnectionOptions := &options.AnsibleConnectionOptions{
		Connection: "local",
	}

	ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
		Inventory:  "127.0.0.1,",
		ModuleName: "debug",
		Args: `msg="
{{ backup_opts }}
{{ ansible_connection }}
{{ ansible_become_method }}
"`,
		ExtraVars: map[string]interface{}{
			"backup_opts":           map[string]interface{}{"dir_path": "/backup"},
			"ansible_user":          "username",
			"ansible_password":      "Password",
			"ansible_connection":    "ansible.netcommon.network_cli",
			"ansible_network_os":    "eos",
			"ansible_become":        "yes",
			"ansible_become_method": "enable"},
	}

	adhoc := &adhoc.AnsibleAdhocCmd{
		Pattern:           "all",
		Options:           ansibleAdhocOptions,
		ConnectionOptions: ansibleConnectionOptions,
	}

	log.Println("Command: ", adhoc)

	err := adhoc.Run(context.TODO())
	if err != nil {
		panic(err)
	}
}

And here you have the output. There you could see that either args and extra-vars are already delimited by single quotes:

❯ go run ansibleadhoc-simple.go
2022/08/24 08:02:21 Command:  ansible all  --args 'msg="
{{ backup_opts }}
{{ ansible_connection }}
{{ ansible_become_method }}
"' --extra-vars '{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_network_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}}' --inventory 127.0.0.1, --module-name debug  --connection local
127.0.0.1 | SUCCESS => {
    "msg": "\n{'dir_path': '/backup'}\nansible.netcommon.network_cli\nenable\n"
}

from go-ansible.

nguyenphituan avatar nguyenphituan commented on June 11, 2024

Go.mod already use version 1.17:

root@ubuntu-18:~/github# cat go.mod
module test
go 1.16
require github.com/apenella/go-ansible v1.1.7 // indirect

I add double quote as a workaround to make it work, it has the same problem as single quote. But i can't find a way to add single quote. IMO converting from json to string function doesn't put single quote at the beginning and in the end of the string so i don't know where it's added:

adhoc pkg:

func (o *AnsibleAdhocOptions) generateExtraVarsCommand() (string, error) {

extraVars, err := common.ObjectToJSONString(o.ExtraVars)
if err != nil {
return "", errors.New("(adhoc::generateExtraVarsCommand)", "Error creationg extra-vars JSON object to string", err)
}
return extraVars, nil
}

common util pkg:

// ObjectToJSONString converts any object to a json string
func ObjectToJSONString(object interface{}) (string, error) {
var jsoned []byte
var err error

jsoned, err = json.Marshal(object)
if err != nil {
return err.Error(), err
}

return string(jsoned), nil
}

from go-ansible.

apenella avatar apenella commented on June 11, 2024

@nguyenphituan
I would like to reproduce in somehow what you found but I need to figure out how to reproduce it before.

Just to summarize what you are facing: Given the following piece of code:

   ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
           Inventory:  "1.2.3.4" + ",",
           ModuleName: "arista.eos.eos_config",
           Args:       "\"backup=yes backup_options={{ backup_opts }} defaults=true\"",
           ExtraVars:  map[string]interface{}{"backup_opts": map[string]interface{}{"dir_path": "/backup"}, "ansible_user": "username", "ansible_password": "Password", "ansible_connection": "ansible.netcommon.network_cli", "ansible_network_os": "eos", "ansible_become": "yes", "ansible_become_method": "enable"},
   }

You expect the following extra-vars outcome when you call the String method (json delimited by quotes):

'{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_network_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}}'

And you receive that one (json without quotes):

{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_network_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}}

Am I right?

As you could see here, extra-vars quotes are added when you convert the command to an string, not when you generates the extra-vars command or when you marshal the interface.

I am not sure if we are going on the right direction, and I as said before, I would like to figure out how to reproduce the issue, then would you mind to execute that piece of code. I expect that it behaves as your original code does.

func main() {

	ansibleConnectionOptions := &options.AnsibleConnectionOptions{
		Connection: "local",
	}

	ansibleAdhocOptions := &adhoc.AnsibleAdhocOptions{
		Inventory:  "127.0.0.1,",
		ModuleName: "debug",
		Args: `msg="
{{ backup_opts }}
{{ ansible_connection }}
{{ ansible_become_method }}
"`,
		ExtraVars: map[string]interface{}{
			"backup_opts":           map[string]interface{}{"dir_path": "/backup"},
			"ansible_user":          "username",
			"ansible_password":      "Password",
			"ansible_connection":    "ansible.netcommon.network_cli",
			"ansible_network_os":    "eos",
			"ansible_become":        "yes",
			"ansible_become_method": "enable"},
	}

	adhoc := &adhoc.AnsibleAdhocCmd{
		Pattern:           "all",
		Options:           ansibleAdhocOptions,
		ConnectionOptions: ansibleConnectionOptions,
	}

	fmt.Println("Command: ", adhoc.String())

	err := adhoc.Run(context.TODO())
	if err != nil {
		panic(err)
	}
}

from go-ansible.

nguyenphituan avatar nguyenphituan commented on June 11, 2024

I got it. Printing adhoc.Command() doesn't have single quote while printing with adhoc.String() does have:

adhoc.string: ansible all --args '"backup=yes backup_options={{ backup_opts }} defaults=true"' --extra-vars >'{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_net>work_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}}' --inventory >1.2.3.4, --module-name arista.eos.eos_config --connection ansible.netcommon.network_cli
adhoc.Command: [ansible all --args "backup=yes backup_options={{ backup_opts }} defaults=true" --extra-vars >{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_net>work_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}} --inventory >1.2.3.4, --module-name arista.eos.eos_config --connection ansible.netcommon.network_cli]

Command from Ansible output doesn't have single quote but i guest executed command has quote:

Error during command execution: ansible-playbook error: one or more host failed

Command executed:
/usr/local/bin/ansible all --args backup=yes backup_options={{ backup_opts }} defaults=true --extra-vars >{"ansible_become":"yes","ansible_become_method":"enable","ansible_connection":"ansible.netcommon.network_cli","ansible_net>work_os":"eos","ansible_password":"Password","ansible_user":"username","backup_opts":{"dir_path":"/backup"}} --inventory >1.2.3.4, --module-name arista.eos.eos_config --connection ansible.netcommon.network_cli

So it's worked as expected since the command was execute without invalid arguments or extra vars incorrect error (I removed double quotes from args). I was confused with printing adhoc.Command() and command reported by Ansible :).

from go-ansible.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.