Zabbix maintenance using Ansible - ansible

I would like to use the zabbix _maintenance module.
But I want to send the host_groups as an extra var so I can put multiple host groups in maintenance.
The problem I faced is that the host_group needs a list of items and I can't understand how to write the role so it will run over a list given to it by the extra var
I tried :
- name: maintenance
zabbix_maintenance:
name: Pause
host_groups:
- "{{ item }}"
with_items:
- { 'zabbix_hosts_groups' }
state: "{{ zabbix_state }}"
server_url: http://zabbix.XXX.com
login_user: YYY
login_password: XXX
minutes: 90
desc: "Paused-for-dep"
and running it:
ansible-playbook -i 'localhost,' --connection=local zabbix-maintenance.yml -e '{"zabbix_hosts_groups":"Test1","Test2"}' -e 'zabbix_state=present

Syntactically correct task definition would be:
- name: maintenance
zabbix_maintenance:
name: Pause
host_groups: "{{ zabbix_hosts_groups }}"
state: "{{ zabbix_state }}"
server_url: http://zabbix.XXX.com
login_user: YYY
login_password: XXX
minutes: 90
desc: "Paused-for-dep"
I don't understand the problem description though. "Jenkins"??? "How to write the role"??? Please at least learn the vocabulary required to ask a question.

I use ansible module zabbix_host. There is an attribute link_templates. But it removes all groups which are linked to your host before.
I have not managed this yet. So now I use this to add common templates, and then handly link required templates in Zabbix GUI.
Check this repo, maybe you'll find some helpful: igogorevi4:Ansible

Related

Ansible - Is it possible to loop over a list of objects in input within a playbook

I am trying to create a playbook which is managing to create some load balancers.
The playbook takes a configuration YAML in input, which is formatted like so:
-----configuration.yml-----
virtual_servers:
- name: "test-1.local"
type: "standard"
vs_port: 443
description: ""
monitor_interval: 30
ssl_flag: true
(omissis)
As you can see, this defines a list of load balancing objects with the relative specifications.
If I want to create for example a monitor instance, which depends on these definitions, I created this task which is defined within a playbook.
-----Playbook snippet-----
...
- name: "Creator | Create new monitor"
include_role:
name: vs-creator
tasks_from: pool_creator
with_items: "{{ virtual_servers }}"
loop_control:
loop_var: monitor_item
...
-----Monitor Task-----
- name: "Set monitor facts - Site 1"
set_fact:
monitor_name: "{{ monitor_item.name }}"
monitor_vs_port: "{{ monitor_item.vs_port }}"
monitor_interval: "{{ monitor_item.monitor_interval}}"
monitor_partition: "{{ hostvars['localhost']['vlan_partition'] | first }}"
...
(omissis)
- name: "Create HTTP monitor - Site 1"
bigip_monitor_http:
state: present
name: "{{ monitor_name }}_{{ monitor_vs_port }}.monitor"
partition: "{{ monitor_partition }}"
interval: "{{ monitor_interval }}"
timeout: "{{ monitor_interval | int * 3 | int + 1 | int }}"
provider:
server: "{{ inventory_hostname}}"
user: "{{ username }}"
password: "{{ password }}"
delegate_to: localhost
when:
- site: 1
- monitor_item.name | regex_search(regex_site_1) != None
...
As you can probably already see, I have a few problems with this code, the main one which I would like to optimize is the following:
The creation of a load balancer (virtual_server) involves multiple tasks (creation of a monitor, pool, etc...), and I would need to treat each list element in the configuration like an object to create, with all the necessary definitions.
I would need to do this for different sites which pertain to our datacenters - for which I use regex_site_1 and site: 1 in order to get the correct one... though I realize that this is not ideal.
The script, as of now, does that, but it's not well-managed I believe, and I'm at a loss on what approach should I take in developing this playbook: I was thinking about looping over the playbook with each element from the configuration list, but apparently, this is not possible, and I'm wondering if there's any way to do this, if possible with an example.
Thanks in advance for any input you might have.
If you can influence input data I advise to turn elements of virtual_servers into hosts.
In this case inventory will look like this:
virtual_servers:
hosts:
test-1.local:
vs_port: 443
description: ""
monitor_interval: 30
ssl_flag: true
And all code code will become a bliss:
- hosts: virtual_servers
tasks:
- name: Doo something
delegate_to: other_host
debug: msg=done
...
Ansible will create all loops for you for free (no need for include_roles or odd loops), and most of things with variables will be very easy. Each host has own set of variable which you just ... use.
And part where 'we are doing configuration on a real host, not this virtual' is done by use of delegate_to.
This is idiomatic Ansible and it's better to follow this way. Every time you have include_role within loop, you for sure made a mistake in designing the inventory.

