Get array of strings from helm config - kubernetes

Ultimately i'm trying to get an array of strings e.g. ['foo', 'bar'] in my js app from my helm config.
./vars/dev/organizations.yaml
...
organizations:
- 'foo'
- 'bar'
...
./templates/configmap.yaml
...
data:
organizations.yaml: |
organizations: "{{ toYaml .Values.organizations | indent 4 }}"
...
./templates/deployment.yaml
...
containers:
args:
- "--organizations-config"
- "/etc/app/cfg/organizations.yaml"
...
index.js
...
const DEFAULT_ORGANIZATIONS_PATH = './vars/local/organizations.yaml'
const program = require('commander')
program
.option(
'--organizations-config <file path>',
'The path to the organizations config file.', DEFAULT_ORGANIZATIONS_PATH)
.parse(process.argv)
function readConfigs () {
return Promise.all(configs.map(path => {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
err ? reject(err) : resolve(yaml.safeLoad(data))
})
})
}))
}
readConfigs()
.then(configs => {
let organizationsConfig = configs[3]
console.log('organizationsConfig = ', organizationsConfig)
console.log('organizationsConfig.organizations = ', organizationsConfig.organizations)
...
The output from above is:
organizationsConfig = { organizations: ' - foo - bar' }
organizationsConfig.organizations = - foo - bar
How can I modify my helm config so that organizationsConfig.organizations will be ['foo', 'bar']

One way to get the output you're looking for is to change:
...
organizations:
- 'foo'
- 'bar'
...
To:
organizations: |
[ 'foo', 'bar']
So helm treats it as a single string. We happen to know that it contains array content but helm just thinks it's a string. Then we can set that string directly in the configmap:
organizations: {{ .Values.organizations | indent 4 }}
What this does is what the grafana chart does in that it forces the user to specify the list in the desired format in the first place. Perhaps you'd prefer to take an array from the helm values and convert it to your desired format, which appears to me to be json format. To do that you could follow the example of the vault chart. So the configmap line becomes:
organizations: {{ .Values.organizations | toJson | indent 4 }}
Then the yaml that the user puts in can be as you originally had it i.e. a true yaml array. I tried this and it works but I notice that it gives double-quoted content like ["foo","bar"]
The other way you can do it is with:
organizations:
{{- range .Values.organizations }}
- {{ . }}
{{- end }}

Sometimes the root cause is that you forget to surround each item by quotes:
organizations:
{{- range .Values.organizations }}
- {{ . | quote }} # <-- SEE Here
{{- end }}

Related

Sorting of strings variable in ansible playbook and display result in asending order

I have list of variable like,
item-1, item-22, item-3, item-99 i need to display as result of ansible playbook in following form
item-1, item-3, item-22, item-99.
I tried with below syntax but no luck.
- set_fact:
sorted_list_values: "{{ cluster_info | sort }}"
also I created one library folder and inside that i tried to written python module and tried to refer in ansible playbook but it gives me indention error.
#!/usr/bin/python
import json
from ansible.module_utils.basic import *
import sysy
def main():
module = AnsibleModule(
argument_spec = dict(
var1 = dict(required=True, type='str'),
var2 = dict(required=True, type='str'),
var3 = dict(required=True, type='str'),
var4 = dict(required=True, type='str'),
)
)
var1 = module.params['var1']
var2 = module.params['var2']
var3 = module.params['var3']
var4 = module.params['var4']
dict1 = OrderedDict(sorted(dict.items()))
module.exit_json(changed=False, meta=response)
if __name__ == '__main__':
main()
actually i am novice in python.
Any link or guidance would be really appreciated to sort strings variable and display as ansible playbook resilt.
Thanks
I used another trick, sorted it with help of Golan sort program.
Sorting with Golang
package main
import (
"fmt" "sort" "os"
)
func main() {
cmd := os.Args[1:]
sort.Strings(cmd)
fmt.Println(cmd)
}
cat site.yaml
---
- hosts: localhost
connection: local
gather_facts: false
vars:
var1: "{{ clus_var1 }}"
var2: "{{ clus_var2 }}"
var3: "{{ clus_var3 }}"
var4: "{{ clus_var4 }}"
tasks:
- shell: "go run /etc/ansible/gosave/sort.go {{ var1 }} {{ var2 }} {{ var3}} {{ var4 }}"
register: result
- debug:
var: result.stdout
run ansible-playbook site.yaml --extra-vars "clus_var1=cluster-2 clus_var2=cluster-99 clus_var3=cluster-1 clus_var4=cluster-5"
o/p as [cluster-1 cluster-2 cluster-5 cluster-99]

Helm variables used at custom places

I am not able to reference variable inside a nested variable in Helm. Also, I am not able to do this as nested reference. I want to retrieve all client variables under client name using the value of the client_name variable. How can I do that?
Values.yaml
clients:
client1:
incomigBucket: databucket
outgoingBucket: tempbucket
webURL: http://example.com
client2:
incomingBucket: databucket
outgoingBucket: tempbucket
webURL: http://example.com
I want to store client variables values in one variable and want to use it at different places in my Json file. if I use range function then it create section twice(as I have mentioned 2 clients), is there any thing in Helm I can use which can store these variables dynamically and use it in custom places in json file?
Sample File Section:
"FileConfig": {
"Client1": {
"incomingLocationPath": "s3://{{ .Values.clients.client1.incomingBucket }}/dir1/dir2",
"outgoingLocationPath": "s3://{{ .Values.clients.client1.outgoingBucket }}/dir1/dir2",
},
"Client2": {
"incomingLocationPath": "s3://{{ .Values.clients.client2.incomingBucket }}/dir1/dir2",
"outgoingLocationPath": "s3://{{ .Values.clients.client2.outgoingBucket }}/dir1/dir2",
}
}
I am not entirely sure where you intend to use this snippet. I assume it is inside a configMap. At least, I am not aware of any resource that had FileConfig section. I wouldn't know why it should be JSON either.
The basic pattern could look like this.
fileConfig:
{{- range $client, $config := .Values.clients }}
{{ $client }}:
incomingLocationPath: "s3://{{ $config.incomingBucket }}/dir1/dir2"
outgoingLocationPath: "s3://{{ $config.outgoingBucket }}/dir1/dir2"
{{- end }}
In something like a configMap to create JSON it could look like this.
kind: ConfigMap
apiVersion: v1
metadata:
name: file-config-json
data:
config.json: |
"fileConfig": {
{{- range $client, $config := .Values.clients }}
"{{ $client }}": {
"incomingLocationPath": "s3://{{ $config.incomingBucket }}/dir1/dir2",
"outgoingLocationPath": "s3://{{ $config.outgoingBucket }}/dir1/dir2"
}
{{- end }}
}

How to wait for StatefulSet using Ansible's community.kubernetes.k8s_info module

Ansible has a great community.kubernetes module.
One of the useful flags of k8s_info is wait that is implemented for Deployment, DaemonSet and Pod.
For other k8s kinds it will return instantly unless wait_condition is provided.
What wait_condition should be provided to wait for StatefulSet?
I would do this using an "helper" tasks file. Say I have some roles/commes/tasks/helpers/wait-for.yaml, that goes something like this:
- name: "Waits for {{ obj_name }} to startup"
block:
- name: "Checks latest {{ obj_name }} status"
debug:
msg: |
Object Kind {{ check_with.kind | default('nothing returned') }}
delay: "{{ wait_for | default(10) }}"
ignore_errors: True
retries: "{{ retries_for | default(10) }}"
until:
- >
check_with.status is defined
and check_with.kind is defined
and check_with.status is defined
and ((check_with.kind == 'Pod'
and (check_with.status.containerStatuses[0].ready | default(False)))
or (check_with.kind == 'DataVolume'
and (check_with.status.phase | default(False)) == 'Succeeded')
or (check_with.kind in [ 'Deployment', 'DeploymentConfig' ]
and (check_with.status.availableReplicas | default(0)) >= 1)
or (check_with.kind == 'Job'
and check_with.status.completionTime is defined
and check_with.status.succeeded is defined)
or (check_with.kind == 'PersistentVolumeClaim'
and (check_with.status.phase | default(False)) == 'Bound')
or (check_with.kind == 'StatefulSet'
and (check_with.status.readyReplicas | default(0)) >= 1))
Then, whenever I need to wait for a Kubernetes resource, I would include that tasks file, using:
- include_role:
name: commons
tasks_from: helpers/wait-for.yaml
vars:
check_with: "{{ lookup('k8s', api_version='apps/v1',
kind='StatefulSet', namespace='default',
resource_name='my-statefulset') }}"
obj_name: "Statefulset default/my-statefulset"
retries_for: 30
wait_for: 10

