Merge pull request #17 from jasonpagetas/playbooks

This commit is contained in:
Jon
2024-08-19 17:12:49 +09:30
committed by GitHub
8 changed files with 574 additions and 1 deletions

View File

@ -1 +1,8 @@
galaxy.yml galaxy[version-incorrect]
galaxy.yml galaxy[version-incorrect]
# N/A as the play runs on the ansible controller and should only run once.
playbooks/teams.yaml run-once[task]
# N/A as the play runs on the ansible controller using permissions of executing user.
playbooks/inventory.yaml risky-file-permissions

View File

@ -0,0 +1,13 @@
---
title: Playbooks
description: Playbooks as part of No Fuss Computings Companion Ansible Collection, Centurion
date: 2024-08-18
template: project.html
about: https://github.com/nofusscomputing/ansible_collection_centurion
---
Available playbooks include:
- [Inventory](./inventory.md)
- [Teams](./teams.md)

View File

@ -0,0 +1,33 @@
---
title: Inventory
description: Ansible Playbook to inventroy devices and publish to Centurion ERP
date: 2024-08-19
template: project.html
about: https://github.com/nofusscomputing/ansible_collection_centurion
---
The inventory playbook has been created to inventory devices and to publish the collected inventory to Centurion ERP. The inventory includes details of all software packages installed on the host machine as well as some details regarding the host machine such as UUID and serial number.
The inventory playbook includes the [AWX Feature](../../../playbooks/awx.md) to import the playbook as a job template in AWX / Ansible Automation Platform.
The following job template will be created:
* **Centurion/ITAM/Inventory** Inventory host machines and publish to Centurion ERP
On import to AWX / Ansible Automation Platform a credential type will also be created, 'Collection/No Fuss Computing/Centurion/API' that can be used to supply the required secrets and Centurion host.
!!! warning
The inventory playbook currently has an issue relating to gathering software starting with L. This issue has been reported and is being worked on
[github issue 19](https://github.com/nofusscomputing/ansible_collection_centurion/issues/19)
## Play workflow
The inventory playbook conducts the follwoing tasks:
- Gathers host information
- Gathers sofware information
- Uploads the inventory report to Centurion ERP
- Cleans any leftover files used to create the reports

View File

@ -0,0 +1,68 @@
---
title: Teams
description: Ansible Playbook for Creating and patching of Centurion ERP teams, including permissions.
date: 2024-08-18
template: project.html
about: https://github.com/nofusscomputing/ansible_collection_centurion
---
The teams playbook has been created for the purpose of creating Centurion ERP teams. It allows teams to be defined as configuration as code which allows standardisation of teams and permissions within an organisation. With this playbook it is possible to create every team within an organisation and define the permissions and notes that are to be applied to that team.
The teams playbook includes the [AWX Feature](../../../playbooks/awx.md) to import the playbook as a job template in AWX / Ansible Automation Platform.
The following job template will be created:
* **Centurion/Access/Teams** Creation and patching of teams and permissions
!!! info
The playbook is able to work with the [inventory plugin](../plugins/index.md) that is included in this collection.
## Play workflow
The teams playbook gathers information regarding centurion organisations from the ansible inventory. Using this information the play is designed to create new teams, patch permissions and patch notes. The workflow for the playbook is as follows
- Fetch all organisations from Centurion ERP
- Fetch all existing teams within each organisation from Centurion ERP
- Fetch any teams to be created from inventory
- Create new teams
- Patch all teams with required permissions
- Patch all teams with required notes
## Configuration
The teams playbook uses variables that are gathered from inventory. The expected structure of the inventory file is:
```yaml
centurion_erp:
teams:
- name: "organisation name"
teams:
- name: "team-name"
permissions: []
notes: "permissions must be a list"
```
!!! tip "common teams"
Common teams can be created by using yaml anchors. This is useful when multiple organisations require a common team and permissions to be set.
```yaml
centurion_erp:
common_teams:
team_name: &team-name "team_name"
team_permissions: &team-name-permissions []
team_name_notes: &team-name-notes "team_notes"
teams:
- name: "organisation name"
teams:
- name: *team-name
permissions: *team-name-permissions
notes: *team-name-notes
```

View File

View File

@ -29,6 +29,14 @@ nav:
- projects/ansible/collection/centurion/index.md
- Playbooks:
- projects/ansible/collection/centurion/playbooks/index.md
- projects/ansible/collection/centurion/playbooks/inventory.md
- projects/ansible/collection/centurion/playbooks/teams.md
- Plugins:
- projects/ansible/collection/centurion/plugins/index.md

176
playbooks/inventory.yaml Normal file
View File

@ -0,0 +1,176 @@
- name: Inventory
hosts: |-
{%- if nfc_pb_host is defined -%}
{{ nfc_pb_host }}
{%- else -%}
all
{%- endif %}
become: true
tasks:
- name: Inventory host
block:
- name: Fetch Packages
ansible.builtin.package_facts:
manager: auto
become: true
- name: Inventory Details
ansible.builtin.set_fact:
details: {
"name": "{{ ansible_hostname }}",
"serial_number": "{{ ansible_product_serial }}",
"uuid": "{{ ansible_product_uuid }}"
}
- name: Inventory Software [a-k]
ansible.builtin.set_fact:
cacheable: false
software: "{{ software | default([]) + [{
'name': package.value[0].name,
'category': package.value[0].category | default(''),
'version': package.value[0].version
}] }}"
# no_log: true
loop: "{{ ansible_facts.packages | dict2items() }}"
loop_control:
loop_var: package
label: "{{ package.key }}"
when: >
package.value[0].name | regex_search("^[a-k]")
# https://github.com/nofusscomputing/ansible_collection_centurion/issues/19
# This task has been commented out due to the above issue
# - name: Inventory Software [l]
# ansible.builtin.set_fact:
# cacheable: false
# software: "{{ software | default([]) + [{
# 'name': package.value[0].name,
# 'category': package.value[0].category | default(''),
# 'version': package.value[0].version
# }] }}"
# # no_log: true
# loop: "{{ ansible_facts.packages | dict2items() }}"
# loop_control:
# loop_var: package
# label: "{{ package.key }}"
# when: >
# package.value[0].name | regex_search("^[l]")
- name: Inventory Software [m-z]
ansible.builtin.set_fact:
cacheable: false
software: "{{ software | default([]) + [{
'name': package.value[0].name,
'category': package.value[0].category | default(''),
'version': package.value[0].version
}] }}"
# no_log: true
loop: "{{ ansible_facts.packages | dict2items() }}"
loop_control:
loop_var: package
label: "{{ package.key }}"
when: >
package.value[0].name | regex_search("^[m-z]")
- name: Inventory Document
ansible.builtin.set_fact:
report: {
"details": "{{ details }}",
"os": {
"name": "{{ ansible_distribution | lower }}",
"version": "{{ ansible_distribution_version }}",
"version_major": "{{ ansible_distribution_major_version }}"
},
"software": "{{ software }}"
}
- name: Save report
ansible.builtin.copy:
content: "{{ report | to_nice_json }}"
dest: "/tmp/{{ ansible_hostname }}.json"
- name: Upload inventory - {{ ansible_hostname }}
ansible.builtin.uri:
url: |-
{{ lookup('env', 'ITSM_API') }}/api/device/inventory
method: POST
body_format: json
src: "/tmp/{{ ansible_hostname }}.json"
remote_src: true
headers:
Authorization: Token {{ lookup('env', 'ITSM_TOKEN') }}
validate_certs: "{{ lookup('env', 'ITSM_VALIDATE_CERTS') | default(true) | bool }}"
timeout: 300
status_code:
- 200
- 201
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
always:
- name: Remove report
ansible.builtin.file:
path: "/tmp/{{ ansible_hostname }}.json"
state: absent
vars:
nfc_pb_awx_tower_template:
- name: "Centurion/ITAM/Inventory"
ask_tags_on_launch: false
ask_inventory_on_launch: true
ask_credential_on_launch: true
ask_limit_on_launch: true
concurrent_jobs_enabled: true
description: Inventory host machines and publish to Centurion ERP
execution_environment: "No Fuss Computing EE"
job_type: "run"
# job_tags: complete
labels:
- centurion
- inventory
- itam
- itsm
use_fact_cache: true
credential_types:
- name: 'Collection/No Fuss Computing/Centurion/API'
description: |
Credentials for authentication to Centurion ERP
inputs: |
fields:
- id: centurion_url
type: string
label: centurion url
help_text: Ensure that `https://` is prefixed to url
- id: centurion_token
type: string
label: api token
secret: true
- id: centurion_validate_certs
type: boolean
label: Validate SSL Certificate
required:
- centurion_api
- centurion_token
injectors: >
env:
CENTURION_API: '{{ centurion_url }}'
CENTURION_TOKEN: '{{ centurion_token }}'
CENTURION_VALIDATE_CERTS: '{{ centurion_validate_certs | default(true) }}'

