Get iterator index in go template (consul-template) - loops

I'm trying to get a simple index that I can append to output of a Go template snippet using consul-template. Looked around a bit and couldn't figure out the simple solution. Basically, given this input
backend web_back
balance roundrobin
{{range service "web-busybox" "passing"}}
server {{ .Name }} {{ .Address }}:80 check
{{ end }}
I would like to see web-busybox-n 10.1.1.1:80 check
Where n is the current index in the range loop. Is this possible with range and maps?

There is no iteration number when ranging over maps (only a value and an optional key). You can achieve what you want with custom functions.
One possible solution that uses an inc() function to increment an index variable in each iteration:
func main() {
t := template.Must(template.New("").Funcs(template.FuncMap{
"inc": func(i int) int { return i + 1 },
}).Parse(src))
m := map[string]string{
"one": "first",
"two": "second",
"three": "third",
}
fmt.Println(t.Execute(os.Stdout, m))
}
const src = `{{$idx := 0}}
{{range $key, $value := .}}
index: {{$idx}} key: {{ $key }} value: {{ $value }}
{{$idx = (inc $idx)}}
{{end}}`
This outputs (try it on the Go Payground) (compacted output):
index: 0 key: one value: first
index: 1 key: three value: third
index: 2 key: two value: second
See similar / related questions:
Go template remove the last comma in range loop
Join range block in go template
Golang code to repeat an html code n times

The example below looks for all servers providing the pmm service, but will only create the command to register with the first pmm server found (when $index == 0)
{{- range $index, $service := service "pmm" -}}
{{- if eq $index 0 -}}
sudo pmm-admin config --server {{ $service.Address }}
{{- end -}}
{{- end -}}

Related

Ansible loop over a list of dicts with count as a key