When including a template in another template, from an ansible role, what is the path?

I am attempting to use templates to seed configurations for apps in an ansible role. The role will configure some related services.
Template 1 - logging_config.json.j2
{
"logger_type": "foo_bar",
"logger_host": "https://fo_host",
"logger_token": "{{ secret_vault_logger_token }}"
}
Template 2 - app1_config.json.j2
{
"api_url_foo": "{{ app1_foo_api_url }}",
"logger": {% include "logging_config.json.j2" %}
}
Template 3 - xapp2_config.json.j2x
{
"port": {{ app2_port }},
"logger": {% include "logging_config.json.j2" %}
}
These are in a role - say roles/my_apps/templates. The role names templates app2_config.json.j2 or app1_config.json.j2 using the k8s module.
I always see this:
fatal: [k8s-non-devops]: FAILED! => {
"changed": false,
"msg": "TemplateNotFound: logging_config.json.j2"
}
In that path I have tried: templates/logging_config.json.j2, myapps/templates/logging_config.json.j2, roles/myapps/templates/logging_config.json.j2.
The variables template_path and template_fullpath are undefined.
Where is it?
In this instance, the j2 {% include %} syntax won't work. The paths don't appear to make sense. However, the ansible lookup plugin will do the job:
{
"port": {{ app2_port }},
"logger": {{ lookup('template', 'logging_config.json.j2' ) }}
}
This however come with a slight cost, ansible seems to recognise and alter the json, turning double quotes into single quotes and making it invalid. So if the config is json, you need to add | to_json:
{
"port": {{ app2_port }},
"logger": {{ lookup('template', 'logging_config.json.j2' ) | to_json }}
}

