How to parse PodSpec.spec.imagePullSecrets from a yaml file? - go

I want to parse the following structure using go:
---
prjA:
user1:
metadata:
namespace: prj-ns
spec:
containers:
- image: some-contaner:latest
name: containerssh-client-image
resources:
limits:
ephemeral-storage: 4Gi
requests:
ephemeral-storage: 2Gi
securityContext:
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
imagePullSecrets:
- docker-registry-secret
I'm using sigs.k8s.io/yaml to unmarshal YAML:
var userConfig map[string]map[string]kubernetes.PodConfig
err = yaml.UnmarshalStrict(yamlFile, &userConfig)
where kubernetes is imported from github.com/containerssh/kubernetes. Everything works fine - except the immagePullSecrets which gives the following error:
ERROR unmarshal user config file; error [error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field PodSpec.spec.imagePullSecrets of type v1.LocalObjectReference]
What is the correct way to specify / parse an imagePullSecrets in go?

This is a problem with the input - and maybe not a very clear error message.
The imagePullSecrets must be specified using the key name like:
imagePullSecrets:
- name: docker-registry-secret
I leave the question as it might help other people who run in the same problem.

Related

Access a property in the body of a kubernetes resource using a field path

I want to get the values of the fields declared in the downwardAPI section of a Pod.
apiVersion: v1
kind: Pod
metadata:
name: sample
namespace: default
spec:
containers:
- image: rpa
imagePullPolicy: Always
name: testbot
volumeMounts:
- mountPath: /etc/pod-info
name: pod-info
volumes:
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.labels
path: labels
- fieldRef:
apiVersion: v1
fieldPath: metadata.name
path: pod-name
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: pod-namespace
name: pod-info
Using client-go, I can use pod.Spec.Volumes[0].DownwardAPI.Items to get the item slice including the fieldPath. But I would now need to dynamically able to fetch whatever values has been declared in the fieldPath. So, from the first item, I would like to access the value of metadata.labels. I could do pod.ObjectMeta.Labels but I would like to access the field dynamically. In terms of Javascript it would have been something like
var foo="metadata.labels"
var fooarr = foo.split(".")
var bar={
metadata:{
labels: "foobar"
}
}
var temp = oof
for(lm of lmaoarr){
temp = temp[lm]
}
console.log(temp)
How do I do something similar using client-go?
The standard kubelet code has logic to translate the downward API fields into environment variables. It is neither simple nor generic, though: at the bottom of the stack, only the specific fields listed in the Kubernetes documentation are supported. It would be incomplete, but not wrong or inconsistent with standard Kubernetes, to just match on these specific fields:
for _, item := range downwardApiObject.Items {
switch item.FieldPath.FieldRef {
case "metadata.name":
return pod.ObjectMeta.Name
}
}
The actual code:
Calls pods.ConvertDownwardAPIFieldLabel which does some very lightweight normalization and validation: subscripts are only allowed on metadata.annotations and metadata.labels, only the dozen or so specific field names are allowed, and spec.host is rewritten to spec.nodeName.
Handles the spec.* and status.* variables that depend on non-metadata fields in the pod spec or runtime data.
Delegates to fieldpath.ExtractFieldPathAsString which knows how to handle the metadata.* variables.
The k8s.io/kubernetes/pkg/fieldpath package contains a couple of helpers that are used in processing the downward API, and a really short answer to your specific question could be just to call fieldpath.ExtractFieldPathAsString passing it the Pod object, which will handle the metadata fields but nothing else.

Get all children key values in a YAML with PyYAML

Say I have a YAML like:
Resources:
AlarmTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- !If
- ShouldAlarm
Protocol: email
How do I get each key and value of all the children if I'm walking over each resource and I want to know if one of the values may contain a certain string? I'm using PyYAML but I'm also open to using some other library.
You can use the low-level event API if you only want to inspect scalar values:
import yaml
import sys
input = """
Resources:
AlarmTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- !If
- ShouldAlarm
- Protocol: email
"""
for e in yaml.parse(input):
if isinstance(e, yaml.ScalarEvent):
print(e.value)
(I fixed your YAML because it had a syntax error.) This yields:
Resources
AlarmTopic
Type
AWS::SNS::Topic
Properties
Subscription
ShouldAlarm
Protocol
email

Updating the Yaml file, with new fields using ruamel

