Skip to content

Commit

Permalink
Merge branch 'main' of github.com:grafana/grizzly into create-mimir-c…
Browse files Browse the repository at this point in the history
…lient
  • Loading branch information
spinillos committed Apr 22, 2024
2 parents 35e4e03 + f7c171e commit ec98e66
Show file tree
Hide file tree
Showing 38 changed files with 223 additions and 146 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
*.orig
*.swp
.idea

/resources
24 changes: 24 additions & 0 deletions .golangci.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[linters]
disable-all = true
enable = [
"dogsled",
"errcheck",
"exportloopref",
"goconst",
"gocritic",
"gocyclo",
"goimports",
"goprintffuncname",
"gosimple",
"govet",
"ineffassign",
"misspell",
"nakedret",
"rowserrcheck",
"staticcheck",
"stylecheck",
"typecheck",
"unconvert",
"unused",
"whitespace"
]
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ GOX := $(BIN_DIR)/gox
DOCKER_COMPOSE := docker compose -f ./test-docker-compose/docker-compose.yml

lint:
test -z $$(gofmt -s -l cmd/ pkg/)
go vet ./...
docker run \
--rm \
--volume "$(shell pwd):/src" \
--workdir "/src" \
golangci/golangci-lint:v1.57 golangci-lint run ./... -v

run-test-image-locally: test-clean
$(DOCKER_COMPOSE) up --force-recreate --detach --remove-orphans --wait
Expand Down
6 changes: 4 additions & 2 deletions cmd/grr/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/grafana/grizzly/pkg/grizzly/notifier"
"github.com/hashicorp/go-multierror"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
terminal "golang.org/x/term"
)

