Is it possible use YamlSlurper and YamlBuilder to find duplicate property names? - groovy

If I have a yaml file like this:
obj:
- name: 'msg'
patterns:
'("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
'("cvv":")([^"]*)(")' : '$1xxxx$3'
'("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
If I use the Groovy YamlSlurper class to load this, the "patterns" object will have two properties, with the following names:
("ssn":")([^"]*)(")
("cvv":")([^"]*)(")
The third property in the input has a name identical to the first property name, so the third one will override the first (or vice versa).
Is there any way I could use some combination of YamlSlurper and perhaps YamlBuilder to somehow detect that the input has a duplicate property name?
I can see that changing the expected syntax of this file so that it expects a format like this:
obj:
- name: 'msg'
patterns:
- '("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
- '("cvv":")([^"]*)(")' : '$1xxxx$3'
- '("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
Would give me the ability to detect duplicates. If I can't detect duplicate property names on the input using the original format, I will consider changing the spec to require the modified format.

behind groovy.yaml.YamlSlurper there is a jackson library.
YamlSlurper.parse()
-> YamlConverter.convertYamlToJson() -> jackson
so, you could use it to detect first duplicate:
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.DeserializationFeature
String yaml = '''
obj:
- name: 'msg'
patterns:
'("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
'("cvv":")([^"]*)(")' : '$1xxxx$3'
'("ssn":")([^"]*)(")' : '$1xxxxxxxxx$3'
'''
def result =
new ObjectMapper()
.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
.readTree(new YAMLFactory().createParser(yaml))
this code throws exception:
com.fasterxml.jackson.databind.exc.MismatchedInputException:
Duplicate field '("ssn":")([^"]*)(")' for `ObjectNode`:
not allowed when `DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY` enabled
at [Source: (StringReader); line: 7, column: 31]

Related

how to patch configmap field using python client library

I have below configmap.yml i want to patch/update date field from python script from container in kubernates deployment i searched various side but couldn't get any reference to do that. Any reference or code sample would be a great help
apiVersion: v1
kind: ConfigMap
metadata:
name: sample-configmap
labels:
app: test
parameter-type: sample
data:
storage.ini: |
[DateInfo]
date=1970-01-01T00:00:00.01Z
I went through this reference code but couldn't figure out what will be content of body and which parameter i should use and which parameter i should neglect
partially update the specified ConfigMap
from __future__ import print_function
import time
import kubernetes.client
from kubernetes.client.rest
import ApiException
from pprint import pprint
configuration = kubernetes.client.Configuration()
# Configure API key authorization: BearerToken configuration.api_key['authorization'] = 'YOUR_API_KEY'
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
# configuration.api_key_prefix['authorization'] = 'Bearer'
# Defining host is optional and default to http://localhost configuration.host = "http://localhost"
# Enter a context with an instance of the API kubernetes.client
with kubernetes.client.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = kubernetes.client.CoreV1Api(api_client)
name = 'name_example' # str | name of the ConfigMap
namespace = 'namespace_example' # str | object name and auth scope, such as for teams and projects
body = None # object |
pretty = 'pretty_example'
dry_run = 'dry_run_example'
field_manager = 'field_manager_example'
force = True
try:
api_response = api_instance.patch_namespaced_config_map(name, namespace, body, pretty=pretty, dry_run=dry_run, field_manager=field_manager, force=force)
pprint(api_response)
except ApiException as e:
print("Exception when calling CoreV1Api->patch_namespaced_config_map: %s\n" % e)
The body parameter in patch_namespaced_config_map is the actual configmap data that you want to patch and needs to be first obtained with read_namespaced_config_map.
Following steps are required for all the operations that have the body argument:
Get the data using the read_*/get_*method
Use the data returned in the first step in the API modifying the object.
Further, for most cases, it is enough to pass the required arguments namely
name, namespace and body but here is the info about each:
Parameters
Name
Type
Description
Notes
name
str
name of the ConfigMap
namespace
str
object name and auth scope, such as for teams and projects
body
object
pretty
str
If 'true', then the output is pretty printed.
[optional]
dry_run
str
When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed
[optional]
field_manager
str
fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).
[optional]
force
bool
Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.
[optional]
Review the K8s python client README for the list of all supported APIs and their usage.

Nim: Can't access fields of object returned by a procedure

I was trying to write a lexer in Nim. Sorry, if this sounds a bit idiotic because I started using nim yesterday, so my problem is that I created a type such as what follows
import position
type
Error* = object
pos_start : position.Position
pos_end : position.Position
name: string
details: string
then I went on to create a procedure that returns an instance of this type,
proc IllegalCharacterError*(pos_start : position.Position, pos_end : position.Position, details : string) : Error =
return Error(pos_start: pos_start, pos_end: pos_end, name: "IllegalCharacterError", details: details)
Now, everything works fine except when I, from another module, try to access fields of this returned instance I get error
from errors import nil
from position import nil
var current_char = "2"
let pos = position.Position(idx: -1, ln: 0, col: -1, fn: fn, ftxt: text)
let error = errors.IllegalCharacterError(pos, pos, current_char)
echo error.name
The last line is the one that throws the error and following is the error that appeared during compilation
Error: undeclared field: 'name' for type errors.Error [declared in C:\Users\Mlogix\Desktop\testNim\errors.nim(4, 3)]
Thanks, any help would be really appreciated.
Ok, finally after an hour I realized that my fields weren't public. For anyone from the future, I changed my type code to
import position
type
Error* = object
pos_start* : position.Position
pos_end* : position.Position
name*: string
details*: string
and it worked. Hooray.