I am trying to update the yaml file using ruamel python.
proc=subprocess.Popen(['kubectl','get','pod','web3','-o','yaml','--export'], stdout=subprocess.PIPE)
rein=proc.stdout.read()
result, indent, block_seq_indent = ruamel.yaml.util.load_yaml_guess_indent(rein, preserve_quotes=True)
So far I have tried :
result['spec'].append('nodeSelector')
which gives ERROR :
result['spec'].append('nodeSelector')
AttributeError: 'CommentedMap' object has no attribute 'append'
Also tried like this :
result['spec']['nodeSelector']['kubernetes.io/hostname']='kubew1'
gives :
result['spec']['nodeSelector']['kubernetes.io/hostname']='kubew1'
File "/usr/local/lib/python3.6/dist-packages/ruamel/yaml/comments.py", line 752, in __getitem__
return ordereddict.__getitem__(self, key)
KeyError: 'nodeSelector'
My Intial Yaml File is :
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
app: demo
name: web
name: web3
selfLink: /api/v1/namespaces/default/pods/web3
spec:
containers:
- image: aexlab/flask-sample-one
imagePullPolicy: Always
name: web
ports:
- containerPort: 5000
name: http
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-7bcc9
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
And Expected fields I want to add inside 'spec' is :
nodeSelector:
kubernetes.io/hostname: kubew1
Any Ideas how to achieve this with ruamel library.
In your YAML file your root level collection is a mapping and the value for the key spec in that mapping is itself a mapping. Both of those mappings get loaded as dict-like objects using ruamel.yaml named CommentedMap.
As with normal dicts you can add key-value pairs, deleted keys (and their values), and update values for a key, but there is no .append() method, as there is with a list (i.e. appending an extra item to a list).
Your output is a bit terse, but of course you cannot just add nodeSelector to anything (list/sequence nor dict/mapping) and expect that to add kubernetes.io/hostname: kubew1 (a mapping in its own right) automatically.
Your try of:
result['spec']['nodeSelector']['kubernetes.io/hostname'] = 'kubew1'
cannot work because there is no dict result['spec']['nodeSelector'] where you can add the key kubernetes.io/hostname.
You would either first have to create a key with an emtpy dict as value:
result['spec']['nodeSelector'] = {}
result['spec']['nodeSelector']['kubernetes.io/hostname'] = 'kubew1'
or do
result['spec']['nodeSelector'] = {'kubernetes.io/hostname': 'kubew1'}
Please note that the above has nothing much to do with ruamel.yaml, that is just basic Python data structure manipulation. Also note that there are over 100 libraries in the ruamel namespace, out of which ruamel.yaml is just one of several published as open source, so using ruamel is not very clear statement, although of course the context often provides enough information on which library you actually use.

How to use the security group existing in horizon in heat template

I'm newbies on heat yaml template loaded by OpenStack
I've got this command which works fine :
openstack server create --image RHEL-7.4 --flavor std.cpu1ram1 --nic net-id=network-name.admin-network --security-group security-name.group-sec-default value instance-name
I tried to write this heat file with the command above :
heat_template_version: 2014-10-16
description: Simple template to deploy a single compute instance with an attached volume
resources:
my_instance:
type: OS::Nova::Server
properties:
name: instance-name
image: RHEL-7.4
flavor: std.cpu1ram1
networks:
- network: network-name.admin-network
security_group:
- security_group: security-name.group-sec-default
security-group:
type: OS::Neutron::SecurityGroup
properties:
rules: security-name.group-sec-default
my_volume:
type: OS::Cinder::Volume
properties:
size: 10
my_attachment:
type: OS::Cinder::VolumeAttachment
properties:
instance_uuid: { get_resource: my_instance }
volume_id: { get_resource: my_volume }
mountpoint: /dev/vdb
The stack creation failed with the following message error :
openstack stack create -t my_first.yaml First_stack
openstack stack show First_stack
.../...
| stack_status_reason | Resource CREATE failed: BadRequest: resources.my_instance: Unable to find security_group with name or id 'sec_group1' (HTTP 400) (Request-ID: req-1c5d041c-2254-4e43-8785-c421319060d0)
.../...
Thanks for helping,
According to the template guide it is expecting the rules type is of list.
So, change the content of template as below for security-group:
security-group:
type: OS::Neutron::SecurityGroup
properties:
rules: [security-name.group-sec-default]
OR
security-group:
type: OS::Neutron::SecurityGroup
properties:
rules:
- security-name.group-sec-default
After digging, I finally found what was wrong in my heat file. I had to declare my instance like this :
my_instance:
type: OS::Nova::Server
properties:
name: instance-name
image: RHEL-7.4
flavor: std.cpu1ram1
networks:
- network: network-name.admin-network
security_groups: [security-name.group-sec-default]
Thanks for your support

In Ansible, is there a way to force variable values to integer?

I'm trying to use ecs_taskdefinition module for Ansible (v2.0), and I think I'm stuck in the basic Ansible YAML gotcha.
As per the example for the module, if I provide integer values for cpu and memory, this works as expected:
- name: "Create task definition"
ecs_taskdefinition:
containers:
- name: simple-app
cpu: 10
memory: 300
essential: true
image: "httpd:2.4"
portMappings:
- containerPort: 80
hostPort: 80
Although, I would like the memory and cpu to be templatable. So that I will be able to use same container definition for different environments.
APP_ENV: "test"
test:
containers:
simple_app:
memory: 1920
cpu: 2560
- name: "Create task definition"
ecs_taskdefinition:
containers:
- name: simple-app
cpu: "{{vars.get(APP_ENV).containers.simple_app.cpu | int}}"
memory: "{{vars.get(APP_ENV).containers.simple_app.memory | int}}"
essential: true
image: "httpd:2.4"
portMappings:
- containerPort: 80
hostPort: 80
With above, I get error from the botocore API:
botocore.exceptions.ParamValidationError: Parameter validation failed:
Invalid type for parameter containerDefinitions[0].memory, value: 1920, type: <type 'str'>, valid types: <type 'int'>, <type 'long'>
Invalid type for parameter containerDefinitions[0].cpu, value: 2560, type: <type 'str'>, valid types: <type 'int'>, <type 'long'>
Is this fixable without having to update the Ansible module to actually try to convert these values to integers?
It seems to be working in Ansible version 2.1.1.0. If you can't get it to work, a possible solution is to define the variables a the top level of the dictionary and not using the int filter…
vars:
APP_ENV: test
simple_app_container_cpu: 2560
simple_app_container_ram: 1920
tasks:
- name: Create task definition
ecs_taskdefinition:
containers:
- name: simple-app
cpu: "{{simple_app_container_cpu}}"
memory: "{{simple_app_container_ram}}"
Note: I used ram instead of memory because I like how it lines up :)

Resources