Ansible

From Omnia
Jump to navigation Jump to search

Ansible

Install

Sample 2.10.7 version:

sudo pip3 uninstall ansible ansible-base ansible-core
sudo pip3 install ansible==2.10.7

OS Version

{{ansible_distribution}} - Debian / Ubuntu
{{ansible_distribution_release}} - buster / focal
{{ansible_distribution_version}} - 10 / 18.04
{{ansible_distribution_major_version}} - 10 / 18

copy

copy - Copies files to remote locations — Ansible Documentation https://docs.ansible.com/ansible/2.6/modules/copy_module.html

- name: example copying file with owner and permissions
  copy:
    src: /srv/myfiles/foo.conf
    dest: /etc/foo.conf
    owner: foo
    group: foo
    mode: 0644
- name: example copying file with owner and permissions
  copy: src=foo.conf dest=/etc/foo.conf

Ansible Misc

~/metricbeat/metricbeat.yml

metricbeat.modules:
- module: system
  metricsets:
    - cpu
    - filesystem
    - memory
    - network
    - process
  enabled: true
  period: 10s
  processes: ['.*']
  cpu_ticks: false
- module: docker
  metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"]
  hosts: ["unix:///var/run/docker.sock"]
  period: 100s
output.elasticsearch:
  hosts: ["test.oeey.com:9200"]
setup.kibana:
  host: "test.oeey.com:8081"

---

Working With Playbooks — Ansible Documentation - https://docs.ansible.com/ansible/latest/user_guide/playbooks.html

Intro to Playbooks — Ansible Documentation - https://docs.ansible.com/ansible/2.5/user_guide/playbooks_intro.html

YAML Syntax — Ansible Documentation - https://docs.ansible.com/ansible/2.5/reference_appendices/YAMLSyntax.html#yaml-syntax

---

Here’s a playbook that contains just one play:

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum:
      name: httpd
      state: latest
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running (and enable it at boot)
    service:
      name: httpd
      state: started
      enabled: yes
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

YAML

See YAML

YAML Syntax — Ansible Documentation - https://docs.ansible.com/ansible/2.5/reference_appendices/YAMLSyntax.html#yaml-syntax

Raspberry Pi

How to Setup the Raspberry Pi 3 Using Ansible | Datahovel - https://datahovel.com/2016/03/20/how-to-setup-the-raspberry-pi-using-ansible/

ansible-playground/raspbian-bootstrap at master · Condla/ansible-playground · GitHub - https://github.com/Condla/ansible-playground/tree/master/raspbian-bootstrap

Automating Raspberry Pi setup with Ansible - http://www.hietala.org/automating-raspberry-pi-setup-with-ansible.html

--

Raspbian Bootstrap

This is simple ansible playbook to setup one or more of your Raspberry Pis running a fresh Raspbian installation on it. I used the imag e from March 2016 available to download from the official website. This playbook bootstraps your Raspberry Pi 3 to be used over your WPA

Wifi network, if you provide a correct SSID and password as a playbook variable. It will additionally install software required to use

Amazon's AWS IoT NodeJS SDK. (http://docs.aws.amazon.com/iot/latest/developerguide/iot-device-sdk-node.html).

After the first time boot of your Raspberry Pi, follow these few steps in order to bootstrap your machine.

  • Install Ansible and Git on your "Controller" machine.
  • Clone this git repository.
  • Configure hostname/IP address in the "hosts" file
  • Unfortunately: Login to Raspi and expand SD card with "sudo raspi-config" -
 This will be automated in the future!
  • Exectute playbook
# Install Ansible and Git on the machine.
sudo apt-get install python-pip git python-dev sshpass
sudo pip install ansible

# Clone this repo:
git clone https://github.com/Condla/ansible-playground.git
cd ansible-playground/raspbian-bootstrap/

# Configure IP address in "hosts" file. If you have more than one
# Raspberry Pi, add more lines and enter details

# Execute playbook
./playbook.yml


