Find a value in a structured file with Ansible - parsing

Here I have a small question about how to find a value in a structured file using Ansible. I've seen lineinfile but I'm not pretty sure that it will be helpful. If we assume that my file looks like this (in fact it's way way longer but for evident reasons I cannot post it here ^^)
################## junos.conf ##################
system {
auto-snapshot;
root-authentication {
encrypted-password ## SECRET-DATA
}
services {
ssh;
netconf ssh;
scp;
}
syslog {
user * {
any emergency;
}
file messages {
any notice;
authorization info;
}
file interactive-commands {
interactive-commands any;
}
}
processes {
dhcp-service {
traceoptions {
file dhcp_logfile size 10m;
level all;
flag all;
}
}
}
}
interfaces {
irb {
unit 0 {
family inet {
dhcp {
vendor-id Juniper-ex4300-48t;
}
}
}
}
vme {
unit 0 {
family inet {
address 172.0.0.1/24
}
}
}
}
forwarding-options {
storm-control-profiles default {
all;
}
}
vlans {
default {
vlan-id 1;
l3-interface irb.0;
}
}
It's a .conf file but it looks like a structured file. Imagine, I want to find a way to get the value interfaces->vme->unit 0->family inet within an Ansible playbook, how could I do ? Which parser could I use in Ansible ?
I've already read this page but I don't really know which parser to use and how to use it : https://docs.ansible.com/ansible/latest/network/user_guide/cli_parsing.html
Thanks,
Max

Regarding your question
Which parser could I use in Ansible?
If you are not able to export the config in a JSON structured format before (show config | display json), because it is in example not under your control, you may need to deal with the given structure.
It's a .conf file but it looks like a structured file.
Since the structure don't look like one of the available templates in Parsing semi-structured text with Ansible, you may need to look to an other option.
I assume you do not want to read in the whole file via file_lookup module and parse it fully within Ansible.
The Lookup Plugins seems also not to have the provided structure implemented. The INI lookup seems also not fit.
Imagine, I want to find a way to get the value interfaces->vme->unit 0->family inet within an Ansible playbook, how could I do?
If your configuration file has just that structure and it is not changing, which we don't know according
... in fact it's way way longer ...
the following approach might be working for a while:
- name: Read IP address from Junos config file
shell:
cmd: grep -o "address.*" /tmp/junos.conf | cut -f 2 -d " " | cut -f 1 -d "/"
register: ip_address
warn: false
check_mode: false
changed_when: false
delegate_to: localhost
tags: junos_conf
- name: Show IP address
debug:
msg: "{{ ip_address }}"
tags: junos_conf
There is also the option to write an own custom plugin.
Thanks to
How to read a line from a file into an Ansible variable
Links from comments
Using NETCONF in Ansible
Using Ansible to Retrieve or Compare Junos OS Configurations

Related

Automatically detect if using GUI or batch mode

I am using Stata both in the GUI and running scripts in batch mode using a slurm cluster. The filepaths need to be established differently in each use case but I would like to have one .do file where all of the paths are defined.
Is there a way to write a falsifiable if statement that can evaluate to true if run from the GUI and false if run in batch?
Something akin to
glob using_gui = T
if $using_gui == T {
glob dir "/mydir"
} else {
glob dir "D:/mydir"
}
But where $using_gui is automatically determined as T or F
As answered within the statalist question linked above, this can be answered with c(mode) so
if "`c(mode)'" == "batch" {
glob dir "/mydir"
}
else {
glob dir "D:/mydir"
}
There are many ways to skin a cat. See help creturn for like options.
Are you running the GUI on one machine and the batch job on a different machine? If so, you can use c(username) for this as the two machines will have different usernames.
For example:
if "`c(username)'" == "MyGUILaptop" {
glob dir "/mydir"
}
else if "`c(username)'" == "MySlurmCluster" {
glob dir "D:/mydir"
}
You can see the username of the computer you are using by using display "`c(username)'". See more about this here (disclaimer: I wrote the book this links to).

How can I pass a pointer to a file in helm upgrade command?

I have a truststore file(a binary file) that I need to provide during helm upgrade. This file is different for each target env(dev,qa,staging or prod). So I can only provide this file at time of deployment. helm upgrade --set-file does not take a binary file. This seem to be the issue I found here: https://github.com/helm/helm/issues/3276. This truststore files are stored in Jenkins Credential store.
As the command itself is described below:
--set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
it is also important to know The Format and Limitations of
--set.
The error you see: Error: failed parsing --set-file data... means that the file you are trying to use does not meet the requirements. See the example below:
--set-file key=filepath is another variant of --set. It reads the
file and use its content as a value. An example use case of it is to
inject a multi-line text into values without dealing with indentation
in YAML. Say you want to create a brigade project with certain value
containing 5 lines JavaScript code, you might write a values.yaml
like:
defaultScript: |
const { events, Job } = require("brigadier")
function run(e, project) {
console.log("hello default script")
}
events.on("run", run)
Being embedded in a YAML, this makes it harder for you to use IDE
features and testing framework and so on that supports writing code.
Instead, you can use --set-file defaultScript=brigade.js with
brigade.js containing:
const { events, Job } = require("brigadier")
function run(e, project) {
console.log("hello default script")
}
events.on("run", run)
I hope it helps.

Is there a way to create with a script a swift class and add properties in pre-build?

Maybe this is dumb but here goes nothing:
I am curious if there is a way to create a swift class or struct based on a list of properties.
Maybe have his script inserted somewhere in the build phases.
For example, have a local JSON file or something similar, to read from:
{"className":"Person", "name":"string", "age":"int" }
would create the struct:
struct Person {
let name: String
let age: Int
}
#! /bin/bash
gawk -F, '{
for (i = 1 ; i <= NF ; ++i)
{
split($i, arr, ":")
match(arr[1], /"(.*)"/, mat)
key=mat[1]
match(arr[2], /"(.*)"/, mat)
value=mat[1]
if (key ~ /className/)
{
struct_name=value
}
else
if (value != "")
{
contents[key]=value
}
}
}
END {
print "struct "struct_name" {"
for (key in contents)
{
print "\tlet "key": "contents[key]
}
print "}"
}' file
I have heard people say this alot that jq is better when dealing with json, but I have never tried that. So you should consider searching about jq if it helps.
The above gawk script should produce the desired output.
The same can be done with general awk or even normal bash scripts but doing it with gawk was a little easier.
All you need to do is redirect the output of the above scipt to the desired file. Like suppose you saved the script with name parser.
bash parser > pathtoyourapp/filename.swift
You can do the same in the above script as too like on the last line of script:
}' file > pathtoyourxcodeproject/controller/filename.swift
As you are making swift code, I assume you have a mac. You can install gawk by any of the package managers available for mac. The one I use is macports. After installing macports, you can install gawk by sudo port install gawk.
UPDATE:
As mentioned in the comments by trojanfoe, the project navigator won't update just by adding the file to the project directory. I am not sure about how to do that.
What I found after searching the net, this seems to do the job.

