Skip to content

Roles


This playbook is designed to fetch a device's/virtual machine's rendered configuration from NetBox and run an ansible role that is mapped to the NetBox device/virtual machine role.

Playbook AWX / Ansible Automation Platform Template Import

This playbook includes the AWX feature where it imports the playbook as job templates in to AWX / Ansible Automation Platform. The following job templates that will be created:

  • Playbook/Role/Ansible Setup a hosts configured role

  • Playbook/Role/Helm Chart Deploy a Helm Chart

  • Playbook/Role/Kubernetes Manifest Deploy a Kubernetes Manifest

Requirements

  • The inventory must contain the following variables: role and serial which the value of serial must match those within NetBox.

    Tip

    The netbox.netbox.nb_inventory inventory plugin does contain the required variables.

  • NetBox has been setup with the required custom fields.

    Info

    You can use our Ansible Role nofusscomputing.kubernetes.kubernetes_netbox to setup NetBox with the required fields. See Documentation for more info.

  • Rendered configuration contains the required variables for the Ansible Role being used.

    Info

    We provide publicly accessible templates for our roles, should you wish not to create your own.

Usage

This playbook is broken up into different role types, they are:

  • Ansible Role

  • Helm Chart

  • Kubernetes Manifest

Ansible Role

  • job tag ansible_role

This playbook requires the following variables be set.

role_map:                                              # Mandatory, Dict.
  kubernetes_node:                                     # Mandatory, String. Netbox device/Virtual Machine role slug
    name: nofusscomputing.kubernetes.nfc_kubernetes    # Mandatory, String. Name of the Ansible Role that will be run
    tasks_from: main                                   # Optional, String. Name of the task file within the role that will be used.

Environmental variables NETBOX_API and NETBOX_TOKEN, must be set for the url (with protocol) and token to access NetBox.

The remaining required variables that must be set are those that are required by the Ansible Role. These variables must be part of the device/virtual machine rendered configuration.

Helm Chart

On the Ansible Controller, helm must be installed as must the PyYaml Python module.

  • job tag helm_chart

This playbook requires the following variables be set.

role_map:                                                # Mandatory, Dict.
  nginx_ingress:                                         # Mandatory, String. Chart Name
    name: nginx                                          # Mandatory, String. Helm deployment name
    repo: 
      name: nginx                                        # Mandatory, String. Name to give the repository
      url: https://kubernetes.github.io/ingress-nginx    # Mandatory, String. Helm Chart repository URL
    chart: ingress-nginx                                 # Mandatory, String. Name of the chart withing the helm repo.
    version: '4.8.2'                                     # Mandatory, String. Chart version to deploy
    namespace: ingress                                   # Optional, String. Kubernetes namespace to deploy chart to.
    create_namespace: true                               # Optional, String. Create Namespoace?
    release_values:                                      # Optional, Dict. Chart Values.
    # Optional, String. Template filename for chart values
    template_file: "{{ inventory_dir + '/../../templates/helm-chart-values/nginx.yaml.j2'}}"

Tip

AS a helm repository can contain multiple helm charts, keeping the repo dictionary the same across different helm role is recommended so that you don't end up with multiple helm repositories pointing to the same content.

The following environmental variables must be set so that the ansible controller can connect to the kubernetes host:

  • K8S_AUTH_HOST, K8S_AUTH_API_KEY, K8S_AUTH_SSL_CA_CERT and optionally K8S_AUTH_VERIFY_SSL

or

  • K8S_AUTH_KUBECONFIG

The remaining required variables that must be set are those that are required by the template file if specified. These variables must be part of the device/virtual machine rendered configuration or included in the Ansible Inventory.

Kubernetes Manifest

On the Ansible Controller, kubectl must be installed as must the PyYaml and jsonpatch Python module.

  • job tag kubernetes_manifest

This playbook requires the following variables be set.

role_map:                                                # Mandatory, Dict.
  ingress_my_website:                                    # Mandatory, String. Chart Name
    name: The ingress for my website                     # Mandatory, String. Arbitrary name.
    state: present                                       # Optional, String. present or absent
    # Mandatory, String. Template filename containing the kubernetes manifest.
    template: "{{ inventory_dir + '/../../templates/kubernetes/my_website.yaml.j2'}}"

The following environmental variables must be set so that the ansible controller can connect to the kubernetes host:

  • K8S_AUTH_HOST, K8S_AUTH_API_KEY, K8S_AUTH_SSL_CA_CERT and optionally K8S_AUTH_VERIFY_SSL

or

  • K8S_AUTH_KUBECONFIG

The remaining required variables that must be set are those that are required by the template file if specified. These variables must be part of the device/virtual machine rendered configuration or included in the Ansible Inventory.