Small sample:

files: ansible.cfg files/ hosts playbook.yml README.md templates/

ansible.cfg:

[defaults]
hostfile = ./hosts
inventory = ./hosts

hosts:

[local]
localhost

playbook.yml:

#!/usr/bin/env ansible-playbook
---
- hosts: local
  gather_facts: yes
  connection: local
  vars:

    packages_to_install: [
        build-essential, tree,
        ]

    pip_packages_to_install: [ pip, pySerial ]

  tasks:

    - name: install ubuntu packages
      apt: pkg={{ item }} state=present
      with_items: '{{packages_to_install}}'
      become: yes

    - name: install python modules
      pip: name={{ item }}
      with_items: '{{pip_packages_to_install}}'
      become: yes

---

helloworld-playbook.yml

#!/usr/bin/env ansible-playbook

---
- name: This is a hello-world example
  hosts: local
  tasks:
  - name: Create a file called '/tmp/testfile.txt' with the content 'hello world'.
    copy: content="hello world\n" dest=/tmp/testfile.txt

Ansible – A “hello world” Playbook – Codingbee - https://codingbee.net/tutorials/ansible/ansible-a-hello-world-playbook

To avoid the "no host matching" use:

hosts: localhost

Hello World

Ansible – A “hello world” Playbook – Codingbee - https://codingbee.net/tutorials/ansible/ansible-a-hello-world-playbook

tower-example/helloworld.yml at master · ansible/tower-example · GitHub - https://github.com/ansible/tower-example/blob/master/helloworld.yml

Logging

ansible.cfg:

[defaults]
log_path = /var/log/ansible.log

Via ENV:

export ANSIBLE_LOG_PATH=~/ansible.log

Enable debug:

export ANSIBLE_DEBUG=True

Apt

apt - Manages apt-packages — Ansible Documentatio - https://docs.ansible.com/ansible/latest/modules/apt_module.html

- name: Remove "foo" package
  apt:
    name: foo
    state: absent
- name: Install a list of packages
  apt:
    name: "{{ packages }}"
  vars:
    packages:
    - foo
    - foo-tools

Pip

Ansible Pip Module - Managing Python Packages - Ansible Tutorials - http://www.mydailytutorials.com/ansible-pip-module/

pip - Manages Python library dependencies — Ansible Documentation - https://docs.ansible.com/ansible/2.6/modules/pip_module.html

  tasks:
  - name: Installing NumPy python library using Ansible pip module
    pip:
      name: NumPy
  tasks:
    - name: Update Pip
      pip:
        name: pip
        state: latest
    - name: Specific fabric
      pip:
        name: fabric<2.0
    - name: More Pip packages
      pip:
        name: python-jenkins jira slackclient

-

pip - Ansible: install multiple Python packages on a single session - Stack Overflow https://stackoverflow.com/questions/31396130/ansible-install-multiple-python-packages-on-a-single-session

  - name: "Install Python Packages: {{ python_packages_to_install }}"
    pip: name={{ item }}
    with_items: "{{ python_packages_to_install }}"
    vars:
      python_packages_to_install:
        - fabric<2.0
        - python-jenkins
        - jira
        - slackclient
        - xmodem
        - pySerial
        - numpy

NFS

mount - Control active and configured mount points — Ansible Documentation - https://docs.ansible.com/ansible/2.5/modules/mount_module.html

  tasks:
  - name: nfs-store5 NFS
    mount:
      name: /nfs-store5
      src: nfs-store5:/wbt
      fstype: nfs
      state: mounted

Dry Run

Dry Run: [1]

ansible-playbook --check playbook.yml

Include Playbook

- include: other.yml

And Include at different levels

  Tasks:
  - include tasks.yml

Create Empty File

- name: ensure file exists
  copy:
    content: ""
    dest: /etc/nologin
    force: no
    group: sys
    owner: root
    mode: 0555

This will touch a file each time (yellow update each time) [2]

