I'm working with Ansible trying to convert attribute from byte to Gb.
The code start with this CSV file
Path,Owner,Group,Mode,Last Access,Last Modified,Size,Total Size,Diskspace Quota,Namespace Quota,File and Directory Count
/a/b/c,user,users,16877,1970-01-01T00:00:00.000Z,2025-02-18T10:57:48.428Z,0,0,-1,-1,13,0
/a/b/e,user,users,16877,2025-02-28T11:37:50.800Z,2025-02-19T14:44:54.496Z,20948515,62845545,-1,-1,662,20948515
Then it convert the CSV into a JSON selecting and renaming fields, and convert byte from string to number type
- name: "Formater les données"
set_fact:
json_data: "{{ csv.content | community.general.from_csv | community.general.json_query('[].{\"Chemin\": \"Path\", \"Date de dernière modification\": \"Last Modified\", \"Taille en octets\": to_number(\"Size\"), \"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}') }}"
Which gives a list of JSON
"json_data": [
{
"Chemin": "/a/b/c",
"Date de dernière modification": "2024-10-23T13:03:51.187Z",
"Nombre de fichiers et de dossiers": "6",
"Taille en octets": 20948515
},
{
"Chemin": "/a/b/e",
"Date de dernière modification": "2025-02-19T14:45:04.971Z",
"Nombre de fichiers et de dossiers": "7",
"Taille en octets": 21948534
}
]
Is there a way to do arithmetic operation within json_query
(or somewhere else)?
to_number(\"Size\")
The solution I found
I simply use this command on the source CSV. Don't ask me how it works ^^
- name: Ajouter la taille en Go
set_fact:
dictionnary: >-
{{ dictionnary + [item | combine({'Taille en Go': (item['Size'] | int / (1024*1024*1024)) | round(2)})] }}
loop: "{{ csv.content | community.general.from_csv }}"
And then I choose the fields I want to keep this way
- name: "Sélectionner les champs à afficher"
set_fact:
result: "{{ dictionnary | community.general.json_query('[].{\"Chemin\": \"Path\", \"Date de dernière modification\": \"Last Modified\", \"Taille en Go\": \"Taille en Go\", \"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}') }}"
The solution I found according to this post
I choose the fields I want to keep this way. It converts the CSV to a list of Json.
- name: "Formater les données"
set_fact:
json_data: "{{
csv.content
| community.general.from_csv
| community.general.json_query(
'[].{
\"Chemin HDFS\": \"Path\",
\"Date de dernière modification\": \"Last Modified\",
\"Taille\": to_number(\"Size\"),
\"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}')
}}"
delegate_to: dpn
Then I loop on every Json, create a new field in a list, and combine with the Json looped. The new field is created using human_readable_filter.
- name: "Convertir la taille en Human Readable"
vars:
key_to_replace: 'Taille'
set_fact:
result: "{{
result | default([]) +
[
item | combine({ key_to_replace: item[key_to_replace] | int | human_readable })
]
}}"
loop: "{{ json_data }}"
I'm working with Ansible trying to convert attribute from byte to Gb.
The code start with this CSV file
Path,Owner,Group,Mode,Last Access,Last Modified,Size,Total Size,Diskspace Quota,Namespace Quota,File and Directory Count
/a/b/c,user,users,16877,1970-01-01T00:00:00.000Z,2025-02-18T10:57:48.428Z,0,0,-1,-1,13,0
/a/b/e,user,users,16877,2025-02-28T11:37:50.800Z,2025-02-19T14:44:54.496Z,20948515,62845545,-1,-1,662,20948515
Then it convert the CSV into a JSON selecting and renaming fields, and convert byte from string to number type
- name: "Formater les données"
set_fact:
json_data: "{{ csv.content | community.general.from_csv | community.general.json_query('[].{\"Chemin\": \"Path\", \"Date de dernière modification\": \"Last Modified\", \"Taille en octets\": to_number(\"Size\"), \"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}') }}"
Which gives a list of JSON
"json_data": [
{
"Chemin": "/a/b/c",
"Date de dernière modification": "2024-10-23T13:03:51.187Z",
"Nombre de fichiers et de dossiers": "6",
"Taille en octets": 20948515
},
{
"Chemin": "/a/b/e",
"Date de dernière modification": "2025-02-19T14:45:04.971Z",
"Nombre de fichiers et de dossiers": "7",
"Taille en octets": 21948534
}
]
Is there a way to do arithmetic operation within json_query
(or somewhere else)?
to_number(\"Size\")
The solution I found
I simply use this command on the source CSV. Don't ask me how it works ^^
- name: Ajouter la taille en Go
set_fact:
dictionnary: >-
{{ dictionnary + [item | combine({'Taille en Go': (item['Size'] | int / (1024*1024*1024)) | round(2)})] }}
loop: "{{ csv.content | community.general.from_csv }}"
And then I choose the fields I want to keep this way
- name: "Sélectionner les champs à afficher"
set_fact:
result: "{{ dictionnary | community.general.json_query('[].{\"Chemin\": \"Path\", \"Date de dernière modification\": \"Last Modified\", \"Taille en Go\": \"Taille en Go\", \"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}') }}"
The solution I found according to this post
I choose the fields I want to keep this way. It converts the CSV to a list of Json.
- name: "Formater les données"
set_fact:
json_data: "{{
csv.content
| community.general.from_csv
| community.general.json_query(
'[].{
\"Chemin HDFS\": \"Path\",
\"Date de dernière modification\": \"Last Modified\",
\"Taille\": to_number(\"Size\"),
\"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}')
}}"
delegate_to: dpn
Then I loop on every Json, create a new field in a list, and combine with the Json looped. The new field is created using human_readable_filter.
- name: "Convertir la taille en Human Readable"
vars:
key_to_replace: 'Taille'
set_fact:
result: "{{
result | default([]) +
[
item | combine({ key_to_replace: item[key_to_replace] | int | human_readable })
]
}}"
loop: "{{ json_data }}"
Share
Improve this question
edited Mar 17 at 7:23
Mike HUMPHREYS
asked Mar 12 at 14:35
Mike HUMPHREYSMike HUMPHREYS
231 silver badge6 bronze badges
2
- 1 You should provide your input (aka the CSV). In short, no JMESPath does not allow arithmetic. But I also doubt you really. need JMESPath to achieve what you want here. – β.εηοιτ.βε Commented Mar 12 at 20:05
- I've edit my question for to be more specific @β.εηοιτ.βε – Mike HUMPHREYS Commented Mar 13 at 7:49
1 Answer
Reset to default 2I'm working with Ansible trying to convert attribute from byte to Gb.
Generally, human_readable
filter is responsible for this.
Don't ask me how it works ^^
It works like this:
- we can't refer to the iterator when using
map
filter, thus we need aloop
where we can use theitem
loop var; - for each dict within a list of dicts,
combine
filter allows us to replace the value of a dict key when we are combining that dict with another dict consisting of one key of the same name.
This solution could be developed further to make the code more understandable and maintainable:
- JMESPath query could be written in multiple lines;
- default value could be set for the resulting variable (your current example doesn't work because of this);
- arithmetic operation could be replaced with
human_readable
filter:
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
vars:
csv
content: |
Path,Owner,Group,Mode,Last Access,Last Modified,Size,Total Size,Diskspace Quota,Namespace Quota,File and Directory Count
/a/b/c,user,users,16877,1970-01-01T00:00:00.000Z,2025-02-18T10:57:48.428Z,0,0,-1,-1,13,0
/a/b/e,user,users,16877,2025-02-28T11:37:50.800Z,2025-02-19T14:44:54.496Z,20948515,62845545
tasks:
- name: "Formater les données"
set_fact:
json_data: "{{
csv.content
| community.general.from_csv
| community.general.json_query(
'[].{
\"Chemin\": \"Path\",
\"Date de dernière modification\": \"Last Modified\",
\"Taille en octets\": to_number(\"Size\"),
\"Nombre de fichiers et de dossiers\": \"File and Directory Count\"}')
}}"
- name: Replace the value
vars:
key_to_replace: 'Taille en octets'
set_fact:
result: "{{
result | default([]) +
[
item | combine({ key_to_replace: item[key_to_replace] | int | human_readable(unit='G') })
]
}}"
- name: Log the result
debug:
var: result
This will produce the following:
"result": [
{
"Chemin": "/a/b/c",
"Date de dernière modification": "2024-10-23T13:03:51.187Z",
"Nombre de fichiers et de dossiers": "6",
"Taille en octets": "0.00 GB"
},
{
"Chemin": "/a/b/e",
"Date de dernière modification": "2025-02-19T14:45:04.971Z",
"Nombre de fichiers et de dossiers": "7",
"Taille en octets": "0.02 GB"
}
]
If you need a numeric representation, the solution would depend on the goal:
- if you're fine to simply have the converted value but want it to be a number, you can apply
| split | first | float
chain of filters; - if you want to perform calculations, there's also
human_to_bytes
filter that is the exact opposite tohuman_readable
.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744747123a4591368.html
评论列表(0条)