Yaml code repetition

I have several block of code repeated all over my code, like this:
- name: Retrieve VM information
os_server_facts:
validate_certs: False ### From this line
api_timeout: 300
timeout: 600
auth:
auth_url: "{{ cloudstack_auth_url }}"
username: "{{ cloudstack_login }}"
password: "{{ cloudstack_password }}"
project_name: "{{ cloudstack_project }}"
auth_type: v2password ### To this line
server: "{{ vm_hostname }}"
Inside the same file, I could use anchors, but I don't know how to do to factorize this piece of code in differents files, any ideas ?
If you have some tasks that are used in many places you can always include these in your playbook from a common .yml file using an include.
- include: ../common/tasks/mytasks.yml
However! Ansible really want's you to use roles for this type of common task use, I would consider putting these into a very simple role and using it in your plays with include_role. It's really a better and more salable way to do this.
- name: Include my tasks as a role
include_role:
name: reusedTasks
tasks_from: simple_role

Launch EC2 instances with a Name

I have a playbook that launches n EC2 instances. When launching, it tags them with Env: {{ env }} and ManagedBy: Ansible, but I'd also like to add a name with some semblance of meaning. For me, this is usually something with a format like <env>-<purpose><number> (e.g. dev-web02 or prd-db01).
I'd really like Ansible to do that for me, if at all possible.
I currently have my playbook built out such that {{ exact_count }} instances are verified to exist using the ec2 module. Created instances are then given a name tag using the ec2_tag module:
- name: Instances | Tag each new instance with a name
ec2_tag:
aws_access_key: "{{ awscli.access_key }}"
aws_secret_key: "{{ awscli.secret_key }}"
region: "{{ aws.region }}"
resource: "{{ item.1.id }}"
state: present
tags:
Name: "{{ env_short }}-{{ 'ws%02d' | format(item.0) }}"
with_indexed_items: webservers.instances
This works great, the first time it's ever run. The problem is that it iterates not across all of my instances, but only across those that may've been created during this run of the playbook.
Is there a better way to do this such that new instances are able to detect the sequence and continue it so that on a second run, for example, after I've changed {{ exact_count }} from 1 to 2, the server created by that second run will get a Name value of dev-ws02?
This may be a lot to ask of Ansible and there may be a good reason I haven't found an answer, but sometimes you get pleasantly surprised, so I thought I'd ask.
Empirically, I've figured out that using the tagged_instances property seems to work. This value appears to contain every server that matches the tags, not just any that were just created. At the moment, I can't remember whether the ec2_tag module simply won't overwrite a tag that already exists or if existing tags are updated, but the net result seems to be working out the way I'd like it to work out.
Here is my updated task:
- name: Instances | Tag each new instance with a name
ec2_tag:
aws_access_key: "{{ awscli.access_key }}"
aws_secret_key: "{{ awscli.secret_key }}"
region: "{{ aws.region }}"
resource: "{{ item.1.id }}"
state: present
tags:
# e.g. dev-web03, prd-anz01
Name: "{{ env_short }}-{{ server_type_abbrev }}{{ '%02d' | format(item.0) }}"
with_indexed_items: ec2.tagged_instances

Tag Name from EC2-group in Ansible

This is another question coming from the following post...:
loops over the registered variable to inspect the results in ansible
So basically having:
- name: EC2Group | Creating an EC2 Security Group inside the Mentioned VPC
local_action:
module: ec2_group
name: "{{ item.sg_name }}"
description: "{{ item.sg_description }}"
region: "{{ vpc_region }}" # Change the AWS region here
vpc_id: "{{ vpc.vpc_id }}" # vpc is the resgister name, you can also set it manually
state: present
rules: "{{ item.sg_rules }}"
with_items: ec2_security_groups
register: aws_sg
- name: Tag the security group with a name
local_action:
module: ec2_tag
resource: "{{ item.group_id }}"
region: "{{ vpc_region }}"
state: present
tags:
Name: "{{vpc_name }}-group"
with_items: aws_sg.results
I wonder how is possible to get the TAG NAME
tags:
Name: "{{ item.sg_name }}"
The same value as per the primary name definition on the Security Groups?
local_action:
module: ec2_group
name: "{{ item.sg_name }}"
I am trying to make that possible but I am not sure how to do it. If it's also possible to retrieve that item?
Thanks!
Tags are available after the ec2.py inventory script is run - they always take the value of tag_key_value where 'key' is the name of the tag, and 'value' is the value within that tag. i.e. if you create a tag called 'Application' and give it a value of 'AwesomeApplication' you would get 'tag_Application_AwesomeApplication'.
That said, if you have just created instances and want to run some commands against those new instances, parse the output from the create instance command to get a list of the IP addresses, and add them to a temporary group, and then you can run commands against that group within the same playbook:
...
- name: add hosts to temporary group
add_host: name="{{ item }}" groups=temporarygroup
with_items: parsedipaddresses
- hosts: temporarygroup
tasks:
- name: awesome script to do stuff goes here
...