const generalFolderUID = "general"
Expand Down Expand Up @@ -508,7 +508,9 @@ func configCmd() *cli.Command {
func initialiseCmd(cmd *cli.Command, opts *Opts) *cli.Command {
// Keep the old flags for backwards compatibility
cmd.Flags().BoolVarP(&opts.Directory, "directory", "d", false, "treat resource path as a directory")
cmd.Flags().MarkDeprecated("directory", "now it is inferred from the operating system")
if err := cmd.Flags().MarkDeprecated("directory", "now it is inferred from the operating system"); err != nil {
log.Fatal(err)
}

cmd.Flags().StringSliceVarP(&opts.Targets, "target", "t", nil, "resources to target")
cmd.Flags().StringSliceVarP(&opts.JsonnetPaths, "jpath", "J", getDefaultJsonnetFolders(), "Specify an additional library search dir (right-most wins)")
Expand Down
36 changes: 24 additions & 12 deletions docs/content/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ To interact with Grafana Cloud Prometheus (aka Mimir), use these settings:

```sh
grr config set mimir.address https://mimir.example.com # URL for Mimir instance or Grafana Cloud Prometheus instance
grr config set mimir.tenant-id "myTenant" # Tenant ID for your Grafana Cloud Prometheus account
grr config set mimir.tenant-id myTenant # Tenant ID for your Grafana Cloud Prometheus account
grr config set mimir.api-key abcdef12345 # Authentication token (if you are using Grafana Cloud)
```

Expand All @@ -56,8 +56,10 @@ grr config set synthetic-monitoring.token abcdef123456 # API key (must have Metr
grr config set synthetic-monitoring.stack-id 123 # Grafana stack ID
grr config set synthetic-monitoring.metrics-id 123 # Metrics instance ID
grr config set synthetic-monitoring.logs-id 123 # Logs instance ID
grr config set synthetic-monitoring.url https://synthetic-monitoring-api.grafana.net # Synthetic Monitoring instance URL
```
Your stack ID is the number at the end of the url when you view your Grafana instance details, ie. `grafana.com/orgs/myorg/stacks/123456` would be `123456`. Your metrics and logs ID's are the `User` when you view your Prometheus or Loki instance details in Grafana Cloud.
You can find your instance URL under your Synthetic Monitoring configuration.

## Configuring Targets
Grizzly supports a number of resource types (`grr providers` will list those supported). Often, however, we do not
Expand Down Expand Up @@ -136,37 +138,47 @@ In some circumstances (e.g. when used within automated pipelines) it makes sense
with environment variables as opposed to contexts. Environment variables, when set, take precedence over
Grizzly contexts as described above. Below are the variables that can be used for this.

| Name | Description | Required | Default |
| --- | --- | --- | --- |
| `GRAFANA_URL` | Fully qualified domain name of your Grafana instance. | true | - |
| `GRAFANA_USER` | Basic auth username if applicable. | false | `api_key` |
| `GRAFANA_TOKEN` | Basic auth password or API token. | false | - |
| Name | Description | Required | Default |
|-----------------|-------------------------------------------------------|----------|-----------|
| `GRAFANA_URL` | Fully qualified domain name of your Grafana instance. | true | - |
| `GRAFANA_USER` | Basic auth username if applicable. | false | `api_key` |
| `GRAFANA_TOKEN` | Basic auth password or API token. | false | - |

See Grafana's [Authentication API
docs](https://grafana.com/docs/grafana/latest/http_api/auth/) for more info.

## Grafana Cloud Prometheus
To interact with Grafana Cloud Prometheus, you must have these environment variables set:

<<<<<<< HEAD
| Name | Description | Required |
|--------------------| --- |----------|
| `MIMIR_ADDRESS` | URL for Grafana Cloud Prometheus instance | true |
| `MIMIR_TENANT_ID` | Tenant ID for your Grafana Cloud Prometheus account | true |
| `MIMIR_API_KEY` | Authentication token/api key | false |
=======
| Name | Description | Required |
|--------------------|-----------------------------------------------------|----------|
| `CORTEX_ADDRESS` | URL for Grafana Cloud Prometheus instance | true |
| `CORTEX_TENANT_ID` | Tenant ID for your Grafana Cloud Prometheus account | true |
| `CORTEX_API_KEY` | Authentication token/api key | true |
>>>>>>> f7c171e48e49970e97686a84c2d505c742b5bc9a
Note, this will also work with other Mimir installations, alongside Grafana Cloud Prometheus.

## Grafana Synthetic Monitoring
To interact with Grafana Synthetic Monitoring, you must have these environment variable set:

| Name | Description | Required |
| --- | --- | --- |
| `GRAFANA_SM_TOKEN` | Authentication token/api key (must have MetricsPublisher permissions) | true |
| `GRAFANA_SM_STACK_ID` | Grafana instance/stack ID | true |
| `GRAFANA_SM_LOGS_ID` | Logs instance ID | true |
| `GRAFANA_SM_METRICS_ID` | Metrics instance ID | true |
| Name | Description | Required |
|-------------------------|-----------------------------------------------------------------------|----------|
| `GRAFANA_SM_TOKEN` | Authentication token/api key (must have MetricsPublisher permissions) | true |
| `GRAFANA_SM_STACK_ID` | Grafana instance/stack ID | true |
| `GRAFANA_SM_LOGS_ID` | Logs instance ID | true |
| `GRAFANA_SM_METRICS_ID` | Metrics instance ID | true |
| `GRAFANA_SM_URL` | Synthetic Monitoring instance URL | true |

Your stack ID is the number at the end of the url when you view your Grafana instance details, ie. `grafana.com/orgs/myorg/stacks/123456` would be `123456`. Your metrics and logs ID's are the `User` when you view your Prometheus or Loki instance details in Grafana Cloud.
You can find your instance URL under your Synthetic Monitoring configuration.

# Grizzly configuration file
To get the path of the config file:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
2 changes: 1 addition & 1 deletion integration/folder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestFolders(t *testing.T) {

t.Run("get remote folder - not found", func(t *testing.T) {
_, err := handler.GetByUID("dummy")
require.ErrorContains(t, err, "Couldn't fetch folder 'dummy' from remote: not found")
require.ErrorContains(t, err, "couldn't fetch folder 'dummy' from remote: not found")
})

t.Run("get folders list", func(t *testing.T) {
Expand Down
1 change: 0 additions & 1 deletion integration/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func TestPull(t *testing.T) {
assert.FileExists(t, filepath.Join(pullDir, "dashboards", "abcdefghi", "dashboard-ReciqtgGk.yaml"))
assert.DirExists(t, filepath.Join(pullDir, "datasources"))
assert.DirExists(t, filepath.Join(pullDir, "folders"))

},
})
})
Expand Down
37 changes: 23 additions & 14 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import (
)

const (
API_VERSION = "v1alpha1"
CURRENT_CONTEXT = "current-context"
CurrentContextSetting = "current-context"
)

func Initialise() {
Expand All @@ -38,6 +37,7 @@ func override(v *viper.Viper) {
"synthetic-monitoring.stack-id": "GRAFANA_SM_STACK_ID",
"synthetic-monitoring.logs-id": "GRAFANA_SM_LOGS_ID",
"synthetic-monitoring.metrics-id": "GRAFANA_SM_METRICS_ID",
"synthetic-monitoring.url": "GRAFANA_SM_URL",

"mimir.address": "MIMIR_ADDRESS",
"mimir.tenant-id": "MIMIR_TENANT_ID",
Expand Down Expand Up @@ -89,7 +89,7 @@ func Mock(values map[string]interface{}) {
}

func Import() error {
name := viper.GetString(CURRENT_CONTEXT)
name := viper.GetString(CurrentContextSetting)
if name == "" {
NewConfig()
return Import()
Expand All @@ -109,14 +109,16 @@ func Import() error {

func NewConfig() {
viper.Set("apiVersion", "v1alpha1")
viper.Set(CURRENT_CONTEXT, "default")
viper.Set(CurrentContextSetting, "default")
viper.Set("contexts.default.name", "default")
}

func GetContexts() error {
contexts := map[string]interface{}{}
currentContext := viper.GetString(CURRENT_CONTEXT)
viper.UnmarshalKey("contexts", &contexts)
currentContext := viper.GetString(CurrentContextSetting)
if err := viper.UnmarshalKey("contexts", &contexts); err != nil {
return err
}
keys := make([]string, 0, len(contexts))
for k := range contexts {
keys = append(keys, k)
Expand All @@ -134,18 +136,20 @@ func GetContexts() error {

func UseContext(context string) error {
contexts := map[string]interface{}{}
viper.UnmarshalKey("contexts", &contexts)
if err := viper.UnmarshalKey("contexts", &contexts); err != nil {
return err
}
for k := range contexts {
if k == context {
viper.Set(CURRENT_CONTEXT, context)
viper.Set(CurrentContextSetting, context)
return Write()
}
}
return fmt.Errorf("context %s not found", context)
}

func CurrentContext() (*Context, error) {
name := viper.GetString(CURRENT_CONTEXT)
name := viper.GetString(CurrentContextSetting)
if name == "" {
NewConfig()
return CurrentContext()
Expand All @@ -157,7 +161,9 @@ func CurrentContext() (*Context, error) {
}
override(ctx)
var context Context
ctx.Unmarshal(&context)
if err := ctx.Unmarshal(&context); err != nil {
return nil, err
}
context.Name = name
return &context, nil
}
Expand All @@ -166,20 +172,23 @@ var acceptableKeys = map[string]string{
"grafana.url": "string",
"grafana.token": "string",
"grafana.user": "string",
"grafana.insecure-skip-verify": "bool",
"grafana.tls-host": "string",
"mimir.address": "string",
"mimir.tenant-id": "string",
"mimir.api-key": "string",
"synthetic-monitoring.token": "string",
"synthetic-monitoring.stack-id": "int",
"synthetic-monitoring.metrics-id": "int",
"synthetic-monitoring.logs-id": "int",
"synthetic-monitoring.url": "string",
"targets": "[]string",
"output-format": "string",
"only-spec": "bool",
}

func Get(path, outputFormat string) (string, error) {
ctx := viper.GetString(CURRENT_CONTEXT)
ctx := viper.GetString(CurrentContextSetting)
fullPath := fmt.Sprintf("contexts.%s", ctx)
if path != "" {
fullPath = fmt.Sprintf("%s.%s", fullPath, path)
Expand All @@ -202,7 +211,7 @@ func Get(path, outputFormat string) (string, error) {
func Set(path string, value string) error {
for key, typ := range acceptableKeys {
if path == key {
ctx := viper.GetString(CURRENT_CONTEXT)
ctx := viper.GetString(CurrentContextSetting)
fullPath := fmt.Sprintf("contexts.%s.%s", ctx, path)
var val any
switch typ {
Expand Down Expand Up @@ -241,7 +250,7 @@ func Unset(path string) error {
return fmt.Errorf("%s is not a valid path", path)
}

ctx := viper.GetString(CURRENT_CONTEXT)
ctx := viper.GetString(CurrentContextSetting)
fullPath := fmt.Sprintf("contexts.%s.%s", ctx, path)

if !viper.InConfig(fullPath) {
Expand Down Expand Up @@ -272,7 +281,7 @@ func deleteValue(settings map[string]any, deleteKey string, iteratorKeys ...stri
}

func CreateContext(name string) error {
viper.Set(CURRENT_CONTEXT, name)
viper.Set(CurrentContextSetting, name)
viper.Set(fmt.Sprintf("contexts.%s.name", name), name)
return Write()
}
Expand Down
11 changes: 7 additions & 4 deletions pkg/config/model.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package config

type GrafanaConfig struct {
URL string `yaml:"url" mapstructure:"url"`
User string `yaml:"user" mapstructure:"user"`
Token string `yaml:"token" mapstructure:"token"`
URL string `yaml:"url" mapstructure:"url"`
User string `yaml:"user" mapstructure:"user"`
Token string `yaml:"token" mapstructure:"token"`
InsecureSkipVerify bool `yaml:"insecure-skip-verify" mapstructure:"insecure-skip-verify"`
TLSHost string `yaml:"tls-host" mapstructure:"tls-host"`
}

type MimirConfig struct {
Address string `yaml:"address" mapstructure:"address"`
TenantID string `yaml:"tenant-id" mapstructure:"tenant-id"`
ApiKey string `yaml:"api-key" mapstructure:"api-key"`
APIKey string `yaml:"api-key" mapstructure:"api-key"`
}

type SyntheticMonitoringConfig struct {
Token string `yaml:"token" mapstructure:"token"`
StackID int64 `yaml:"stack-id" mapstructure:"stack-id"`
LogsID int64 `yaml:"logs-id" mapstructure:"logs-id"`
MetricsID int64 `yaml:"metrics-id" mapstructure:"metrics-id"`
URL string `yaml:"url" mapstructure:"url"`
}

type Context struct {
Expand Down
Loading

0 comments on commit ec98e66

Please sign in to comment.