- name: create fake 'nologin' shell
  file: path=/etc/nologin state=touch owner=root group=sys mode=0555

With command module:

- name: Create file
  command: touch /path/to/file
  args:
    creates: /path/to/file

Remove File

- name: Clear Pi Warnings
  hosts: localhost
  tasks:

  - name: Remove pi password warning
    file:
      state: absent
      path: /etc/profile.d/sshpwd.sh

  - name: Remove Wifi warning
    file:
      state: absent
      path: /etc/profile.d/wifi-country.sh

Don't Fail on Error

- name: Do not count this as a failure
  ansible.builtin.command: /bin/false
  ignore_errors: true

ref: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html

Execute Script

script - Runs a local script on a remote node after transferring it — Ansible Documentation - https://docs.ansible.com/ansible/2.6/modules/script_module.html

# Example from Ansible Playbooks
- script: /some/local/script.sh --some-arguments 1234

# Run a script that creates a file, but only if the file is not yet created
- script: /some/local/create_file.sh --some-arguments 1234
  args:
    creates: /the/created/file.txt

# Run a script that removes a file, but only if the file is not yet removed
- script: /some/local/remove_file.sh --some-arguments 1234
  args:
    removes: /the/removed/file.txt

# Run a script using a executable in a non-system path
- script: /some/local/script
  args:
    executable: /some/remote/executable

# Run a script using a executable in a system path
- script: /some/local/script.py
  args:
    executable: python3

Execute Shell

shell - Execute commands in nodes. — Ansible Documentation - https://docs.ansible.com/ansible/2.5/modules/shell_module.html

- name: Execute the command in remote shell; stdout goes to the specified file on the remote.
  shell: somescript.sh >> somelog.txt

- name: Change the working directory to somedir/ before executing the command.
  shell: somescript.sh >> somelog.txt
  args:
    chdir: somedir/

# You can also use the 'args' form to provide the options.
- name: This command will change the working directory to somedir/ and will only run when somedir/somelog.txt doesn't exist.
  shell: somescript.sh >> somelog.txt
  args:
    chdir: somedir/
    creates: somelog.txt

- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but bash does)
  shell: cat < /tmp/*txt
  args:
    executable: /bin/bash

- name: Run a command using a templated variable (always use quote filter to avoid injection)
  shell: cat {{ myfile|quote }}

# You can use shell to run other executables to perform actions inline
- name: Run expect to wait for a successful PXE boot via out-of-band CIMC
  shell: |
    set timeout 300
    spawn ssh admin@{{ cimc_host }}

    expect "password:"
    send "{{ cimc_password }}\n"

    expect "\n{{ cimc_name }}"
    send "connect host\n"

    expect "pxeboot.n12"
    send "\n"

    exit 0
  args:
    executable: /usr/bin/expect
  delegate_to: localhost

Download File

get_url - Downloads files from HTTP, HTTPS, or FTP to node — Ansible Documentation - https://docs.ansible.com/ansible/2.5/modules/get_url_module.html

- name: Download foo.conf
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    mode: 0440

- name: Download file and force basic auth
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    force_basic_auth: yes

- name: Download file with custom HTTP headers
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    headers: 'key:value,key:value'

- name: Download file with check (sha256)
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    checksum: sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c

- name: Download file with check (md5)
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    checksum: md5:66dffb5228a211e61d6d7ef4a86f5758

- name: Download file from a file path
  get_url:
    url: file:///tmp/afile.txt
    dest: /tmp/afilecopy.txt

Build Program from Source

Using Ansible to Compile NGINX from Sources with Custom Modules - https://medium.com/bigpanda-engineering/using-ansible-to-compile-nginx-from-sources-with-custom-modules-f6e6c6a42493

compile_nginx_from_sources.yml:

---

- name: Compile NGINX from sources
  hosts: webserver
  vars:
    nginx_version: nginx-1.13.4
    nginx_tarball_url: "http://nginx.org/download/{{ nginx_version }}.tar.gz"
    nginx_install_dir: "/tmp/{{ nginx_version }}"
    nginx_sbin_path: "/usr/sbin/nginx"
    nginx_conf_path: "/etc/nginx/nginx.conf"
    nginx_custom_modules: "--with-http_auth_request_module"

  tasks:
  - name: Installing NGINX Dependencies
    become: yes
    apt:
      name: "{{ item }}"
      update_cache: yes
    with_items:
      - libssl-dev
      - zlib1g-dev
      - libpcre3
      - libpcre3-dev
      - unzip

  - name: Downloading NGINX sources
    get_url:
      url: "{{ nginx_tarball_url }}"
      dest: "/tmp/{{ nginx_version }}.tar.gz"
    register: nginx_source

  - name: Unpacking NGINX
    unarchive:
      copy: no
      dest: /tmp/
      src: "{{ nginx_source.dest }}"
    when: nginx_source.changed
    register: nginx_source_unpack

  - name: Create required Nginx dirs
    become: yes
    file:
      path: /etc/nginx
      state: directory
      owner: root
      mode: 0755

  - name: Configuring NGINX source with custom modules
    command: "./configure --sbin-path={{ nginx_sbin_path }} --conf-path={{ nginx_conf_path }} {{ nginx_custom_modules }}"
    args:
      chdir: "{{ nginx_install_dir }}"
    when: nginx_source_unpack|changed
    register: nginx_configure

  - name: Installing NGINX
    become: yes
    shell: make && make install
    args:
      chdir: "{{ nginx_install_dir }}"
    when: nginx_configure|changed

  - name: Creating NGINX conf file
    become: yes
    template:
      src: nginx.conf
      dest: "{{ nginx_conf_path }}"
      owner: "{{ ansible_user }}"
      group: "{{ ansible_user }}"
      mode: 0644

  - name: Installing NGINX init script (service)
    become: yes
    template:
      src: nginx.init
      dest: /etc/init.d/nginx
      owner: root
      group: root
      mode: 0755

  - name: Starting NGINX
    become: yes
    service:
      name: nginx
      state: started

Build tio

tio.yml:

- name: Compile tio from sources
  hosts: localhost
  vars:
    tio_version: v1.30
    tio_install_dir: "/root/.src/tio"
    tio_sbin_path: "/usr/local/bin/tio"

  tasks:
  - name: Git fun
    git:
      name: 'https://github.com/tio/tio.git'
      dest: "{{tio_install_dir}}"
      version: "{{tio_version}}"
    register: tio_git

  - name: Make tio configure
    command: "sh autogen.sh"
    args:
      chdir: "{{ tio_install_dir }}"
      creates: "{{tio_sbin_path}}"
    register: tio_make_configure

  - name: Configuring tio source
    command: "./configure"
    args:
      chdir: "{{ tio_install_dir }}"
    when: tio_make_configure|changed
    register: tio_configure

  - name: Installing tio
    become: yes
    shell: make && make install
    args:
      chdir: "{{ tio_install_dir }}"
    when: tio_configure|changed

Encrypt Files

Create new file:

ansible-vault create --vault-id test@multi_password_file foo.yml

Encrypt existing:

ansible-vault encrypt foo.yml bar.yml baz.yml
ansible-vault encrypt --vault-id project@prompt foo.yml bar.yml baz.yml

View encrypted file:

ansible-vault view foo.yml bar.yml baz.yml

Decrypt file:

ansible-vault decrypt foo.yml bar.yml baz.yml

Always use a password file:

alias ansible='ansible-playbook --vault-id /etc/ansible/password'
alias ansible-playbook='ansible-playbook --vault-id /etc/ansible/password'


ref: [3]

AWX

AWX provides a web-based user interface, REST API, and task engine built on top of Ansible. It is the upstream project for Tower, a commercial derivative of AWX.

https://github.com/ansible/awx

AWX stands for "Ansible WorX" a play on AnsibleWorks.

Ref: [4] [5]

--

AWX in Ansible AWX stands for Ansible WorX

It is found inside this commit https://github.com/ansible/awx/commit/5c6895e6065a81f4483dfb6bc7650706f8866e1e

They used an X instead of ks

ref: https://stackoverflow.com/questions/63509580/ansible-awx-what-awx-stands-for

Galaxy Framework

Galaxy Framework Role Initalize

ansible-galaxy init [role]

Example:

ansible-galaxy init linux-common
`-- linux-common
    |-- README.md
    |-- defaults
    |   `-- main.yml
    |-- files
    |-- handlers
    |   `-- main.yml
    |-- meta
    |   `-- main.yml
    |-- tasks
    |   `-- main.yml
    |-- templates
    |-- tests
    |   |-- inventory
    |   `-- test.yml
    `-- vars
        `-- main.yml

See https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html#collection-init

Sample Ansible Simple Playbook

inventory:

[webservers]
server1
server2

[databases]
server3
server4

playbook.yml:

---
- name: Update web servers
  hosts: webservers
  remote_user: root

  tasks:
  - name: Ensure apache is at the latest version
    ansible.builtin.yum:
      name: httpd
      state: latest

  - name: Write the apache config file
    ansible.builtin.template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf

- name: Update db servers
  hosts: databases
  remote_user: root

  tasks:
  - name: Ensure postgresql is at the latest version
    ansible.builtin.yum:
      name: postgresql
      state: latest

  - name: Ensure that postgresql is started
    ansible.builtin.service:
      name: postgresql
      state: started

Run:

ansible-playbook -i inventory playbook.yml

ref: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html

Sample Ansible Setup

ansible.cfg

inventory/
  systems.ini
  #or
  systems.yml

group_vars/
  group1.yml

host_vars/
  hostname1.yml

playbook1.yml
# or - if do this you will need to modify the roles_path in ansible.cfg
# playbooks/
#   playbook1.yml

roles/
  role1/
    ....
    tasks/
      main.yml

ansible.cfg:

[defaults]
inventory = inventory

inventory/systems: (ini format, but no .ini extension)

[linux]
host1
host2

inventory/systems.yml:

linux:
  hosts:
    host1
    host2

playbook1.yml:

- hosts: [linux]
  roles:
    - linux-common

roles/linux-common/tasks/main.yml:

- import_tasks: update_apt.yml

roles/linux-common/tasks/update_apt.yml:

# Ref: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html

- name: Run an apt-get update [tag - apt_update]
  ansible.builtin.apt:
    update_cache: yes
  tags:
    - apt_update

- name: Run an apt-get upgrade [tag - apt_upgrade]
  ansible.builtin.apt:
    update_cache: yes
    upgrade: yes
  tags:
    - apt_upgrade

Run examples:

ansible-playbook playbook1.yml
ansible-playbook playbook1.yml -t apt_update

See https://docs.ansible.com/ansible/latest/tips_tricks/sample_setup.html

Variable Precedence

Understanding variable precedence

Ansible does apply variable precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed variables override all other variables):

  1. command line values (for example, -u my_user, these are not variables)
  2. role defaults (defined in role/defaults/main.yml) 1
  3. inventory file or script group vars 2
  4. inventory group_vars/all 3
  5. playbook group_vars/all 3
  6. inventory group_vars/* 3
  7. playbook group_vars/* 3
  8. inventory file or script host vars 2
  9. inventory host_vars/* 3
  10. playbook host_vars/* 3
  11. host facts / cached set_facts 4
  12. play vars
  13. play vars_prompt
  14. play vars_files
  15. role vars (defined in role/vars/main.yml)
  16. block vars (only for tasks in block)
  17. task vars (only for the task)
  18. include_vars
  19. set_facts / registered vars
  20. role (and include_role) params
  21. include params
  22. extra vars (for example, -e "user=my_user")(always win precedence)

ref:

Using Variables — Ansible Documentation
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html

keywords

Test