How do we refer to etc package from NixOS configuration?

I want to get a path, which leads to nixos /etc location (any one of /run/current-system/etc or /nix/store/hashhere-etc-1.0). I use this path to configure pppd connect script, some kind of the following,
environment.etc."huawei" =
{ text = ''
/dev/ttyUSB0
38400
lock
crtscts
nodetach
noipdefault
# Below here what I've struggled
connect ${pkgs.etc}/${environment.etc."huawei-script".target}
'';
mode = "0777";
target = "ppp/peers/huawei"; };
I have tried to write ${pkgs.etc} or ${system.build.etc} or even ${environment.etc} resulting errors.
The directory structure is actually relative, but I think it's safer to use absolute path.
/nix/store/...etc.../ppp/peers
|- huawei
|- huawei.d
|- huawei.sh
|- huawei.chat
You can refer to path to file in /nix/store/...etc... like this:
{ config, pkgs, lib, ... }:
{
environment.etc."test".text = "helo";
environment.etc."test2".text = "${config.environment.etc."test".source.outPath}";
}
Now I have in /etc/test2:
$ cat /etc/test2
/nix/store/1igc2rf011jmrr3cprsgbdp3hhm5d4l0-etc-test
If I understand correctly your problem is you simply need to pass the string value of the target attribute to the huawei.text connect directive. As per the description for the target attribute the value is a path relative to /etc so you should be able to either:
Make the value of the connect directive the string literal connect /etc/ppp/peers/huawei or
make the etc.huaweiattribute set a recursive one so that the attributes can refer to each other then do
environment.etc.huawei = rec {
target = "ppp/peers/huawei";
text = ''...
# Below here what I've struggled
connect ${target}
'';
};
Sorry, I was overlook a fact where NixOS actually map any files in /nix/store/...etc../ into the /etc itself.
So, to refer to a file, it is better to use /etc directly.
connect /etc/${environment.etc."huawei-script".target}

Is it possible to load more config files from an externalized config file in Grails?

Hypothetical situation:
I have downloaded a Grails application from the web as a WAR file, foo.war. In the documentation it says that I can put my own custom configuration in /foo.groovy, because this path is included in grails.config.locations in Config.groovy. I can dump all my custom config in that one file and life is good.
How, here's my problem... The configuration for FooApp is big and hairy, and I don't want it all in one file. I would like to break it up into /bar.groovy and /baz.groovy to keep things organized. Is there a way to specify something in /foo.groovy so that FooApp will also pick up /bar.groovy and /baz.groovy and process them?
I already tried appending paths to grails.config.locations in /foo.groovy, but Grails didn't like that and threw a nasty exception on startup. I'm not sure what other approach to take.
Edit for clarity:
grails-app/conf/Config.groovy looks like this:
grails.config.locations = ["file:/foo.groovy"]
Now, without modifying grails-app/conf/Config.groovy, and only by modifying /foo.groovy, is there a way to load more config files other than /foo.groovy?
You could slurp the additional config files within foo.groovy:
foo.groovy
port {
to {
somewhere=8080
another {
place=7070
}
}
}
host = new ConfigSlurper().parse(new File("bar.groovy").toURL())
bar.groovy
to {
somewhere="http://localhost/"
another {
place="https://another.place.com/"
}
}
So within your app you have:
assert grailsApplication.config.port.to.somewhere == 8080
assert grailsApplication.config.port.to.another.place == 7070
assert grailsApplication.config.host.to.somewhere == "http://localhost/"
assert grailsApplication.config.host.to.another.place == "https://another.place.com/"

Resources