I am running this playbook to install mysql.
File var.yml:
PORT : 3306
USER : mysql
USERID : "{{ PORT }}"
GROUP : mysql
GROUPID : "{{ PORT }}"
SECGROUP : wls
DBUSER : root
DBPASSWD : "{{ DBPASS }}"
GROUPS:
- name: "{{ GROUP }}"
gid: "{{ GROUPID }}"
USERS:
- name : "{{ USER }}"
uid: "{{ USERID }}"
group: "{{ GROUP }}"
groups: "{{ SECGROUP }}"
comment: "{{ USER }}"
playbook.yml:
tasks:
- name: 1. create group
group:
name: "{{ item.name }}"
gid: "{{ item.gid }}"
state: present
with_items:
- "{{ GROUPS }}"
- name: 2. create user account
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
groups: "{{ item.groups }}"
uid: "{{ item.uid }}"
comment: "{{ item.comment }}"
with_items:
- "{{ USERS }}"
When I run it, I have an issue with the second task:
failed : (item={u'comment': u'mysql', u'group': u'mysql', u'name': u'mysql', u'groups': u'wls', u'uid': u'3306'}) => {"ansible_loop_var": "item", "changed": false, "item": {"comment}: "mysql", "group": "mysql", "groups" : "wls", "name": "mysql", "uid": "3306"}, "msg": "Group wls does not exist"}
How can I fix it?
It's because group wls does not exist as error says: "msg": "Group wls does not exist"
You cannot create an user with a non-existent group in its groups. You either need to remove group wls from USERS[0].groups or create group wls. Your task 1. only creates group mysql.
To create both groups in task 1. You can just add group wls to the list:
GROUPS:
- name: "{{ GROUP }}"
gid: "{{ GROUPID }}"
- name: "{{ SECGROUP }}"
gid: "<provide gid here>"
(Note: normally in Ansible you don't have to provide gid to group action and it would chose one, but the way you have written your task 1 requires it).
This will make your task 1 create both mysql and wls groups and also pass task 2.
Related
There is probably simple solution to this i just cant figure it out.
I got the following list in Ansible:
result: [
{
"name": "DC1",
"region": "EU",
"net": "10.10.1.0"
},
{
"name": "DC1",
"region": "EU",
"net": "10.10.2.0"
},
{
"name": "DC2",
"region": "NA",
"net": "10.10.3.0"
},
]
and would like to get the new list in this format:
[
{
"name": "DC1",
"region": "EU",
"net": ["10.10.1.0","10.10.2.0"]
},
{
"name": "DC2",
"region": "NA",
"net": "10.10.3.0"
}
]
In the meantime i have also found the solution for the data format expected by Ansible module
- name: Convert items from the input list
set_fact:
list_conv: "{{ list_conv|default([])+ (item | dict2items )}}"
loop: "{{ result }}"
when: item.name == 'DC1'
- name: Create new list
set_fact:
list_final: "{{ list_final|default([]) + [{ item.key: item.value }] }}"
loop: "{{ list_conv | unique }}"
Output then will:
[
{"name": "DC1"},
{"region": "EU"},
{"net": "10.10.1.0"},
{"net": "10.10.2.0"}
]
There are more options.
The simplest option is converting the addresses to the lists
net_lists: "{{ result|json_query('[].{name: name, net: [net]}') }}"
gives
net_lists:
- name: DC1
net: [10.10.1.0]
- name: DC1
net: [10.10.2.0]
- name: DC2
net: [10.10.3.0]
Then, merge the items by name and append the lists
net_list: "{{ [net_lists, []]|
community.general.lists_mergeby('name', list_merge='append') }}"
gives what you want
net_list:
- name: DC1
net: [10.10.1.0, 10.10.2.0]
- name: DC2
net: [10.10.3.0]
Example of a complete playbook for testing
- hosts: localhost
vars:
result:
- name: DC1
net: 10.10.1.0
- name: DC1
net: 10.10.2.0
- name: DC2
net: 10.10.3.0
net_lists: "{{ result|json_query('[].{name: name, net: [net]}') }}"
net_list: "{{ [net_lists, []]|
community.general.lists_mergeby('name', list_merge='append') }}"
tasks:
- debug:
var: net_lists|to_yaml
- debug:
var: net_list|to_yaml
The next option is grouping the items by name, selecting the keys and values, and creating a dictionary. Declare the variables
net_groups: "{{ result|groupby('name') }}"
net_names: "{{ net_groups|map('first')|list }}"
net_lists: "{{ net_groups|map('last')|
map('map', attribute='net')|list }}"
net_dict: "{{ dict(net_names|zip(net_lists)) }}"
net_list: "{{ net_dict|dict2items(key_name='name', value_name='net') }}"
give
net_groups:
- - DC1
- - {name: DC1, net: 10.10.1.0}
- {name: DC1, net: 10.10.2.0}
- - DC2
- - {name: DC2, net: 10.10.3.0}
net_names: [DC1, DC2]
net_lists:
- [10.10.1.0, 10.10.2.0]
- [10.10.3.0]
net_dict:
DC1: [10.10.1.0, 10.10.2.0]
DC2: [10.10.3.0]
net_list:
- name: DC1
net: [10.10.1.0, 10.10.2.0]
- name: DC2
net: [10.10.3.0]
Example of a complete playbook for testing
- hosts: localhost
vars:
result:
- name: DC1
net: 10.10.1.0
- name: DC1
net: 10.10.2.0
- name: DC2
net: 10.10.3.0
net_groups: "{{ result|groupby('name') }}"
net_names: "{{ net_groups|map('first')|list }}"
net_lists: "{{ net_groups|map('last')|
map('map', attribute='net')|list }}"
net_dict: "{{ dict(net_names|zip(net_lists)) }}"
net_list: "{{ net_dict|dict2items(key_name='name', value_name='net') }}"
tasks:
- debug:
var: net_groups|to_yaml
- debug:
var: net_names|to_yaml
- debug:
var: net_lists|to_yaml
- debug:
var: net_dict|to_yaml
- debug:
var: net_list|to_yaml
Q: "How possibly can I generate such a list from my input data?"
- name: DC1
- net: 10.10.1.0
- net: 10.10.2.0
A: There are no filters to produce this structure. You can use Jinja instead. For example,
net_dict2_str: |
{% for k,v in net_dict.items() %}
{{ k }}:
- name: {{ k }}
{% for n in v %}
- net: {{ n }}
{% endfor %}
{% endfor %}
net_dict2: "{{ net_dict2_str|from_yaml }}"
give
net_dict2:
DC1:
- name: DC1
- net: 10.10.1.0
- net: 10.10.2.0
DC2:
- name: DC2
- net: 10.10.3.0
Fit the template to your needs.
Please help me figure out what I'm wrong with. I'm getting a JSON from Ansible and filtering it, after which I want to save the output and reuse it. But, unfortunately, I get an error that this attribute does not exist. Where did I go wrong?
playbook code:
var:
query_general: "body.results[].{display_name: display_name, subnets: subnets[]}"
- name: parsing query
set_fact:
myvar: "{{ results | json_query(query_general) }}"
register: output
- name: qwe
set_fact:
scndjson: "{{ output.myvar[].display_name }}"
- name: print
debug:
msg: "{{ scndjson }}"
I tried the json_query second case as well, but that didn't work either.
in register:output i have:
[
{
"display_name": "1test",
"subnets": [
{
"gateway_address": "0.0.0.0/25",
"network": "0.0.0.0/25"
}
]
},
{
"display_name": "test",
"subnets": [
{
"gateway_address": "0.0.0.1/25",
"network": "0.0.0.1/25"
}
]
}
]
error:
The task includes an option with an undefined variable.
it can be: output, display_name, etc
UPD:
I corrected the yaml, there are no errors, but the data is not displayed.
tasks:
- name:
nsxt_rest:
hostname: anyhost
username: anyuser
password: anypass
validate_certs: false
method: get
path: /policy/api/v1/infra/segments
register: nsx_results
- debug:
var: nsx_query_general
vars:
nsx_query_general: "{{ nsx_results | json_query('body.results[].{display_name: display_name, subnets: subnets[]}') }}"
register: output
- debug:
var: secondjson
vars:
secondjson: "{{ output|json_query('[].display_name') }}"
Output from nsx_query_general:
{
"nsx_query_general": [
{
"display_name": "test",
"subnets": [
{
"gateway_address": "0.0.0.0/25",
"network": "0.0.0.0/25"
}
]
},
{
"display_name": "1test",
"subnets": [
{
"gateway_address": "0.0.0.1/25",
"network": "0.0.0.1/25"
}
]
}]}
Output from secondjson:
{
"secondjson": "",
"_ansible_verbose_always": true,
"_ansible_no_log": false,
"changed": false
}
Given the registered variable output
output:
- display_name: 1test
subnets:
- gateway_address: 0.0.0.0/25
network: 0.0.0.0/25
- display_name: test
subnets:
- gateway_address: 0.0.0.1/25
network: 0.0.0.1/25
Either use json_query
scndjson: "{{ output|json_query('[].display_name') }}"
, or map attribute
scndjson: "{{ output|map(attribute='display_name')|list }}"
Both declarations create the list
scndjson: [1test, test]
Example of a complete playbook
- hosts: localhost
vars:
output:
- display_name: 1test
subnets:
- gateway_address: 0.0.0.0/25
network: 0.0.0.0/25
- display_name: test
subnets:
- gateway_address: 0.0.0.1/25
network: 0.0.0.1/25
tasks:
- debug:
var: scndjson
vars:
scndjson: "{{ output|json_query('[].display_name') }}"
- debug:
var: scndjson
vars:
scndjson: "{{ output|map(attribute='display_name')|list }}"
I am using an Ansible module (vmware_guest_info) with this code:
- name: Get status of VM post-change
vmware_guest_info:
datacenter: "xxxx"
hostname: "{{ result_item.vcenter }}"
username: "{{ xxxx }}"
password: "{{ ansible_password }}"
name: "{{ result_item.vmname }}"
schema: "vsphere"
validate_certs: no
properties: ["config.hardware.memoryMB", "config.hardware.numCPU", "config.hardware.numCoresPerSocket"]
register: postvmname_vminfo
loop: "{{ result.list }}"
loop_control:
loop_var: result_item
It produces the following JSON:
{
"results": [
{
"ansible_loop_var": "result_item",
"changed": false,
"failed": false,
"instance": {
"config": {
"hardware": {
"memoryMB": 4096,
"numCPU": 6,
"numCoresPerSocket": 1
}
}
},
The command that produces the json is looping though an excel file with these contents:
vmname vcenter
Server1 Vcenter1
Server2 Vcenter1
I need to create a dictionary between vmname and numCPU. How can I do this?
I have tried this:
- set_fact:
resultCPU: "{{ instance.config.hardware.numCPU }}"
with_items:
- "{{ postvmname_vminfo.results | json_query(query) }}"
vars:
query: "[?invocation.module_args.name=='{{ result_item.vmname }}']"
loop: "{{ result.list }}"
loop_control:
loop_var: result_item
I get item is undefined from the above. I believe the issue is with my query. I think what I really need to do is use zip to create a dictionary between the servers(vmname) in my Excel file and the value of numCPU.
Does anyone have any suggestions?
My data is in json file as shown below:
vmdata.json
{
"VMDetails":
[
{
"name": "Owner1",
"vms": [ "vm10", "vm11", "vm12", "vm13" ]
},
{
"name": "Owner2",
"vms": [ "vm20", "vm21", "vm22", "vm23" ]
},
{
"name": "Owner3",
"vms": [ "vm30", "vm31", "vm32", "vm33" ]
}
]
}
I need this json data converted to list of key-value pairs and later used for tagging the VMs on vcenter.
Owner1: vm11
Owner1: vm12
Owner1: vm13
Owner1: vm14
Owner2: vm21
Owner2: vm22
Owner2: vm23
Owner2: vm24
Owner3: vm31
Owner3: vm32
Owner3: vm33
Owner3: vm34
I have assigned the content from the data file to variable using :
vms_tobe_tagged: "{{ lookup ('file', 'vmtags.json')| from_json}}"
I query and get the list of owners using this and it works well:
- set_fact:
Owner: "{{ vms_tobe_tagged| json_query('OwnerDetails[*].name') }}"
- name: Test loop
debug:
msg: "{{ Owner }}"
Is it possible to generate the data using this?
loop: "{{ ['alice', 'bob'] |product(['clientdb', 'employeedb', 'providerdb'])|list }}"
Q: "I need this json data converted to a list of key-value pairs ..."
Owner1: vm11
Owner1: vm12
Owner1: vm13
Owner1: vm14
Owner2: vm21
...
Is it possible to generate the data using 'product' filter?
A: Yes. With the product filter it's possible to create a list that comprises all products. The list of the key-value pairs can be created in the next loop. For example the tasks below
- set_fact:
owner_list: "{{ owner_list|
default([]) +
[item.name]|product(item.vms)|list }}"
loop: "{{ vms_tobe_tagged.VMDetails }}"
- set_fact:
owner: "{{ owner|
default([]) +
[{item.0: item.1}] }}"
loop: "{{ owner_list }}"
- debug:
var: owner
give
"owner": [
{
"Owner1": "vm10"
},
{
"Owner1": "vm11"
},
{
"Owner1": "vm12"
},
{
"Owner1": "vm13"
},
{
"Owner2": "vm20"
...
This helped me. I used json_query, with_subelements to iterate.
- set_fact:
VMOwnerdetails: "{{ vms_tobe_tagged| json_query('VMDetails[*]') }}"
- name: Verbose updates
with_subelements:
- "{{VMOwnerdetails}}"
- vms
debug:
msg: "{{ item.0.name }} : {{ item.1 }}"
I'm trying to get the datastore name for a specific hard disk but I haven't been successful in being able to figuring out choose an entry in the list.
This output is from the ansible module "vmware_guest_disk_facts"
I save this output to a variable called "vm_info".
"guest_disk_facts": {
"0": {
"backing_filename": "stuffstuff",
"capacity_in_kb": 106954752,
"backing_eagerlyscrub": false,
"backing_datastore": "WHAT I REALLY WANT",
"backing_writethrough": false,
"label": "Hard disk 1",
"backing_type": "FlatVer2",
"key": 2000,
"capacity_in_bytes": 109521666048,
"backing_thinprovisioned": false,
"controller_key": 1000,
"summary": "106,954,752 KB",
"unit_number": 0,
"backing_uuid": "info"
},
"1": {
"backing_filename": "stuffstuff",
"capacity_in_kb": 15728640,
"backing_eagerlyscrub": false,
"backing_datastore": "DON'T CARE OF ABOUT THIS ONE",
"backing_writethrough": false,
"label": "Hard disk 2",
"backing_type": "FlatVer2",
"key": 2001,
"capacity_in_bytes": 16106127360,
"backing_thinprovisioned": false,
"controller_key": 1000,
"summary": "15,728,640 KB",
"unit_number": 1,
"backing_uuid": "info"
}
- debug:
msg: "{{ item.guest_disk_facts | json_query(query) }}"
with_items: "{{ vm_info.results }}"
vars:
query: "guest_disk_facts.0.backing_datastore" #done w/ & w/o quotes around 0
I've also tried the following queries and I feel like I've exhausted all options at this point.
query: "guest_disk_facts.[0].backing_datastore"#done w/ & w/o quotes around 0
query: "guest_disk_facts[0].backing_datastore" #done w/ & w/o quotes around 0
query: "guest_disk_facts.*.backing_datastore" #will give me backing_datastore entries for both dictionaries in this case
I would like to just get backing_datastore for one entry in this list of dictionaries
msg: "WHAT I REALLY WANT"
but so far I'm returned with either this error:
Expecting: ['quoted_identifier', 'unquoted_identifier', 'lbracket', 'lbrace'], got: number: Parse error at column 17, token \"0\" (NUMBER), for expression
OR
msg: ""
OR
msg:[
"0",
]
The task below gives "WHAT YOU REALLY WANT"
- debug:
msg: "{{ guest_disk_facts['0'|quote].backing_datastore }}"
The point is quoting the quoted key. The keys '0' and '1' are not valid variables and must be quoted.
The loop below
- debug:
msg: "{{ guest_disk_facts[item|quote].backing_datastore }}"
loop: "{{ guest_disk_facts.keys() }}"
gives
ok: [localhost] => (item=1) =>
msg: DON'T CARE OF ABOUT THIS ONE
ok: [localhost] => (item=0) =>
msg: WHAT I REALLY WANT
Another way to do this -
- name: Get all disks from existing VM
vmware_guest_disk_info:
validate_certs: False
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
datacenter: Asia-Datacenter1
name: VM_8046
register: existing_disk
- name: Get Backing datastore for desired disk id
set_fact:
disk_zero_datastore: "{{ item.value.backing_datastore }}"
with_dict: "{{ existing_disk.guest_disk_info }}"
when: item.key == '0'
- debug:
msg: "{{ disk_zero_datastore }}"
when: disk_zero_datastore is defined