symfony form embeding other forms, how to reach form_errors/validation.message

I am having trouble on Symfony3 to display {{ form_errors([formname.field]) }} messages with a form embedding other forms.
I've dropped a symfony project on GitHub to explain my issue:
https://github.com/nyluje/symfony_test_form_embedded
You'll find in it:
\src\AppBundle\Controller\DefaultController.php modified to display
the test.
Under \src\AppBundle\Entity\ two entities: EntityForFormA and
EntityForFromB created with a "field1" being of EmailType.
Under \src\AppBundle\Form: 3 forms files; 2 Are directly related to
the EntityForFormA and EntityForFormB: FormAType and FormBType, and
the last one FormCType is there to embed both into one form.
At the top of the file \app\Resources\default\index.hmtl.twig:
{{ form_start(form_a) }}
{{ form_label(form_a.field1) }}
{{ form_widget(form_a.field1) }}
{{ form_errors(form_a.field1) }}
{{ form_end(form_a) }}
{{ form_start(form_c) }}
{{ form_label(form_c.FormA.field1) }}
{{ form_widget(form_c.FormA.field1) }}
{{ form_errors(form_c.FormA.field1) }}
{{ form_label(form_c.FormB.field1) }}
{{ form_widget(form_c.FormB.field1) }}
{{ form_errors(form_c.FormB.field1) }}
{{ form_end(form_c) }}
If you do a form A submit with value "j#j" you get:
The error message "This value is not a valid email address" is clearly displayed.
Now if you submit form C with value "j#j" in both fields:
The error message "This value is not a valid email address" is not displayed.
Does anyone know why the error messages don't display in case of FormC?
By default validation won't traverse to properties that are objects or collections. Use the valid constraint:
http://symfony.com/doc/current/reference/constraints/Valid.html
You cans set the traverse option for collections as well.