268
playbooks/teams.yaml Normal file
View File

@ -0,0 +1,268 @@
---
- name: Centurion ERP Teams Setup
hosts: |-
{%- if nfc_pb_host is defined -%}
{{ nfc_pb_host }}
{%- else -%}
all
{%- endif %}
become: false
gather_facts: false
connection: local # Play uses HTTP requests ONLY!
tasks:
- name: Confirm required vars exist
ansible.builtin.assert:
that:
- centurion_erp.teams is defined
- |
centurion_erp.teams is not mapping
and
centurion_erp.teams is iterable
and
centurion_erp.teams is not string
msg: "Missing required variable or it's of the incorrect type[list]"
run_once: true
delegate_to: localhost
- name: Collect organizations from centurion ERP
ansible.builtin.uri:
url: |-
{{ lookup('env', 'CENTURION_API') }}/api/organization/
method: GET
body_format: json
headers:
authorization: Token {{ lookup('env', 'CENTURION_TOKEN') }}
validate_certs: "{{ lookup('env', 'VALIDATE_CENTURION_CERTS') | default(true) | bool }}"
return_content: true
status_code:
- 200
register: api_get_organizations
run_once: true
delegate_to: localhost
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Collect teams from centurion ERP
ansible.builtin.uri:
url: "{{ item }}"
method: GET
body_format: json
headers:
authorization: Token {{ lookup('env', 'CENTURION_TOKEN') }}
validate_certs: "{{ lookup('env', 'VALIDATE_CENTURION_CERTS') | default(true) | bool }}"
return_content: true
status_code:
- 200
loop: "{{ api_get_organizations.json.results | map(attribute='url') | list }}"
register: api_get_permissions
run_once: true
delegate_to: localhost
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Create list of Teams
ansible.builtin.set_fact:
team_permissions: |
[
{% for config_organisation in centurion_erp.teams %}
{% set ns = namespace(added_teams = []) %}
{% for config_team in config_organisation.teams %}
{% for organization in api_get_permissions.results %}
{% if organization.json.name == config_organisation.name %}
{% for team in organization.json.teams %}
{% if team.team_name == config_team.name %}
{
"organization_id": "{{ organization.json.id }}",
"team_name": "{{ team.team_name }}",
"url": "{{ team.url }}",
"notes": "{{ config_team.notes }}",
"permissions":
{{ config_team.permissions }}
},
{% set ns.added_teams = ns.added_teams + [ config_team.name ] %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% if config_team.name not in ns.added_teams %}
{
"organization_id":
{% for organization in api_get_permissions.results %}
{% if organization.json.name == config_organisation.name %}
"{{ organization.json.id }}",
{% endif %}
{% endfor %}
"team_name": "{{ config_team.name }}",
"notes": "{{ config_team.notes }}",
"permissions":
{{ config_team.permissions }}
},
{% set ns.added_teams = ns.added_teams + [ config_team.name ] %}
{% endif %}
{% endfor %}
{% endfor %}
]
delegate_to: localhost
run_once: true
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Create new teams in centurion_ERP
ansible.builtin.uri:
url: |-
{{ lookup('env', 'CENTURION_API') }}/api/organization/{{ item.organization_id }}/team
method: POST
body_format: json
body: |-
{
"team_name": "{{ item.team_name }}"
}
headers:
Authorization: Token {{ lookup('env', 'CENTURION_TOKEN') }}
validate_certs: "{{ lookup('env', 'VALIDATE_CENTURION_CERTS') | default(true) | bool }}"
status_code:
- 201
when: >
item.url is not defined
loop: "{{ team_permissions | list }}"
register: api_post_teams
delegate_to: localhost
run_once: true
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Update permissions to include newly created teams
ansible.builtin.set_fact:
team_permissions: |
[
{% for team in team_permissions %}
{
"organization_id": "{{ team.organization_id }}",
"team_name": "{{ team.team_name }}",
"notes": "{{ team.notes }}",
"permissions":
{{ team.permissions }},
"url":
{% if team.url is defined %}
"{{ team.url }}",
{% elif team.url is not defined %}
{% for api_values in api_post_teams.results %}
{% if api_values.item.organization_id == team.organization_id %}
{% if api_values.json.team_name == team.team_name %}
"{{ api_values.json.url }}",
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
},
{% endfor %}
]
delegate_to: localhost
run_once: true
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Patch team permissions
ansible.builtin.uri:
url: |-
{{ item.url }}permissions
method: PATCH
body_format: json
body: "{{ item.permissions }}"
headers:
Authorization: Token {{ lookup('env', 'CENTURION_TOKEN') }}
validate_certs: "{{ lookup('env', 'VALIDATE_CENTURION_CERTS') | default(true) | bool }}"
status_code:
- 200
when: >
item.url is defined
loop: "{{ team_permissions | list }}"
delegate_to: localhost
run_once: true
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
- name: Patch team notes
ansible.builtin.uri:
url: |-
{{ item.url }}
method: PATCH
body_format: json
body: |-
{
"model_notes": "{{ item.notes }}"
}
headers:
Authorization: Token {{ lookup('env', 'CENTURION_TOKEN') }}
validate_certs: "{{ lookup('env', 'VALIDATE_CENTURION_CERTS') | default(true) | bool }}"
status_code:
- 200
when: >
item.url is defined
loop: "{{ team_permissions | list }}"
delegate_to: localhost
run_once: true
no_log: > # Contains a secret that logging shows
{{ nfc_pb_disable_log | default(true) }}
vars:
nfc_pb_awx_tower_template:
- name: "Centurion/Access/Teams"
ask_tags_on_launch: false
ask_inventory_on_launch: true
ask_credential_on_launch: true
ask_limit_on_launch: true
concurrent_jobs_enabled: true
description: Creation and patching of teams and permissions
execution_environment: "No Fuss Computing EE"
job_type: "run"
# job_tags: complete
labels:
- access
- centurion_erp
- itam
- itsm
- permissions
- teams
use_fact_cache: true