-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a80f3ac
commit 2b076b7
Showing
12 changed files
with
382 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
local main = import '%s'; | ||
|
||
local convert(main, apiVersion) = { | ||
local makeResource(kind, name, spec=null, data=null, metadata={}) = { | ||
apiVersion: apiVersion, | ||
kind: kind, | ||
metadata: { | ||
name: std.strReplace(std.strReplace(std.strReplace(name, '.json', ''), '.yaml', ''), '.yml', ''), | ||
} + metadata, | ||
[if spec != null then 'spec']: spec, | ||
[if data != null then 'data']: std.manifestJsonEx(data, ' '), | ||
}, | ||
|
||
local formatUID(name) = | ||
local is_alpha(x) = std.member("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_", x); | ||
std.join("", std.filter(is_alpha, std.stringChars(name))), | ||
|
||
grafana: { | ||
folders: | ||
if ('grafanaDashboardFolder' in main) && main.grafanaDashboardFolder != 'General' | ||
then makeResource( | ||
'DashboardFolder', | ||
formatUID(main.grafanaDashboardFolder), | ||
spec={ | ||
title: main.grafanaDashboardFolder, | ||
}), | ||
dashboards: | ||
local uid(k, dashboard) = | ||
if std.objectHasAll(dashboard, "uid") | ||
then dashboard.uid | ||
else k; | ||
local folder = | ||
if 'grafanaDashboardFolder' in main | ||
then formatUID(main.grafanaDashboardFolder) | ||
else 'General'; | ||
local fromMap(dashboards, folder) = [ | ||
makeResource( | ||
'Dashboard', | ||
uid(k, dashboards[k]), | ||
spec=dashboards[k] + { | ||
uid::'', | ||
}, | ||
metadata={ folder: folder } | ||
) | ||
for k in std.objectFields(dashboards) | ||
]; | ||
if 'grafanaDashboards' in main | ||
then fromMap(main.grafanaDashboards, folder) | ||
else {}, | ||
|
||
datasources: | ||
local fromMap(datasources) = [ | ||
makeResource( | ||
'Datasource', | ||
k, | ||
spec=datasources[k] + { | ||
name:: '' | ||
}, | ||
) | ||
for k in std.objectFields(datasources) | ||
]; | ||
if 'grafanaDatasources' in main | ||
then fromMap(main.grafanaDatasources) | ||
else {}, | ||
}, | ||
|
||
prometheus: | ||
local forceNamespace(contents) = | ||
// if rulesGroup isn't namespaced (monitoring-mixins), then put them into default namespace | ||
if std.objectHas(contents, 'groups') then | ||
// no namespace, wrap into default namespace | ||
{ 'grizzly_rules': contents } | ||
else | ||
// already has namespace | ||
contents | ||
; | ||
local fromMap(key) = | ||
if key in main then | ||
local allNamespaced = forceNamespace(main[key]); | ||
[ | ||
|
||
makeResource( | ||
'PrometheusRuleGroup', | ||
g.name, | ||
spec={ | ||
rules: g.rules, | ||
}, | ||
metadata={ namespace: ns } | ||
) | ||
|
||
for ns in std.objectFields(allNamespaced) | ||
for g in allNamespaced[ns].groups | ||
] | ||
else []; | ||
fromMap('prometheusRules') | ||
+ fromMap('prometheusAlerts'), | ||
|
||
syntheticMonitoringChecks: | ||
local fromMap(checks) = [ | ||
makeResource( | ||
'SyntheticMonitoringCheck', | ||
checks[k].job, | ||
spec=checks[k] + { | ||
job::'', | ||
}, | ||
metadata={type: std.objectFields(checks[k].settings)[0]} | ||
) | ||
for k in std.objectFields(checks) | ||
]; | ||
if 'syntheticMonitoring' in main | ||
then fromMap(main.syntheticMonitoring) | ||
else {}, | ||
}; | ||
convert(main, 'grizzly.grafana.com/v1alpha1') + main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package encoding | ||
|
||
import ( | ||
"encoding/json" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
func MarshalToJSON(spec map[string]interface{}, filename string) error { | ||
j, err := json.MarshalIndent(spec, "", " ") | ||
if err != nil { | ||
return err | ||
} | ||
return writeFile(filename, j) | ||
} | ||
|
||
func writeFile(filename string, content []byte) error { | ||
dir := filepath.Dir(filename) | ||
err := os.MkdirAll(dir, 0755) | ||
if err != nil { | ||
return err | ||
} | ||
err = os.WriteFile(filename, content, 0644) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package encoding | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/google/go-jsonnet" | ||
"github.com/grafana/tanka/pkg/jsonnet/native" | ||
"github.com/grafana/tanka/pkg/kubernetes/manifest" | ||
"github.com/grafana/tanka/pkg/process" | ||
) | ||
|
||
//go:embed grizzly.jsonnet | ||
var script string | ||
|
||
// ParseJsonnet evaluates a jsonnet file and parses it into an object tree | ||
func ParseJsonnet(jsonnetFile string, jsonnetPaths []string) (map[string]manifest.Manifest, error) { | ||
if _, err := os.Stat(jsonnetFile); os.IsNotExist(err) { | ||
return nil, fmt.Errorf("file does not exist: %s", jsonnetFile) | ||
} | ||
|
||
script := fmt.Sprintf(script, jsonnetFile) | ||
vm := jsonnet.MakeVM() | ||
currentWorkingDirectory, err := os.Getwd() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
vm.Importer(newExtendedImporter(jsonnetFile, currentWorkingDirectory, jsonnetPaths)) | ||
for _, nf := range native.Funcs() { | ||
vm.NativeFunction(nf) | ||
} | ||
|
||
result, err := vm.EvaluateAnonymousSnippet(jsonnetFile, script) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var data interface{} | ||
if err := json.Unmarshal([]byte(result), &data); err != nil { | ||
return nil, err | ||
} | ||
|
||
extracted, err := process.Extract(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Unwrap *List types | ||
if err := process.Unwrap(extracted); err != nil { | ||
return nil, err | ||
} | ||
|
||
return extracted, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package encoding | ||
|
||
import ( | ||
"path/filepath" | ||
|
||
"github.com/google/go-jsonnet" | ||
) | ||
|
||
// ExtendedImporter does stuff | ||
type ExtendedImporter struct { | ||
loaders []importLoader // for loading jsonnet from somewhere. First one that returns non-nil is used | ||
processors []importProcessor // for post-processing (e.g. yaml -> json) | ||
} | ||
|
||
type importLoader func(importedFrom, importedPath string) (c *jsonnet.Contents, foundAt string, err error) | ||
|
||
// importProcessor are executed after the file import and may modify the result | ||
// further | ||
type importProcessor func(contents, foundAt string) (c *jsonnet.Contents, err error) | ||
|
||
// newFileLoader returns an importLoader that uses jsonnet.FileImporter to source | ||
// files from the local filesystem | ||
func newFileLoader(fi *jsonnet.FileImporter) importLoader { | ||
return func(importedFrom, importedPath string) (contents *jsonnet.Contents, foundAt string, err error) { | ||
var c jsonnet.Contents | ||
c, foundAt, err = fi.Import(importedFrom, importedPath) | ||
return &c, foundAt, err | ||
} | ||
} | ||
|
||
func newExtendedImporter(jsonnetFile, path string, jpath []string) *ExtendedImporter { | ||
absolutePaths := make([]string, len(jpath)*2+1) | ||
absolutePaths = append(absolutePaths, path) | ||
jsonnetDir := filepath.Dir(jsonnetFile) | ||
for _, p := range jpath { | ||
if !filepath.IsAbs(p) { | ||
p = filepath.Join(jsonnetDir, p) | ||
} | ||
absolutePaths = append(absolutePaths, p) | ||
} | ||
for _, p := range jpath { | ||
if !filepath.IsAbs(p) { | ||
p = filepath.Join(path, p) | ||
} | ||
absolutePaths = append(absolutePaths, p) | ||
} | ||
return &ExtendedImporter{ | ||
loaders: []importLoader{ | ||
newFileLoader(&jsonnet.FileImporter{ | ||
JPaths: absolutePaths, | ||
})}, | ||
processors: []importProcessor{}, | ||
} | ||
} | ||
|
||
// Import implements the functionality offered by the ExtendedImporter | ||
func (i *ExtendedImporter) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) { | ||
// load using loader | ||
for _, loader := range i.loaders { | ||
c, f, err := loader(importedFrom, importedPath) | ||
if err != nil { | ||
return jsonnet.Contents{}, "", err | ||
} | ||
if c != nil { | ||
contents = *c | ||
foundAt = f | ||
break | ||
} | ||
} | ||
|
||
// check if needs postprocessing | ||
for _, processor := range i.processors { | ||
c, err := processor(contents.String(), foundAt) | ||
if err != nil { | ||
return jsonnet.Contents{}, "", err | ||
} | ||
if c != nil { | ||
contents = *c | ||
break | ||
} | ||
} | ||
|
||
return contents, foundAt, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package encoding | ||
|
||
import ( | ||
"io" | ||
"math" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
|
||
"github.com/goccy/go-yaml" | ||
) | ||
|
||
// NewYAMLDecoder returns a YAML decoder configured to unmarshal data from the given reader. | ||
func NewYAMLDecoder(reader io.Reader) *yaml.Decoder { | ||
return yaml.NewDecoder(reader) | ||
} | ||
|
||
// MarshalYAML takes an input and renders as a YAML string. | ||
func MarshalYAML(input any) (string, error) { | ||
y, err := yaml.MarshalWithOptions( | ||
input, | ||
yaml.Indent(4), | ||
yaml.IndentSequence(true), | ||
yaml.UseLiteralStyleIfMultiline(true), | ||
yaml.CustomMarshaler[float64](func(v float64) ([]byte, error) { | ||
// goccy/go-yaml tends to add .0 suffixes to floats, even when they're not required. | ||
// To preserve consistency with go-yaml/yaml, this custom marshaler disables that feature. | ||
|
||
if v == math.Inf(0) { | ||
return []byte(".inf"), nil | ||
} | ||
if v == math.Inf(-1) { | ||
return []byte("-.inf"), nil | ||
} | ||
if math.IsNaN(v) { | ||
return []byte(".nan"), nil | ||
} | ||
|
||
return []byte(strconv.FormatFloat(v, 'g', -1, 64)), nil | ||
}), | ||
) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return string(y), nil | ||
} | ||
|
||
// MarshalYAMLFile takes an input and renders it to a file as a YAML string. | ||
func MarshalYAMLFile(input any, filename string) error { | ||
y, err := MarshalYAML(input) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
dir := filepath.Dir(filename) | ||
err = os.MkdirAll(dir, 0755) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = os.WriteFile(filename, []byte(y), 0644) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// UnmarshalYAML takes YAML content as input unmarshals it into the destination. | ||
func UnmarshalYAML(input []byte, destination any) error { | ||
return yaml.Unmarshal(input, destination) | ||
} |
Oops, something went wrong.