Capture file existance status and send output to csv file in ansible

Here is Ansible playbook to check the config file exist and capture that output using register and send that output to csv file.If file exist It should get 1 in csv file.But am getting error "The task includes an option with an undefined variable. The error was : 'dict object' has no attribute 'stdout' \n\n The error appeares to be in ..../..../../main.yml , but may \n be elsewhere in the file depending n the exact syntax problem. \n \n The offending line appears to be \n\n\n"
---
- hosts: all
tasks:
- name : Gather the metadata
shell : curl -H Metadata:true "http://169.254.169.254/metadata/instance"
register : vm_medtadata
- name : Assign the meta json to variable
set_facts:
meta : "{{vm_metadata.stdout }}"
- name : setting the facts for csv
set_fact:
vm_resourcegroup: "{{meta.compute.resourceGroupName }}"
- name : check config file exist
stat:
path: /etc/example.config
register: file_status
- name: create local file with file existance status
local_action : copy content = "{{vm_resourcegroup}} {{ansible_hostname}} {{file_status.stdout}}" \n dest= "{{build_source_dir}}/src/ansible/ansible_file_status{{anisible_hostname}}.csv "
...
local_action: copy content = "{{vm_resourcegroup}} {{ansible_hostname}} {{file_status.stdout}}" \n dest= "{{build_source_dir}}/src/ansible/ansible_file_status{{anisible_hostname}}.csv "
You have a misunderstanding about stat: -- it does not have a .stdout property, but rather an .stat property with several sub-fields
Also, your local_action appears to have a stray \n in it, perhaps you meant to include that inside the double-quotes?

looping a template using groovy GStringTemplateEngine()

My requirement is to create a template engine to support a looping in it.
The final template should look something like this:
#cat output.template
env:
- name : param1
value : 1
- name : param2
value : 2
I have pseudo code to explain my requirement
def f = new File('output.template')
def engine = new groovy.text.GStringTemplateEngine()
def mapping = [
[ name : "param1",
value : "1"],
[ name : "param2",
value : "2" ]
] // This mapping can consists of a multiple key value pairs.
def Template = engine.createTemplate(f).make(mapping)
println "${Template}"
Can someone help me how to achieve this requirement of looping inside the templates and how should I modify my template?
*UPDATE : All the solutions provided by tim_yates or by Eduardo Melzer has resulted in following output with extra blank lines at the end of template. What could be the reason for that?* Are the solution providers not able to see this behavior or the issue is my system only?.
# groovy loop_template.groovy
env:
- name: param1
value : 1
- name: param2
value : 2
root#instance-1:
Change your template file to look like this:
#cat output.template
env:<% mapping.eachWithIndex { v, i -> %>
- name : ${v.name}
value : ${v.value}<% } %>
As you can see, your template file expects an input parameter called mapping, so you need change your main code to something like this:
def f = new File('output.template')
def engine = new groovy.text.GStringTemplateEngine()
def mapping = [
[ name : "param1", value : "1"],
[ name : "param2", value : "2"]
] // This mapping can consists of a multiple key value pairs.
def Template = engine.createTemplate(f).make([mapping: mapping])
println "${Template}"
Output:
#cat output.template
env:
- name : param1
value : 1
- name : param2
value : 2

Not able to get a value from yml file in groovy

I have stored an entire yaml file into a Map yamlConfig which i am able to print and check.
The Output when I run the code: yamlConfig.each{ k, v -> println "${k}:${v}" } is:
Host:localhost
Port:10000
application:[name:ABC, preferences:[UUID:d3f3278e, server:localhost:2222]]
services:[[name:XYZ, instances:1, start:true]]
dataSets:[[name:ABC], [name:XYZ]]
Now, I am trying to fetch a value from Map using following code:
println yamlConfig.get("services").getAt("name")
However, I am getting the value: [XYZ]. Instead I need the result as XYZ, without square brackets.
Yml file I am using:
Host: localhost
Port: 10000
application:
name: ABC
preferences:
UUID: d3f3278e
server: localhost:2222
services:
- name: XYZ
instances: 1
start: true
data:
- name: ABC
- name: XYZ
This is because of the - character placed before your name property. It makes the yaml parser treat what's inside the services section as an array.
When you ask for the name property doing yamlConfig['services']['name'] groovy gives you all the macthing properties of array items in the services array, and it can only return them in another array.
So either remove the - or use yamlConfig['services'][0]['name'].
yamlConfig.get("services")
return a list but not a service, therefore when you apply getAt to the returned list of services it returns a list of names.
yamlConfig.get("services").getAt('name')
actually does
yaml['services'].collect { it['name'] }
so in order to get a name of a certain service you need to do something like this:
println yaml['services'][0]['name']

Resources