Most Python expressions and filters are valid in YAML playbooks since lists and dictionaries work the same, and ansible is built on Python.
Configuring A Fork describes how to add the upstream parent remote to my local fork.
Clone my fork to local and list remotes
$ git clone {git-server}/MY_ACCOUNT/MY_REPOSITORY.git
$ git remote -v
Add a new remote pointing to upstream source of my fork, then list remotes.
$ git remote add upstream {git-server}/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
$ git remote -v
If you need to update which commit is associated with a tag, you add the tag again with the -f
option to force git to update it if it already exists. If your repository is associated with a remote, you then need to push the tag update to the remote with the -f
force option.
$ git tag -f -a -m "tag message" "tag"
$ git push -f --tags
This is particularly useful if you use releases in GitHub / GitLab. When you create a release, a corresponding tag is created and associated with most recent commit in the master branch. Any future commits to the master branch will be ahead of the commit associated with the release tag. If you want those newer commits to be included in the release, you must update the commit associated with the release tag.
Assume you create a release v1.0 for your project on GitHub / GitLab, which in turn creates a corresponding tag v1.0 associated with the newest commit to your master branch. If you make new commits to the master branch and want them included in release v1.0, you need to update the commit associated with the v1.0 tag. To accomplish this you may use commands similat to this:
$ git tag -f -a -m "add more to the CHANGELOG for v1.0" "v1.0"
$ git push -f --tags
This would force an update to the v1.0 tag to associate with the newest commit, and the force that update on the remote.
Syncing A Fork describes how to sync upstream commits into my fork.
$ git switch master # switch to master branch
$ git fetch upstream # fetch upstream to local
$ git merge upstream/master # merge upstream into master
$ git push # push to my fork on github
This describes how to use the value of a variable as a key into a structured dictionary to extract values. The concept would be that the variable’s value would be passed into the playbook at run time. In Ansible Tower / AWX, a multiple choice survey can restrict selection to known values. For a more detailed example look at server-specs.yml
# virtual machine resource profiles
# structured data complex dictionary
#
# vm_spec['vm_small' ].cpu, .ram
# vm_spec['vm_medium'].cpu, .ram
# vm_spec['vm_large' ].cpu, .ram
#
# vm_size: vm_small
# vm_spec[vm_size].cpu, .ram
vm_spec:
t2small: { cpu: 1, ram: 2 }
t2medium: { cpu: 2, ram: 4 }
t2large: { cpu: 4, ram: 8 }
t2xlarge: { cpu: 8, ram: 16 }
t2x2large: { cpu: 16, ram: 32 }
# guaranteed default value
vm_size: t2small
# create a list of keys for vm_spec dictionary
vm_keys: "{{ vm_spec.keys() | list }}"
Building on this you can test whether a value is in a list.
tasks:
fail: msg="Invalid VM size {{ vm_size }}"
when: vm_size not in vm_keys
There are times when you need to create structured data in real-time. This is useful in Ansible Tower workflows where upstream templates need to pass per-host information to downstream templates in the workflow. With the help from other online articles I figured out this solution.
- name: Create and Add items to dictionary
set_stats:
data:
my_dict: "{{ my_dict | default({}) | combine ({ item.key : item.value }) }}"
with_items:
- { "key": "{{ inventory_hostname_short }}" , "value": {
"var_a" : "{{ var_a_val }}",
"var_b" : "{{ var_b_val }}",
"var_c" : "{{ var_c_val }}"
}
}
This results in a dictionary that is passed back to ansible tower as an artifact. Downstream templates in the workflow will receive it in extra_vars.
my_dict:
host1:
var_a: "host1_var_a_val"
var_b: "host1_var_b_val"
var_c: "host1_var_c_val"
host2:
var_a: "host2_var_a_val"
var_b: "host2_var_b_val"
var_c: "host2_var_c_val"
hostN:
var_a: "host3_var_a_val"
var_b: "host3_var_b_val"
var_c: "host3_var_c_val"
Downstream templates can access this data as follows:
my_dict[inventory_hostname_short].var_a
my_dict[inventory_hostname_short].var_b
my_dict[inventory_hostname_short].var_c
Strings in Ansible are strings in Python which are lists of characters. Lists can be concatenated using the "+" operating.
var1: "one"
var2: "two"
var3: "three"
var4: "{{ var1 + var2 + var3 }}"
var5: "{{ var1 + ' for the money' }}"
The value of var4 is "onetwothree". The value of var5 is "one for the money".
You can split strings with a delimiter.
string: "this is a string"
{{ string.split }} # yields "this", "is", "a", "string"
will split on the spaces by default and yield "this", "is", "a", "string".
address: 192.168.100.10
{{ address.split('.') }} # yields "192", "160", "100", "10"
You can split strings with a delimiter and select a specific items from the resulting list.
address: 192.168.100.10
{{ address.split('.')[0] }} # yields "192"
{{ address.split('.')[2] }} # yields "100"
{{ address.split('.')[-1] }} # yields "10"
And you can use splitext to split a filename on dot to get the basename.
filename: basename.iso
{{ address | splitext }} # yields "basename"
You can extract a "substring" using list notation since strings are lists of characters. Remember that lists start with index 0. Substring extract would be specified by index of starting position, a colon, and the number of list items to extract.
string: "onetwothree"
{{ string[0:3] }} # yields "one"
{{ string[3:3] }} # yields "two"
{{ string[6:5] }} # yields "three"
{{ string[4:1] }} # yields "w"
This article Adding strings to an array in Ansible provides an example of how to build a list in a loop.
---
- hosts: localhost
gather_facts: no
tasks:
- name: Initialize an empty list for our strings
set_fact:
my_strings: []
- name: Setup a string variable
set_fact:
my_name: "Max"
- name: Append string to list
set_fact:
my_strings: "{{ my_strings + [ my_name ] }}"
- debug: var=my_strings
- name: Append another item to the list
set_fact:
my_strings: "{{ my_strings + [ 'Power' ] }}"
- debug: var=my_strings
You can loop through multiple lists in parallel using "with_together". See with_together.yml. The example below shows two lists and references them as item.0 and item.1. If you have more lists, reference them as item.3, item.4, etc.
vms_list:[
{ name: vm1, os: redhat7, fs: general, size: vm_small },
{ name: vm2, os: redhat7, fs: web. , size: vm_small },
{ name: vm3, os: redhat7, fs: oracle , size: vm_large }
]
mac_addr: [
"00:00:00:00:00:00",
"00:00:00:00:00:00",
"00:00:00:00:00:00"
]
# 'with_together' syncs two lists into a common list
# [ (a,b) (1,2) ] becomes [ (a,1) (b,2) ]
# item.0 is first item in resulting list (even a list itself)
# item.1 is second item in resulting list (even a list itself)
#
# loop to display vm names, mac addresses
debug:
msg: VM "{{ item.0.name }}" has MAC address is "{{ item.1 }}"
with_together:
- "{{ vms_list }}"
- "{{ mac_addr }}"
Taken from Ansible Docs Playbooks Conditionals.
when: (ansible_facts['distribution'] == "CentOS" or ansible_facts['distribution'] == "RedHat")
when: (ansible_facts['distribution'] == "Debian" or ansible_facts['distribution'] == "Ubuntu")
when: (ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == "Debian")
when: (ansible_facts['distribution'] == "RedHat" and ansible_facts['distribution_major_version'] == "7")
Read about Python strings to learn more about Ansible strings.
Read the Ansible Variables doc for more info on variable references.
This show how to create diagrams using markdown syntax with the Mermaid language.
%% graphs can be LR, RL, TB, BT
graph LR
%% node styles
classDef fuscia fill:#fbf,stroke:#e6e,stroke-width:1.5px
classDef green fill:#9e9,stroke:#0a0,stroke-width:1.5px
classDef blue fill:#ddf,stroke:#88f,stroke-width:1.5px
classDef red fill:#fbb,stroke:#f11,stroke-width:1.5px
%% subgraph styles
style sub1 fill:#9e9,stroke:#0a0,stroke-width:1.5px
style sub2 fill:#ddf,stroke:#66f,stroke-width:1.5px
style sub3 fill:#fbb,stroke:#f33,stroke-width:1.5px
%% define some nodes
a(Actor):::red
b(Block):::fuscia
c(Computer):::green
%% define some subgraphs
subgraph sub1[Subgraph 1]
a --> b
end
subgraph sub2[Subgraph 2]
b --> c
c --> d
subgraph sub3[Subgraph 3]
d[(Database)]:::blue
end
end