Workflow

This playbook has the following workflow:

  1. Confirm environmental variables NETBOX_API and NETBOX_TOKEN are set

  2. Fetching of the host (Device / Virtual Machine) ID from NetBox using inventory_hostname and serial as the filter

  3. Fetching of the hosts rendered config

  4. Saves the rendered config to a tmp file

  5. Load tmp file (load variables into hostvars)

  6. Removes tmp file

  7. Variable Validation

    • Role kubernetes_node Confirms required variables are set
  8. Runs the role as specified in role_map

Playbook Definition

role.yaml
---
- name: Host Role Configuration / Deployment
  hosts: |-
    {%- if nfc_pb_host is defined -%}
      {{ nfc_pb_host }}
    {%- else -%}
      all
    {%- endif %}
  become: true
  gather_facts: false


  pre_tasks:


    - name: Confirm Existance of NetBox Connection Variables
      ansible.builtin.assert:
        that:
          - lookup('env', 'NETBOX_API') != ''
          - lookup('env', 'NETBOX_TOKEN') != ''
        msg: "'NETBOX_API' and 'NETBOX_TOKEN' environmental variables must be set"
      tags:
        - always


    - name: Confirm Existance of Required Host Variables
      ansible.builtin.assert:
        that:
          - is_virtual is defined
          - is_virtual != ''
          - role is defined
          - role != ''
        msg: "Missing required variables variables must be set"
      tags:
        - always


    - name: Fetch DCIM ID from NetBox
      ansible.builtin.uri:
        url: |-
          {{ lookup('env', 'NETBOX_API') }}/api/
          {%- if is_virtual -%}
            virtualization/virtual-machines
          {%- else -%}
            dcim/devices
          {%- endif -%}
          /?name={{ inventory_hostname }}{% if serial is defined -%}
            &serial={{ serial }}
          {%- endif %}
        method: GET
        headers:
          Authorization: Token {{ lookup('env', 'NETBOX_TOKEN') }}
        return_content: true
        validate_certs: "{{ lookup('env', 'NETBOX_VALIDATE_CERTS') | default(true) | bool }}"
      check_mode: false
      delegate_to: localhost
      no_log: >    # Contains a secret that logging shows
        {{ nfc_pb_disable_log | default(true) }}
      register: host_details
      tags:
        - always
      vars:
        ansible_connection: local


    - name: Fetch Rendered Config from NetBox
      ansible.builtin.uri:
        url: |-
          {{ lookup('env', 'NETBOX_API') }}/api/
          {%- if is_virtual -%}
            virtualization/virtual-machines
          {%- else -%}
            dcim/devices
          {%- endif -%}
          /{{ host_details.json.results[0].id }}/render-config/
        method: POST
        headers:
          Authorization: Token {{ lookup('env', 'NETBOX_TOKEN') }}
        return_content: true
        validate_certs: "{{ lookup('env', 'NETBOX_VALIDATE_CERTS') | default(true) | bool }}"
      check_mode: false
      delegate_to: localhost
      no_log: >    # Contains a secret that logging shows
        {{ nfc_pb_disable_log | default(true) }}
      register: host_configuration
      tags:
        - always
      vars:
        ansible_connection: local


    - name: TRACE Rendered Config
      ansible.builtin.debug:
        msg: "{{ host_configuration.json.content | from_yaml }}"
      check_mode: true
      tags:
        - always


    - name: Try / Catch
      block:


        - name: Save Vars to temp file so they can be loaded as hostvars
          ansible.builtin.copy:
            content: "{{ host_configuration.json.content | from_yaml | to_nice_json(indent=0) }}"
            dest: "/tmp/vars_{{ inventory_hostname }}.json"
            mode: '777'
          changed_when: false
          check_mode: false
          delegate_to: localhost
          tags:
            - always
          vars:
            ansible_connection: local


        - name: Load Vars as hostvars
          ansible.builtin.include_vars:
            file: "/tmp/vars_{{ inventory_hostname }}.json"
          check_mode: false
          delegate_to: localhost
          tags:
            - always
          vars:
            ansible_connection: local


      always:


        - name: Clean tmp var files
          ansible.builtin.file:
            path: "/tmp/vars_{{ inventory_hostname }}.json"
            state: absent
          changed_when: false
          check_mode: false
          delegate_to: localhost
          tags:
            - always
          vars:
            ansible_connection: local


    - name: Role Validation
      ansible.builtin.include_tasks:
        file: tasks/role/validation.yaml
      tags:
        - always


  tasks:

    - name: TRACE
      ansible.builtin.debug:
        msg: "{{ role }}"
      check_mode: false
      tags:
        - always


    - name: "Ansible Role - {{ role_map[role].name }}"
      ansible.builtin.include_role:
        name: "{{ role_map[role].name }}"
        tasks_from: "{{ role_map[role].tasks_from | default(omit) }}"
      tags:
        - never
        - ansible_role


    - name: Confirm Existance of Kubernetes Connection Variables
      ansible.builtin.assert:
        that:
          - |
            (
              lookup('env', 'K8S_AUTH_HOST') != ''
                and
              lookup('env', 'K8S_AUTH_API_KEY') != ''
                and
              lookup('env', 'K8S_AUTH_SSL_CA_CERT') != ''
            ) or
            (
              lookup('env', 'K8S_AUTH_KUBECONFIG') != ''
            )
        msg: "Missing Helm Chart/Kubernetes required environmental variables"
      tags:
        - never
        - helm_chart
        - kubernetes_manifest


    - name: Confirm Existance of Required Helm Chart Variables
      ansible.builtin.assert:
        that:
          - chart is defined
          - chart != ''
        msg: "Missing helm chart required variables"
      tags:
        - never
        - helm_chart


    - name: "Add Helm Chart Repository - {{ role_map[chart].repo.name }}"
      kubernetes.core.helm_repository:
        name: "{{ role_map[chart].repo.name }}"
        repo_url: "{{ role_map[chart].repo.url }}"
      tags:
        - never
        - helm_chart


    - name: "Deploy Helm Chart - {{ role_map[chart].name }}"
      kubernetes.core.helm:
        name: "{{ role_map[chart].name }}"
        chart_ref: "{{ role_map[chart].repo.name }}/{{ role_map[chart].chart }}"
        chart_version: "{{ role_map[chart].version }}"
        release_values: |
          {{ lookup('template', role_map[chart].template_file) | default(role_map[chart].release_values) | default(omit) }}
        create_namespace: "{{ role_map[chart].create_namespace | default(omit) | bool }}"
        namespace: "{{ role_map[chart].namespace | default(omit) }}"
        wait: false
        state: "{{ role_map[chart].state | default('present') }}"
        skip_crds: false
      delay: 5
      delegate_to: localhost
      diff: true
      retries: 3
      tags:
        - never
        - helm_chart
      vars:
        ansible_connection: local


    - name: Confirm Existance of Required Kubernetes Variables
      ansible.builtin.assert:
        that:
          - manifest is defined
          - manifest != ''
        msg: "Missing Kubernetes required variables"
      tags:
        - never
        - kubernetes_manifest


    - name: Deploy Kubernetes Manifest - {{ role_map[manifest].name }}"
      kubernetes.core.k8s:
        apply: true
        template: "{{ role_map[manifest].template }}"
        server_side_apply:
          field_manager: ansible
          force_conflicts: true
        state: "{{ role_map[manifest].state | default(present) }}"
      delay: 5
      delegate_to: localhost
      diff: true
      retries: 3
      tags:
        - never
        - kubernetes_manifest
      vars:
        ansible_connection: local


  vars:

    nfc_pb_awx_tower_template:

      - name: "Playbook/Role/Ansible"
        ask_tags_on_launch: false
        ask_inventory_on_launch: true
        ask_credential_on_launch: true
        ask_limit_on_launch: true
        description: Run an Ansible Role against a host.
        execution_environment: "No Fuss Computing EE"
        job_type: "check"
        job_tags: ansible_role
        labels:
          - initial
          - onboarding
          - role
          - soe
        use_fact_cache: true

      - name: "Playbook/Role/Helm Chart"
        ask_tags_on_launch: false
        ask_inventory_on_launch: true
        ask_credential_on_launch: true
        ask_limit_on_launch: true
        description: Deploy a Helm Chart.
        execution_environment: "No Fuss Computing EE"
        job_type: "check"
        job_tags: helm_chart
        labels:
          - chart
          - helm
          - initial
          - kubernetes
          - onboarding
          - role
          - soe
        use_fact_cache: true

      - name: "Playbook/Role/Kubernetes Manifest"
        ask_tags_on_launch: false
        ask_inventory_on_launch: true
        ask_credential_on_launch: true
        ask_limit_on_launch: true
        description: Deploy a Kubernetes Manifest.
        execution_environment: "No Fuss Computing EE"
        job_type: "check"
        job_tags: kubernetes_manifest
        labels:
          - initial
          - kubernetes
          - manifest
          - onboarding
          - role
          - soe
        use_fact_cache: true

About:

This page forms part of our Project Ansible Playbooks.

Page Metadata
Version: ToDo: place files short git commit here
Date Created: 2024-04-24
Date Edited: 2024-04-24

Contribution:

Would You like to contribute to our Ansible Playbooks project? You can assist in the following ways:

 

ToDo: Add the page list of contributors