write_charts is a custom module for ansible that generate charts in image format on the ansible control node.
The purpose of this project is to use ansible's control node to generate charts in image format. To do this, some of the functions of the Python Plotly library are used.
This module is very basic and uses only a few functions in comparison with the vast number of possibilities offered by the Plotly library.
It is currently possible to generate charts of this type:
- line
- bar
- pie
- donut
In images of these formats:
- png
- jpeg
- webp
- svg
- eps
├── /library
│ └── write_charts.py ##<-- python custom module
First of all, in order to use this module you MUST have installed the necessary library on your control node and/or in your environment.
Precisely this module uses plotly 5.22.0
Python lib:
- Plotly
- Kaleido
Depending on the libraries already present, you may also need:
- Tenacity
- Packaging
You can install these libraries directly from pip
If you have no way of modifying your control node or environment, you can install the libraries by the pip module directly via the playbook that will use this module.
SAMPLE:
- name: Install plotly
become: false
ansible.builtin.pip:
name: plotly=5.22.0
delegate_to: localhost
You can also install the libraries via .whl files
- name: Install plotly
become: false
ansible.builtin.pip:
name: /tmp/plotly-5.22.0-py3-none-any.whl
delegate_to: localhost
Parameter | Type | Required | Sample | Comment |
---|---|---|---|---|
type | string | true | "line" | The chart type. Choice: line - bar - pie - donut |
titlechart | string | false | "sample title" | The chart title. |
imgwidth | int | false | 1920 | The image file width. |
imgheight | int | false | 1080 | The image file height. |
format | string | false | "png" | The image file format. Choice: png - jpeg - webp - svg - pdf - eps |
path | string | true | "/tmp/output" | The path where the image file should be saved. |
filename | string | true | "sample_name" | The name of the image file |
xaxis | list | line/bar | ['00:00','02:00','04:00'] | The X axis data. |
xaxisname | string | line/bar | "Time" | The X axis title name. |
yaxis | list | line/bar | [20,20,30] | The Y axis data. |
yaxisname | list | line/bar | ["cpu","memory"] | The Y axis title name. |
yaxiscolor | list | line/bar | ["#1500ff","#ff00b7"] | The Y axis color. |
shape_line | string | line | "spline" | The chart shape line. Choice: spline - linear |
fontsize | int | false | 18 | The text font size. |
fontcolor | string | false | "#000000" | The text font color. |
titlelegend | string | false | "sample legend" | The legend title. |
slicedata | list | pie/donut | [20, 80] | The pie/donut chart data. |
slicelabel | list | pie/donut | ['sys','dba'] | The pie/donut chart labels. |
slicecolor | list | pie/donut | ["#1500ff","#ff00b7"] | The pie/donut chart color. |
sizehole | float | donut | .5 | The size of the hole in the centre of the donut chart |
Attribute | Support | Description |
---|---|---|
check_mode | full | Can run in check_mode and return changed status prediction without modifying target. |
-
Some theoretical examples can be found in EXAMPLES.md file
-
Below are two more practical examples of how to transform data into charts.
This portion of code converts the data collected yesterday by sar on the swap usage of a linux host into the bar chart above.
---
vars:
LCTIME: "LC_TIME=en_UK.utf8"
DAY: "yesterday"
EGREP: "Linux|RESTART|%|Average|^$"
tasks:
- name: Create directory on localhost
become: false
ansible.builtin.file:
path: /tmp/chart_collection
state: directory
delegate_to: localhost
- name: collect swap sar output
shell: "{{LCTIME}} sar -f /var/log/sa/sa$(date +%d -d '{{DAY}}') -S | egrep -v '{{EGREP}}' | awk '{print $1,$4,$6}'"
register: sarcmd
- name: set bar axis data
set_fact:
xdata: "{{ xdata|default([]) + [item.split(' ')[0]] }}"
y1data: "{{ y1data|default([]) + [item.split(' ')[1] | float]}}"
y2data: "{{ y2data|default([]) + [item.split(' ')[2] | float]}}"
with_items:
- "{{ sarcmd.stdout_lines}}"
- name: run bar chart
become: false
write_charts:
titlechart: "Swap Summary"
type: bar
xaxis: '{{xdata}}'
xaxisname: Time
yaxis:
- '{{y1data}}'
- '{{y2data}}'
yaxisname:
- "%swpused"
- "%swpcad"
yaxiscolor:
- "#1500ff"
- "#ff00b7"
imgwidth: 1920
imgheight: 1080
format: png
path: /tmp/chart_collection
filename: "swap_barchart"
delegate_to: localhost
This portion of code converts the data collected yesterday by sar on the load average of a linux host into the line chart above.
---
vars:
LCTIME: "LC_TIME=en_UK.utf8"
DAY: "yesterday"
EGREP: "Linux|RESTART|ldavg|Average|^$"
tasks:
- name: Create directory on localhost
become: false
ansible.builtin.file:
path: /tmp/chart_collection
state: directory
delegate_to: localhost
- name: collect ldavg sar output
shell: "{{LCTIME}} sar -f /var/log/sa/sa$(date +%d -d '{{DAY}}') -q | egrep -v '{{EGREP}}' | awk '{print $1,$4,$5,$6}'"
register: sarcmd
- name: set line axis data
set_fact:
xdata: "{{ xdata|default([]) + [item.split(' ')[0]] }}"
y1data: "{{ y1data|default([]) + [item.split(' ')[1] | float]}}"
y2data: "{{ y2data|default([]) + [item.split(' ')[2] | float]}}"
y3data: "{{ y3data|default([]) + [item.split(' ')[3] | float]}}"
with_items:
- "{{ sarcmd.stdout_lines}}"
- name: run line chart
become: false
write_charts:
titlechart: "Load Average Summary"
type: line
xaxis: '{{xdata}}'
xaxisname: Time
yaxis:
- '{{y1data}}'
- '{{y2data}}'
- '{{y3data}}'
yaxisname:
- "ldavg-1"
- "ldavg-5"
- "ldavg-15"
yaxiscolor:
- "#1500ff"
- "#ff00b7"
- "#f007c9"
titlelegend: "ldavg Legend"
shape_line: "spline"
imgwidth: 1920
imgheight: 1080
format: png
path: /tmp/chart_collection
filename: "ldavg_linechart"
delegate_to: localhost
- This module return
'changed': True
Key | Type | Sample |
---|---|---|
changed | boolean | True |
- Assuming you are in the root folder of your ansible project.
Specify a module path in your ansible configuration file.
$ vim ansible.cfg
[defaults]
...
library = ./library
...
Create the directory and copy the python modules into that directory
$ mkdir library
$ cp path/to/module library
- If you use Ansible AWX and have no way to edit the control node, you can add the /library directory to the same directory as the playbook .yml file
├── root repository
│ ├── playbooks
│ │ ├── /library
│ │ │ └── write_charts.py ##<-- python custom module
│ │ └── your_playbook.yml ##<-- you playbook