Comments (7)
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.
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.
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.
@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.
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 errorjsoned, err = json.Marshal(object)
if err != nil {
return err.Error(), err
}return string(jsoned), nil
}
from go-ansible.
@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.
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)
- How can I modify VerboseFlag HOT 2
- How can I run the example "ansibleplaybook-walk-through-json-output" HOT 6
- Create a container executor HOT 2
- Extra vars issue in playbooks HOT 2
- Feature Request: GO:Embed HOT 12
- real time output HOT 5
- Generate vaulted extra-vars
- Change the Executor signature to 'Execute(ctx context.Context, command []string, options ...ExecuteOptions)' HOT 1
- Ansible Configuration Support HOT 6
- SSH StrictHostKeyChecking HOT 3
- [Question] Can we use alias for inventory? HOT 3
- execute.WithEnvVar is not working HOT 4
- Suggestion for a Feature to Execute Inventory-Related Commands HOT 3
- Implementing support for `go-embed-python` HOT 9
- Example for winrm connection configuration HOT 2
- Many ssh <defunct> then using library. HOT 5
- How to properly provide multiple ssh extra args HOT 3
- cannot use go get v2 HOT 3
- Can I embed playbook and inventory file to binary after build HOT 4
- extra vars not being set HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-ansible.