/
insights_operator_prometheus.go
186 lines (156 loc) · 5.34 KB
/
insights_operator_prometheus.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
Copyright © 2020, 2021, 2022 Pavel Tisnovsky
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
// Creates animation from static GIF image + set of programmed rules. That
// animation displays the data flow from Insights Operator to OCP WebConsole
// via Prometheus metrics.
// Link to generated documentation for this script:
// https://redhatinsights.github.io/insights-results-aggregator-utils/packages/insights_operator_prometheus.html
import (
"bufio"
"image"
"image/color"
"image/draw"
"image/gif"
"os"
)
// readOriginal function tries to read the GIF file that contains the static
// input image. Animation to be created are based on this source image.
func readOriginal(filename string) *image.Paletted {
// try to open the file specified by its name and check for any error
fin, err := os.Open(filename) // #nosec G304
if err != nil {
panic(err)
}
// file needs to be closed properly before that function ends
defer func() {
// try to close the file and check for any error that might
// happened
err := fin.Close()
if err != nil {
panic(err)
}
}()
reader := bufio.NewReader(fin)
// try to decode GIF frames from reader
img, err := gif.Decode(reader)
if err != nil {
panic(err)
}
// we have to use image.Paletted, so it is needed to convert the image
// into desired format
return img.(*image.Paletted)
}
// writeAnimation function stores all images into GIF file. Each image (from
// `images` parameter) is stored as a GIF frame and delays between frames are
// provided by `delays` parameter. Please note that it would be possible to
// create smaller GIF image by applying external tool like `gifsicle` to the
// generated GIF file.
func writeAnimation(filename string, images []*image.Paletted, delays []int) {
// try to open the file specified by its name and check for any error
outfile, err := os.Create(filename)
if err != nil {
panic(err)
}
// file needs to be closed properly before that function ends
defer func() {
// try to close the file and check for any error that might
// happened
err := outfile.Close()
if err != nil {
panic(err)
}
}()
// try to encode all GIF frames to output file
err = gif.EncodeAll(outfile, &gif.GIF{
Image: images,
Delay: delays,
})
// check if any error occured during EncodeAll operation
if err != nil {
panic(err)
}
}
// drawAnt function draws one "marching" ant into the frame represented by
// `img` parameter. Position (center of ant) of marching ant is specified by
// `x0` and `y0`, and the color is selected by `col` parameter. There exists
// four colors that can be used.
//
// TODO: make color palette completely configurable
func drawAnt(img *image.Paletted, x0 int, y0 int, col int) {
// standard color palette with four colors
palette := make(map[int]color.RGBA, 4)
// initialize color palette
palette[0] = color.RGBA{200, 100, 100, 255}
palette[1] = color.RGBA{00, 200, 00, 255}
palette[2] = color.RGBA{255, 255, 255, 255}
palette[3] = color.RGBA{105, 62, 200, 255}
// rectangle that represents ant
r := image.Rect(x0, y0, x0+10, y0+10)
// draw the rectangle using selected color
draw.Draw(img, r, &image.Uniform{palette[col]}, image.ZP, draw.Src)
}
// drawMarchingAnts functions draws all "marching" ants into the frame
// represented by `img` parameter. Currently marching ants are placed on four
// lines (two horizontal ones and two vertical ones).
//
// TODO: make this part completely configurable
func drawMarchingAnts(img *image.Paletted, step int) {
// first vertical line (to WebConsole)
for y := 239; y > 100; y -= 20 {
drawAnt(img, 82-4, y+(20-step)-20, 0)
}
// second vertical line
for y := 340; y < 590; y += 20 {
drawAnt(img, 194-6, y-step+3, 1)
}
// first horizontal line
for x := 194; x < 574; x += 20 {
drawAnt(img, x-step+10+4, 590-5, 1)
}
// third vertical line
for y := 341; y < 580; y += 20 {
drawAnt(img, 194-6+20, y-(20-step)+3, 3)
}
// horizontal line
for x := 194; x < 554; x += 20 {
drawAnt(img, x-(20-step)+30+4, 590-5-20, 3)
}
// special unmovable blocks
drawAnt(img, 82-4, 240, 1)
drawAnt(img, 574, 590-5, 3)
}
// main function is called by runtime after the tool has been started
// from command line.
func main() {
// frames representing the whole animation stored in GIF file
var images []*image.Paletted
// delays between frames
var delays []int
// only 20 frames needs to be created
steps := 20
// create all frames to generate final animation
for step := 0; step < steps; step++ {
// read original image
// TODO: make the file name configurable
img := readOriginal("io-pulling-prometheus.gif")
// draw new frame based on original image
drawMarchingAnts(img, step)
// and add the frame into animation
images = append(images, img)
delays = append(delays, 10)
}
// write resulting animation (set of frames) into GIF file
// TODO: make the file name configurable
writeAnimation("2.gif", images, delays)
}