Say I have a list of dicts like the following:
my_dummy_list:
- { name: x, count: 2 }
- { name: y, count: 5 }
- { name: z, count: 1 }
...
I need to iterate over it so a task gets applied the count times for each name.
I tried to use with_subelements, but it requires the second argument to be a list, and thus I must transform counts to range() like
my_dummy_list:
- { name: x, count: "{{ range(1, 3) | list }} }
- { name: y, count: "{{ range(1, 6) | list }} }
...
which is unreadable, unobvious and mistakable, I really want to avoid it.
I also had an idea of using templating but it would overencumber the playbook, it's already pretty much complicated.
Will appreciate any help.
PS my task looks as follows (very simplified)
- name: my_task
shell: echo {{item.0.name}}_{{item.1}}
with_subelements:
- "{{ my_dummy_list }}"
- count
and I expect the following output
x_1
x_2
y_1
...
y_5
z_1

TICKScript never resets Level to OK

I’m writing a TickScript that acts on a series of points that can have exactly two outcomes.
Either the result is pass or “not pass” (usually some variant of exit NUM).
The script I have looks sort of like this:
// RP: autogen
// Monitor the result of updates
// WARNING if the result is anything other than pass
batch
|query('''SELECT * FROM "mydb"."autogen"."measurement"''')
.period(25h)
.every(24h)
.groupBy('host')
|alert()
.id('kapacitor/{{ .TaskName }}/{{ .Group }}')
.infoReset(lambda: TRUE)
.warn(lambda: "result" != 'pass')
.message(
'{{ index .Tags "host" }}' +
'{{ if eq .Level "OK" }} are updating again.' +
'{{ else }}' +
'are failing to update.' +
'{{ end }}'
)
.idField('id')
.levelField('level')
.messageField('description')
.stateChangesOnly()
#alertFilterAdapter()
#alertFilter()
The script does seem to sort of do its thing, but has a critical issue of never setting the Level back to OK.
If I feed influx these 4 points:
time host name result
---- ---- ---- ------
1544079584447374994 fakeS176 /usr/bin/yum update -y pass
1544079584447374994 fakeS177 /usr/bin/yum update -y exit 1
1544129084447375177 fakeS176 /usr/bin/yum update -y exit 1
1544129084447375177 fakeS177 /usr/bin/yum update -y pass
I would expect 1 warning, and 1 OK. Where all of the timestamps listed above are within the 25 hour period.
However what actually happens is that I get 2 warns and no OKs.
Could someone give some advice on how to move forward?
Update - a coworker told me about a nodes I had no idea about. Adding a last() node and adding an as(), then removing the infoReset() node seemed to do it.
// RP: autogen
// Monitor the result of updates
// WARNING if the result is anything other than pass
batch
|query('''SELECT * FROM "mydb"."autogen"."measurement"''')
.period(25h)
.every(24h)
.groupBy('host')
|last('result')
.as('result')
|alert()
.id('kapacitor/{{ .TaskName }}/{{ .Group }}')
.warn(lambda: "result" != 'pass')
.message(
'{{ index .Tags "host" }}' +
'{{ if eq .Level "OK" }} are updating again.' +
'{{ else }}' +
'are failing to update.' +
'{{ end }}'
)
.idField('id')
.levelField('level')
.messageField('description')
.stateChangesOnly()
#alertFilterAdapter()
#alertFilter()
Screw this blasted language.

accessing array content whithin for loop - Auto Hot Key AHK

I am trying to extract the content of an array member at index i into a variable and then append it to a file.
How do I do that ?
Here is what I tried but it will not take the content of cgi[i]
firstrun(){
GuiControlGet, cgiDelay,,_cgiDelay
returnCode:=[]
for i in cgi {
msg := "http://" ip "/Nexus.cgi?session=" session "&action=" firstRunCgi[i] "&tokenoverride=1"
sendToHttp(msg)
getRespond()
returnCode[i]:=parseReturnCode()
if (returnCode[i] !=0){
addTextToGui("Setting 1st run Fail #: " i "`terrorCode: " returnCode[i] "`t"firstRunCgi[i])
txt = `ncgi[i],skipped
FileAppend, %txt%, cgiLog.txt
cgi[i] :=""
}
else{
; addTextToGui("Setting 1st run OK #: " i "`terrorCode: " returnCode[i] "`t"firstRunCgi[i])
}
Sleep (cgiDelay)
}
}
now sure why and how but this fixed it:
txt := "`n" cgi[i] ",skipped"
FileAppend, %txt%, cgiLog.csv
See here: AutoHotKey: How to access array with counter variable
In your Example you posted: For i in cgi the variable i contains your Key/Index, so you can access a Value in cgi Array with the Key/Index by: value := cgi[i]
Alternatatively you can declare two variables to hold both your Key/Index and Value directly in your For loop like so:
cgi := ["Hello", "World"]
For i, v in cgi ; Notice the comma
MsgBox % "This is the Key/Index: " i
. "`nThis is the Value from the For loop: " v
. "`nThis Value was accessed using Key/Index: " cgi[i]

Extracting values from text file using autohotkey

I have a small text file that I would like to extract some values using autohotkey.
Example of text file's content:
Date: 2014-12-02 12:06:47
Study: G585.010.411
Image: 6.24
Tlbar: 2.60
Notes: 0.74
My current code:
FileReadLine, datetime, C:\File.txt, 1
datedsp := SubStr(datetime, 7)
Sleep 500
FileReadLine, study, C:\File.txt, 2
studydsp := SubStr(study, 7)
Sleep 500
FileReadLine, image, C:\File.txt, 3
imgdsp := SubStr(image, 7)
Sleep 500
FileReadLine, notes, C:\File.txt, 5
notesdsp := SubStr(notes, 7)
Sleep 500
MsgBox %datedsp%
MsgBox %studydsp%
MsgBox %imgdsp%
MsgBox %notesdsp%
All I want to do is to grab the value of each of those lines and assign it to variables. For example, studydsp value would be G58500411, imagedsp value would be 6.24, datedsp value would be 2014-12-02 12:06:47.
Is there anyway to achieve this in a better way?
Possible issues with this code:
I am unable to get the string from the date line perhaps due to a space at
the beginning(?)
I can't get the SubStr value of either date (refer to 1st issue) or
study (perhaps because of special characters?)
You can use FileRead and RegExMatch
var:="
(
Date: 2014-12-02 12:06:47
Study: G585.010.411
Image: 6.24
Tlbar: 2.60
Notes: 0.74
)"
;~ FileRead, var, C:\file.txt
pos:=1
while pos := RegExMatch(var, "\s?(.*?):(.*?)(\v|\z)", m, pos+StrLen(m))
%m1% := m2
msgbox % "Date holds " date
. "`nStudy holds " Study
. "`nImage holds " Image
. "`nTlbar holds " Tlbar
. "`nNotes holds " Notes
Just remove the var part and uncomment the fileread line, at least thats one way to do it to :)
hope it helps
Basically the same as #blackholyman's answer, but using an object based approach by building a value map:
fileCont =
(
Date: 2014-12-02 12:06:47
Study: G585.010.411
Image: 6.24
Tlbar: 2.60
Notes: 0.74
)
valueMap := {}
; Alternatively, use: Loop, Read, C:\file.txt
Loop, Parse, fileCont, `r`n
{
RegExMatch(A_LoopField, "(.*?):(.*)", parts)
; Optionally make keys always lower case:
; StringLower, parts1, parts1
valueMap[Trim(parts1)] := Trim(parts2)
}
msgbox % "Date = " valueMap["Date"]
. "`nImage = " valueMap["Image"]
; We can also iterate over the map
out := ""
for key, val in valueMap
{
out .= key "`t= " val "`n"
}
msgbox % out

My datastore has no index entries on appspot?

First I create a index.yaml
- kind: Tarifa 2014
ancestor: yes
properties:
- name: Date
direction: desc
- kind: Tarifa 2014
ancestor: yes
properties:
- name: Division
- name: Heat
- name: Date
direction: desc
Then I put some data in
key := datastore.NewKey(s.Context, "Tarifa 2014", "", 0, s.Root)
key, err = datastore.Put(s.Context, key, m)
Simple queries work,
key := datastore.NewKey(s.Context, "Tarifa 2014", "", id, s.Root)
err = datastore.Get(s.Context, key, &m)
but this does do not because my index is still empty?
datastore.NewQuery(e).Ancestor(s.Root).Filter("Division =", d).Filter("Heat =", h).Order("-Date")
Same for this, it also does not work?
datastore.NewQuery(e).Ancestor(s.Root).Order("-Date")
My index looks like this on appspot.com?
My datastore looks like this on appspot.com
Note that on localhost:8080 all queries work fine?
For a reason that is not clear, if I use Namespace , indexed queries break on appspot.com
c2 := endpoints.NewContext(r)
c, err := appengine.Namespace(c2, "")
if err != nil {return err}
You need to use endpoints context directly without a namespace.
c := endpoints.NewContext(r)

Resources