ansible: using with_items with notify handler

I want to pass a variable to a notification handler, but can't find anywhere be it here on SO, the docs or the issues in the github repo, how to do it. What I'm doing is deploying multiple webapps, and when the code for one of those webapps is changed, it should restart the service for that webapp.
From this SO question, I got this to work, somewhat:
- hosts: localhost
tasks:
- name: "task 1"
shell: "echo {{ item }}"
register: "task_1_output"
with_items: [a,b]
- name: "task 2"
debug:
msg: "{{ item.item }}"
when: item.changed
with_items: task_1_output.results
(Put it in test.yml and run it with ansible-playbook test.yml -c local.)
But this registers the result of the first task and conditionally loops over that in the second task. My problem is that it gets messy when you have two or more tasks that need to notify the second task! For example, restart the web service if either the code was updated or the configuration was changed.
AFAICT, there's no way to pass a variable to a handler. That would cleanly fix it for me. I found some issues on github where other people run into the same problem, and some syntaxes are proposed, but none of them actually work.
Including a sub-playbook won't work either, because using with_items together with include was deprecated.
In my playbooks, I have a site.yml that lists the roles of a group, then in the group_vars for that group I define the list of webapps (including the versions) that should be installed. This seems correct to me, because this way I can use the same playbook for staging and production. But maybe the only solution is to define the role multiple times, and duplicate the list of roles for staging and production.
So what is the wisdom here?
Variables in Ansible are global so there is no reason to pass a variable to handler. If you are trying to make a handler parameterized in a way that you are trying to use a variable in the name of a handler you won't be able to do that in Ansible.
What you can do is create a handler that loops over a list of services easily enough, here is a working example that can be tested locally:
- hosts: localhost
tasks:
- file: >
path=/tmp/{{ item }}
state=directory
register: files_created
with_items:
- one
- two
notify: some_handler
handlers:
- name: "some_handler"
shell: "echo {{ item }} has changed!"
when: item.changed
with_items: files_created.results
I finally solved it by splitting the apps out over multiple instances of the same role. This way, the handler in the role can refer to variables that are defined as role variable.
In site.yml:
- hosts: localhost
roles:
- role: something
name: a
- role: something
name: b
In roles/something/tasks/main.yml:
- name: do something
shell: "echo {{ name }}"
notify: something happened
- name: do something else
shell: "echo {{ name }}"
notify: something happened
In roles/something/handlers/main.yml:
- name: something happened
debug:
msg: "{{ name }}"
Seems a lot less hackish than the first solution!
To update jarv's answer above, Ansible 2.5 replaces with_items with loop. When getting results, item by itself will not work. You will need to explicitly get the name, e.g., item.name.
- hosts: localhost
tasks:
- file: >
path=/tmp/{{ item }}
state=directory
register: files_created
loop:
- one
- two
notify: some_handler
handlers:
- name: "some_handler"
shell: "echo {{ item.name }} has changed!"
when: item.changed
loop: files_created.results
I got mine to work like this - I had to add some curly brackets
tasks:
- name: Aktivieren von Security-, Backport- und Non-Security-Upgrades
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^[^"//"]*"\${distro_id}:\${distro_codename}-{{ item }}";'
line: ' "${distro_id}:${distro_codename}-{{ item }}";'
insertafter: "Unattended-Upgrade::Allowed-Origins {"
state: present
register: aenderung
loop:
- updates
- security
- backports
notify: Auskommentierte Zeilen entfernen
handlers:
- name: Auskommentierte Zeilen entfernen
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^\/\/.*{{ item.item }}";.*'
state: absent
when: item.changed
loop: "{{ aenderung.results }}"

Resources