Heaving some trouble getting something to work in the argo-helm helm chart.
I am trying to make use of the very conveinet extraObjects value in their argo-cd chart.
Setup
values.yaml
extraObjects:
- apiVersion: v1
kind: ConfigMap
metadata:
labels: "{{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | nindent 4 | trim }}"
name: some-config-map
data:
something: something
template/extra-manifests.yaml
{{ range .Values.extraObjects }}
---
{{ tpl (toYaml .) $ }}
{{ end }}
Result
sadly it will produce
# Source: argo-cd/templates/extra-manifests.yaml
apiVersion: v1
data:
something: something
kind: ConfigMap
metadata:
labels: '
helm.sh/chart: argo-cd-5.19.12
app.kubernetes.io/name: some-config-map
app.kubernetes.io/instance: argocd
app.kubernetes.io/component: configmap
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/part-of: argocd'
name: some-config-map
---
The problem
This is unsurprising really. We put the template into a string so it makes sense that we see a string with the templated content.
I want the template to "float" on the labels field. But I can't do that because {{ blablaba }} isnt a vaild yaml object.
(Or it is but {} is object notation)
Because they are using the toYaml function to turn a valid YAML object into a string for use in the tpl function, I can't represent the template any other way other than using the string.
What I've tried
Comment Trick?
labels: # {{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | nindent 4 | trim }}
Thought becuse of the nindent it could insert the labels under the comment but it must be striped by toYaml or helm when the values used
Yaml !!map
labels: !!map |
{{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | nindent 4 | trim }}
and
labels: !!map |
{{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | fromYaml }}
I don't think yaml has built in conversion but it was worth a shot.
Yaml !!yaml
Tried to play around with !!yaml but I don't understand what it's supposed to do.
Tried this:
labels:
!!yaml: '!' : '!map'
!!value = : {{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | nindent 4 | trim }}
and
labels:
!!yaml: '!' : '!map'
!!value = : {{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | fromYaml }}
Question
Is there any valid YAML notation or object I can use to pass the template through toYaml without using a string?
Is there anyway to represent {{ blabla }} in YAML without using a string?
The Correct Way
Obviously doing away with toYaml and using strings will result in the expected behavior
extraObjects:
- |
apiVersion: v1
kind: ConfigMap
metadata:
labels:
{{ include `argo-cd.labels` (dict `context` . `component` `configmap` `name` `some-config-map`) | nindent 4 | trim }}
name: some-config-map
data:
something: something
{{ range .Values.extraObjects }}
---
{{ tpl . $ }}
{{ end }}
Before I open an issue with the Argo-CD Helm team I just want to know if there is any workaround?
Related
I am trying to following but I am getting this error "The conditional check 'item.vrf = 'default'' failed. The error was: template error while templating string: expected token 'end of statement block', got '='. String: {% if item.vrf = 'default' %} True {% else %} False {% endif %}" how to fix it?
proc_vrf: [{''proc'': ''T1'', ''vrf'': ''default''}, {''proc'': ''T2'', ''vrf'': ''vrf_T2''}, {''proc'': ''T3'', ''vrf'': ''default''}, {''proc'': ''T3'', ''vrf'': ''vrf_T3''}]
- name: Shut ospf for default vrf
cisco.nxos.nxos_config:
lines:
- shutdown
parents: router ospf {{ item.proc }}
save_when: modified
when: item.vrf|lower == 'default'
with_items: "{{ proc_vrf }}"
- name: Shut ospf for other vrf
cisco.nxos.nxos_config:
lines:
- shutdown
parents: router ospf {{ item.proc }}; vrf {{ proc_vrf }}
save_when: modified
when: item.vrf|lower != 'default'
with_items: "{{ proc_vrf }}"
There was an operator error. corrected comparison operator, ==
I am trying to associate users in a aws-auth config map using Helm. I'd like to loop through a nested map in our values file. My attempt to do this is as follows:
mapUsers: |
{{- range $username := .Values.users }}
- groups:
- system:masters
userarn: {{ $username.adminArn }}
username: {{ $username }}
{{- end }}
And the values file is as follows:
users:
username: user.name
userArn: user/Arn
adminArn: user/AdminArn
I'm not certain if this will solve my problem and would like some feedback.
After taking feedback from #Andrew, I was able to get this to work by first changing the structure of my values file to:
users:
testuser:
username: test.user
userArn: testuser/arn
adminArn: testuser/adminArn
I then was able to update my loop to:
{{- range $k := .Values.users }}
- groups:
- system:masters
userarn: {{ .adminArn }}
username: {{ .username }}
{{- end }}
I would like to iterate over a variable in ansible yaml and add key and value in jinja template
variable:
my:
variable:
- name: test
path: /etc/apt
cert: key.crt
my template
{% for key, value in item() %}
{{key}}: {{value}}
{% endfor %}
ansible yaml
- name: test
template:
force: yes
src: test.conf.j2
dest: /tmp/test.conf"
become: yes
with_items:
- "{{ my.variable }}"
How my yaml should look like:
path: /etc/apt
cert: key.crt
You actually have three issues in your task:
When using a loop, may it be loop or all the flavour of with_* you access the element currently looped in with the variable item, so not a function like you used in your task (item())
You are doing a superfluous list of list in
with_items:
- "{{ my.variable }}"
A first step would be to do with_items: "{{ my.variable }}".
An ever better step would be to use the loop replacement of the with_* syntax as suggested in the documentation
We added loop in Ansible 2.5. It is not yet a full replacement for with_<lookup>, but we recommend it for most use cases.
So you will end up with
loop: "{{ my.variable }}"
Then accessing properties of a dictionary in Jinja is done using the syntax
{% for key, value in dict.items() %}
Source: https://jinja.palletsprojects.com/en/2.11.x/templates/#for
So in your case:
{% for key, value in item.items() %}
All together, a working playbook demonstrating this would be:
- hosts: all
gather_facts: no
tasks:
- debug:
msg: |
{% for key, value in item.items() %}
{{key}}: {{value}}
{% endfor %}
loop: "{{ my.variable }}"
vars:
my:
variable:
- name: test
path: /etc/apt
cert: key.crt
That yields the result:
PLAY [all] *******************************************************************************************************
TASK [debug] *****************************************************************************************************
ok: [localhost] => (item={'name': 'test', 'path': '/etc/apt', 'cert': 'key.crt'}) => {
"msg": " name: test\n path: /etc/apt\n cert: key.crt\n"
}
PLAY RECAP *******************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Now you just have to reuse this in your template and loop and you should have what you expect.
Objective
I am trying to append a string to a list belonging to a key which is a few layers down within a dictionary.
Explanation
I initialize an empty list buried within some pre-existing variable called info:
tasks:
- set_fact:
info: "{{ info | combine( { host: { repo: { folders: [] }}}, recursive=true ) }}"
In a later task, I wish to append a string to that empty list. This may happen over multiple tasks, so I don't want to replace the empty list, but add onto it as needed. I am currently trying this:
tasks:
- set_fact:
info: "{{ info | combine( { 'host': { 'repo': { 'folders': [] }}}, recursive=true ) }}"
- set_fact:
info: "{{ info.host.repo.folders + ['ERROR. folderX does not exist'] }}"
when: folderX does not exist
- set_fact:
info: "{{ info.host.repo.folders + ['ERROR. folderY does not exist'] }}"
when: folderY does not exist
However, I receive a template error:
FAILED! => {"msg": "template error while templating string: expected name or number. String: {{ info.host.repo.folder + ['ERROR. folderX does not exist'] }}"}
I know that you can simply add elements to a list when the destination is on topmost layer. For example:
- set_fact:
folders: []
- set_fact:
folders: "{{ folders + ['ERROR. folderX does not exist'] }}"
when: folderX does not exist
- set_fact:
folders: "{{ folders + ['ERROR. folderY does not exist'] }}"
when: folderY does not exist
- debug: var=folders
Which, as desired, gives:
TASK [debug] ***************************************************************************************************
"folders": [
"ERROR. folderX does not exist",
"ERROR. folderY does not exist"
]
So, how does the syntax change when I am trying to descend multiple layers and access a list that resides in a nested dictionary? Thank you!
dicts and lists in ansible are "live", so you can update them via set statements
- set_fact:
info: >-
{%- set _ = info.host.repo.update({"folders": []}) -%}
{{ info }}
- set_fact:
info: >-
{%- set _ = info.host.repo.folders.append("ERROR. folderY does not exist") -%}
{{ info }}
when: folderY does not exist
that set _ = business is because ansible's jinja does not support the do statement so one cannot have an assignment statement by itself
I'm trying to access the id field in JSON in a Django template, but it has a colon in it.
When I include it in the template, I get the following error:
"Could not parse the remainder: ':id' from 'result.id.attributes.im:id'".
I've tried escaping the name and the colon with no success.
I've included the JSON output when I use it's parent, as well as the Django template.
Any suggestions?
*HTML Output with JSON when passing up the parent (result.id.attribute) *
1 id: {**u'im:id': u'422689480'**, u'im:bundleId': u'com.google.Gmail'} Name: Gmail - Google, Inc.
2 id: {u'im:id': u'530755375', u'im:bundleId': u'com.kfactormedia.mycalendarfree'} Name: MyCalendar Free - K-Factor Media, LLC.
3 id: {u'im:id': u'518972315', u'im:bundleId': u'com.click2mobile.textGramFree'} Name: Textgram - Texting with Instagram FREE - click2mobile
4 id: {u'im:id': u'521863802', u'im:bundleId': u'com.appmosys.emoji2free'} Name: Emoji 2 Free - 300+ NEW Emoticons and Symbols - Appmosys
Django Template
<html>
<body>
{% for result in app_data.entry %}
<h3>
{{ forloop.counter }}
Id: {{ result.id.attributes }}
Name: {{ result.title.label }}
{% endfor %}
</h3>
</body>
</html>
Edit to include the View:
View
def findAppRank(request,AppId=424909112):
URL="http://itunes.apple.com/us/rss/topfreeapplications/limit=300/genre=6007/json"
r=requests.get(URL)
output=r.content
data=json.loads(output)
AppData=data['feed']
t=get_template('myrank.html')
html=t.render(Context({'app_data': AppData, 'app_id': AppId }))
return HttpResponse(html)
You're looking for the slice filter.
{{ result.id.attributes|slice:"'im:id'" }}