Merge branch 'main' into kristina/static-transform-refIds
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
[build]
|
||||
bin = "./bin/grafana"
|
||||
bin = "./bin/grafana-air"
|
||||
args_bin = ["server", "-profile", "-profile-addr=127.0.0.1", "-profile-port=6000", "-profile-block-rate=1", "-profile-mutex-rate=5", "-packaging=dev", "cfg:app_mode=development"]
|
||||
cmd = "make GO_BUILD_DEV=1 build-backend"
|
||||
cmd = "make GO_BUILD_DEV=1 build-air"
|
||||
exclude_regex = ["_test.go", "_gen.go"]
|
||||
exclude_unchanged = true
|
||||
follow_symlink = true
|
||||
include_dir = ["apps", "conf", "devenv/dev-dashboards", "pkg", "public/views"]
|
||||
include_dir = ["apps", "conf", "pkg", "public/views"]
|
||||
include_ext = ["go", "ini", "toml", "html", "json"]
|
||||
stop_on_error = false
|
||||
stop_on_error = true
|
||||
send_interrupt = true
|
||||
kill_delay = 500
|
||||
|
||||
|
||||
+3
-1
@@ -32,7 +32,9 @@
|
||||
/devenv/README.md @grafana/docs-grafana
|
||||
|
||||
# START Technical documentation
|
||||
/.vale.ini @grafana/docs-tooling
|
||||
/.vale.ini @grafana/docs-tooling
|
||||
/AGENTS.md @grafana/docs-tooling
|
||||
|
||||
# `make docs` procedure and related workflows are owned @grafana/docs-tooling. Slack #docs.
|
||||
/docs/ @grafana/docs-tooling
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ permissions: {}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Feature toggles documentation is in sync with source
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -149,19 +149,11 @@ jobs:
|
||||
needs:
|
||||
- build-grafana
|
||||
steps:
|
||||
- id: vault-secrets
|
||||
uses: grafana/shared-workflows/actions/get-vault-secrets@main
|
||||
- id: get-github-token
|
||||
name: "create github app token"
|
||||
uses: grafana/shared-workflows/actions/create-github-app-token@eb02241ed0a92aff205feab8ac3afcdf51c757c8 # create-github-app-token-v0.2.0
|
||||
with:
|
||||
repo_secrets: |
|
||||
GRAFANA_DELIVERY_BOT_APP_PEM=delivery-bot-app:PRIVATE_KEY
|
||||
- name: Generate token
|
||||
id: generate_token
|
||||
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
|
||||
with:
|
||||
app_id: ${{ vars.DELIVERY_BOT_APP_ID }}
|
||||
private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }}
|
||||
repositories: '["grafana"]'
|
||||
permissions: '{"checks": "write"}'
|
||||
github_app: "delivery-bot-app"
|
||||
- uses: grafana/shared-workflows/actions/login-to-gar@main
|
||||
id: login-to-gar
|
||||
with:
|
||||
@@ -184,7 +176,7 @@ jobs:
|
||||
echo "IMAGE=${DOCKER_IMAGE}" >> "$GITHUB_ENV"
|
||||
- name: Add PR status check
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
GH_TOKEN: ${{ steps.get-github-token.outputs.token }}
|
||||
SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
gh api \
|
||||
|
||||
@@ -39,12 +39,14 @@ permissions: {}
|
||||
|
||||
jobs:
|
||||
# If called with version_type 'canary' or 'stable', build + publish to NPM
|
||||
# If called with version_type 'nightly', just tag the given version with nightly tag. It was already published by the canary build.
|
||||
# If called with version_type 'nightly', do nothing (we're not yet tagging them with the nightly tag)
|
||||
|
||||
publish:
|
||||
name: Publish NPM packages
|
||||
runs-on: github-hosted-ubuntu-x64-small
|
||||
if: inputs.version_type == 'canary' || inputs.version_type == 'stable'
|
||||
# Required for this workflow to have permission to publish NPM packages
|
||||
environment: npm-publish
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -130,18 +132,3 @@ jobs:
|
||||
env:
|
||||
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
||||
run: ./scripts/publish-npm-packages.sh --dist-tag "$NPM_TAG" --registry 'https://registry.npmjs.org/'
|
||||
|
||||
# TODO: finish this step
|
||||
tag-nightly:
|
||||
name: Tag nightly release
|
||||
runs-on: github-hosted-ubuntu-x64-small
|
||||
if: inputs.version_type == 'nightly'
|
||||
|
||||
steps:
|
||||
- name: Checkout workflow ref
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# TODO: tag the given release with nightly
|
||||
|
||||
|
||||
@@ -39,9 +39,10 @@ jobs:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
package-manager-cache: false # too large for GH's cache limits :-(
|
||||
- run: yarn install --immutable --check-cache
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps
|
||||
@@ -68,9 +69,10 @@ jobs:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
package-manager-cache: false # too large for GH's cache limits :-(
|
||||
- run: yarn install --immutable --check-cache
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
@@ -6,9 +6,13 @@ on:
|
||||
paths:
|
||||
- '**/*.cue'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: "ubuntu-latest"
|
||||
permissions:
|
||||
contents: read # clone repository
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v5"
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
# AGENTS.md
|
||||
|
||||
<!-- docs-ai-begin -->
|
||||
|
||||
<!-- version: 1.1.0 -->
|
||||
|
||||
## Documentation
|
||||
|
||||
Instructions for documentation authoring in Markdown files.
|
||||
|
||||
DOCS.md contains all the Docs AI toolkit docs in one file.
|
||||
|
||||
## Role
|
||||
|
||||
Act as an experienced software engineer and technical writer for Grafana Labs.
|
||||
|
||||
Write for software developers and engineers who understand general programming concepts.
|
||||
|
||||
Focus on practical implementation and clear problem-solving guidance.
|
||||
|
||||
### Grafana
|
||||
|
||||
Use full product names on first mention, then short names:
|
||||
|
||||
- Grafana Alloy (full), Alloy (short)
|
||||
- Grafana Beyla (full), Beyla (short)
|
||||
|
||||
Use "OpenTelemetry Collector" on first mention, then "Collector" for subsequent references.
|
||||
Keep full name for distributions, headings, and links.
|
||||
|
||||
Always use "Grafana Cloud" in full.
|
||||
|
||||
Use complete terms:
|
||||
|
||||
- "OpenTelemetry" (not "OTel")
|
||||
- "Kubernetes" (not "K8s")
|
||||
|
||||
Present observability signals in order: metrics, logs, traces, and profiles.
|
||||
|
||||
Focus content on Grafana solutions when discussing integrations or migrations.
|
||||
|
||||
## Style
|
||||
|
||||
### Structure
|
||||
|
||||
Structure articles into sections with headings.
|
||||
|
||||
Leave Markdown front matter content between two triple dashes `---`.
|
||||
|
||||
The front matter YAML `title` and the content h1 (#) heading should be the same.
|
||||
Make sure there's an h1 heading in the content; this redundancy is required.
|
||||
|
||||
Always include copy after a heading or between headings, for example:
|
||||
|
||||
```markdown
|
||||
## Heading
|
||||
|
||||
Immediately followed by copy and not another heading.
|
||||
|
||||
## Sub heading
|
||||
```
|
||||
|
||||
The immediate copy after a heading should introduce and provide an overview of what's covered in the section.
|
||||
|
||||
Start articles with an introduction that covers the goal of the article. Example goals:
|
||||
|
||||
- Learn concepts
|
||||
- Set up or install something
|
||||
- Configure something
|
||||
- Use a product to solve a business problem
|
||||
- Troubleshoot a problem
|
||||
- Integrate with other software or systems
|
||||
- Migrate from one thing to another
|
||||
- Refer to APIs or reference documentation
|
||||
|
||||
Follow the goal with a list of prerequisites, for example:
|
||||
|
||||
```markdown
|
||||
Before you begin, ensure you have the following:
|
||||
|
||||
- <Prerequisite 1>
|
||||
- <Prerequisite 2>
|
||||
- ...
|
||||
```
|
||||
|
||||
Suggest and link to next steps and related resources at the end of the article, for example:
|
||||
|
||||
- Learn more about A, B, C
|
||||
- Configure X
|
||||
- Use X to achieve Y
|
||||
- Use X to achieve Z
|
||||
- Project homepage or documentation
|
||||
- Project repository (for example, GitHub, GitLab)
|
||||
- Project package (for example, pip or NPM)
|
||||
|
||||
You don't need to use the "Refer to..." syntax for next steps; use the link text directly.
|
||||
|
||||
### Copy
|
||||
|
||||
Write simple, direct copy with short sentences and paragraphs.
|
||||
|
||||
Use contractions:
|
||||
|
||||
- it's, isn't, that's, you're, don't
|
||||
|
||||
Choose simple words:
|
||||
|
||||
- use (not utilize)
|
||||
- help (not assist)
|
||||
- show (not demonstrate)
|
||||
|
||||
Write with verbs and nouns. Use minimal adjectives except when describing Grafana Labs products.
|
||||
|
||||
## Tense
|
||||
|
||||
Write in present simple tense.
|
||||
|
||||
Avoid present continuous tense.
|
||||
|
||||
Only write in future tense to show future actions.
|
||||
|
||||
### Voice
|
||||
|
||||
Always write in an active voice.
|
||||
|
||||
Change passive voice to active voice.
|
||||
|
||||
### Perspective
|
||||
|
||||
Address users as "you".
|
||||
|
||||
Use second person perspective consistently.
|
||||
|
||||
### Wordlist
|
||||
|
||||
Use allowlist/blocklist instead of whitelist/blacklist.
|
||||
|
||||
Use primary/secondary instead of master/slave.
|
||||
|
||||
Use "refer to" instead of "see", "consult", "check out", and other phrases.
|
||||
|
||||
### Formatting
|
||||
|
||||
Use sentence case for titles and headings.
|
||||
|
||||
Use inline Markdown links: [Link text](https://example.com).
|
||||
|
||||
Link to other sections using descriptive phrases that include the section name:
|
||||
"For setup details, refer to the [Lists](#lists) section."
|
||||
|
||||
Bold text with two asterisks: **bold**
|
||||
|
||||
Emphasize text with one underscore: _italics_
|
||||
|
||||
Format UI elements using sentence case as they appear:
|
||||
|
||||
- Click **Submit**.
|
||||
- Navigate to **User settings**.
|
||||
- Configure **Alerting rules**.
|
||||
|
||||
### Lists
|
||||
|
||||
Write complete sentences for lists:
|
||||
|
||||
- Works with all languages and frameworks (correct)
|
||||
- All languages and frameworks (incorrect)
|
||||
|
||||
Use dashes for unordered lists.
|
||||
|
||||
Bold keywords at list start and follow with a colon.
|
||||
|
||||
### Images
|
||||
|
||||
Include descriptive alt text that conveys the essential information or purpose.
|
||||
|
||||
Write alt text without "Image of..." or "Picture of..." prefixes.
|
||||
|
||||
### Code
|
||||
|
||||
Use single code backticks for:
|
||||
|
||||
- user input
|
||||
- placeholders in markdown, for example _`<PLACEHOLDER_NAME>`_
|
||||
- files and directories, for example `/opt/file.md`
|
||||
- source code keywords and identifiers,
|
||||
for example variables, function and class names
|
||||
- configuration options and values, for example `PORT` and `80`
|
||||
- status codes, for example `404`
|
||||
|
||||
Use triple code backticks followed by the syntax for code blocks, for example:
|
||||
|
||||
```javascript
|
||||
console.log('Hello World!');
|
||||
```
|
||||
|
||||
Introduce each code block with a short description.
|
||||
End the introduction with a colon if the code sample follows it, for example:
|
||||
|
||||
```markdown
|
||||
The code sample outputs "Hello World!" to the browser console:
|
||||
|
||||
<CODE_BLOCK>
|
||||
```
|
||||
|
||||
Use descriptive placeholder names in code samples.
|
||||
Use uppercase letters with underscores to separate words in placeholders,
|
||||
for example:
|
||||
|
||||
```sh
|
||||
OTEL_RESOURCE_ATTRIBUTES="service.name=<SERVICE_NAME>
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=<OTLP_ENDPOINT>
|
||||
```
|
||||
|
||||
The placeholder includes the name and the less than and greater than symbols,
|
||||
for example <PLACEHOLDER_NAME>.
|
||||
|
||||
If the placeholder is markdown emphasize it with underscores,
|
||||
for example _`<PLACEHOLDER_NAME>`_.
|
||||
|
||||
In code blocks use the placeholder without additional backticks or emphasis,
|
||||
for example <PLACEHOLDER_NAME>.
|
||||
|
||||
Provide an explanation for each placeholder,
|
||||
typically in the text following the code block or in a configuration section.
|
||||
|
||||
Follow code samples with an explanation
|
||||
and configuration options for placeholders, for example:
|
||||
|
||||
```markdown
|
||||
<CODE_BLOCK>
|
||||
|
||||
This code sets required environment variables
|
||||
to send OTLP data to an OTLP endpoint.
|
||||
To configure the code refer to the configuration section.
|
||||
|
||||
<CONFIGURATION>
|
||||
```
|
||||
|
||||
Put configuration for a code block after the code block.
|
||||
|
||||
## APIs
|
||||
|
||||
When documenting API endpoints specify the HTTP method,
|
||||
for example `GET`, `POST`, `PUT`, `DELETE`.
|
||||
|
||||
Provide the full request path, using backticks.
|
||||
|
||||
Use backticks for parameter names and example values.
|
||||
|
||||
Use placeholders like `{userId}` for path parameters, for example:
|
||||
|
||||
- To retrieve user details, make a `GET` request to `/api/v1/users/{userId}`.
|
||||
|
||||
### CLI commands
|
||||
|
||||
When presenting CLI commands and their output,
|
||||
introduce the command with a brief explanation of its purpose.
|
||||
Clearly distinguish the command from its output.
|
||||
|
||||
For commands, use `sh` to specify the code block language.
|
||||
|
||||
For output, use a generic specifier like `text`, `console`,
|
||||
or `json`/`yaml` if the output is structured.
|
||||
|
||||
For example:
|
||||
|
||||
```markdown
|
||||
To list all running pods in the `default` namespace, use the following command:
|
||||
|
||||
<CODE_BLOCK>
|
||||
```
|
||||
|
||||
The output will resemble the following:
|
||||
|
||||
```text
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
my-app-deployment-7fdb6c5f65-abcde 1/1 Running 0 2d1h
|
||||
another-service-pod-xyz123 2/2 Running 0 5h30m
|
||||
```
|
||||
|
||||
### Shortcodes
|
||||
|
||||
Leave Hugo shortcodes in the content when editing.
|
||||
|
||||
Use our custom admonition Hugo shortcode for notes, cautions, or warnings,
|
||||
with `<TYPE>` as "note", "caution", or "warning":
|
||||
|
||||
```markdown
|
||||
{{< admonition type="<TYPE>" >}}
|
||||
...
|
||||
{{< /admonition >}}
|
||||
```
|
||||
|
||||
Use admonitions sparingly.
|
||||
Only include exceptional information in admonitions.
|
||||
|
||||
<!-- docs-ai-end -->
|
||||
@@ -17,6 +17,7 @@ GO_RACE_FLAG := $(if $(GO_RACE),-race)
|
||||
GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev)
|
||||
GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS))
|
||||
GO_BUILD_FLAGS += $(GO_RACE_FLAG)
|
||||
GO_BUILD_FLAGS += $(if $(GO_BUILD_CGO),-cgo-enabled=$(GO_BUILD_CGO))
|
||||
GO_TEST_FLAGS += $(if $(GO_BUILD_TAGS),-tags=$(GO_BUILD_TAGS))
|
||||
GIT_BASE = remotes/origin/main
|
||||
|
||||
@@ -245,6 +246,10 @@ build-backend: ## Build Grafana backend.
|
||||
@echo "build backend"
|
||||
$(GO) run build.go $(GO_BUILD_FLAGS) build-backend
|
||||
|
||||
.PHONY: build-air
|
||||
build-air: build-backend
|
||||
@cp ./bin/grafana ./bin/grafana-air
|
||||
|
||||
.PHONY: build-server
|
||||
build-server: ## Build Grafana server.
|
||||
@echo "build server"
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/k8s"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||
@@ -48,8 +49,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "advisor",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
log.WithContext(ctx).Error("Informer processing error", "error", err)
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
log.WithContext(ctx).Error("Informer processing error", "error", err)
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
|
||||
@@ -3,14 +3,14 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
@@ -28,7 +28,7 @@ require (
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.44.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
|
||||
@@ -2,8 +2,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
@@ -21,8 +21,8 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -91,8 +91,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -5,6 +5,7 @@ metadata:
|
||||
spec:
|
||||
appName: alerting-notifications
|
||||
group: notifications.alerting.grafana.app
|
||||
preferredVersion: v0alpha1
|
||||
versions:
|
||||
- kinds:
|
||||
- conversion: false
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/alerting/notifications
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
@@ -19,7 +19,7 @@ require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
@@ -94,7 +94,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -21,8 +21,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
@@ -69,8 +69,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
@@ -284,8 +284,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.
|
||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -34,8 +34,9 @@ var (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "alerting-notifications",
|
||||
Group: "notifications.alerting.grafana.app",
|
||||
AppName: "alerting-notifications",
|
||||
Group: "notifications.alerting.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis"
|
||||
@@ -22,8 +23,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "alerting.notification",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.DefaultLogger.With("error", err).Error("Informer processing error")
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.DefaultLogger.With("error", err).Error("Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: managedKinds,
|
||||
|
||||
@@ -5,6 +5,7 @@ metadata:
|
||||
spec:
|
||||
appName: alerting
|
||||
group: rules.alerting.grafana.app
|
||||
preferredVersion: v0alpha1
|
||||
versions:
|
||||
- kinds:
|
||||
- conversion: false
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/alerting/rules
|
||||
go 1.24.4
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -77,7 +77,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
||||
@@ -10,8 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
@@ -46,8 +46,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -28,8 +28,9 @@ var (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "alerting",
|
||||
Group: "rules.alerting.grafana.app",
|
||||
AppName: "alerting",
|
||||
Group: "rules.alerting.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/rules/pkg/apis"
|
||||
@@ -22,8 +23,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "alerting.rules",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.DefaultLogger.With("error", err).Error("Informer processing error")
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.DefaultLogger.With("error", err).Error("Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: managedKinds,
|
||||
|
||||
@@ -6,4 +6,5 @@ generate: install-app-sdk update-app-sdk
|
||||
--source=./kinds/ \
|
||||
--gogenpath=./pkg/apis \
|
||||
--grouping=group \
|
||||
--genoperatorstate=false \
|
||||
--defencoding=none
|
||||
@@ -5,7 +5,7 @@ go 1.24.0
|
||||
toolchain go1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
@@ -17,7 +17,7 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -79,7 +79,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
||||
@@ -10,8 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
@@ -46,8 +46,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type CorrelationClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *CorrelationClient) Patch(ctx context.Context, identifier resource.Ident
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *CorrelationClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CorrelationStatus, opts resource.UpdateOptions) (*Correlation, error) {
|
||||
return c.client.Update(ctx, &Correlation{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: CorrelationKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CorrelationClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type Correlation struct {
|
||||
|
||||
// Spec is the spec of the Correlation
|
||||
Spec CorrelationSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status CorrelationStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *Correlation) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *Correlation) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *Correlation) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *Correlation) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *Correlation) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *Correlation) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(CorrelationStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type CorrelationStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *Correlation) DeepCopyInto(dst *Correlation) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *CorrelationSpec) DeepCopy() *CorrelationSpec {
|
||||
func (s *CorrelationSpec) DeepCopyInto(dst *CorrelationSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of CorrelationStatus
|
||||
func (s *CorrelationStatus) DeepCopy() *CorrelationStatus {
|
||||
cpy := &CorrelationStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies CorrelationStatus into another CorrelationStatus object
|
||||
func (s *CorrelationStatus) DeepCopyInto(dst *CorrelationStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type CorrelationstatusOperatorState struct {
|
||||
// lastEvaluation is the ResourceVersion last evaluated
|
||||
LastEvaluation string `json:"lastEvaluation"`
|
||||
// state describes the state of the lastEvaluation.
|
||||
// It is limited to three possible states for machine evaluation.
|
||||
State CorrelationStatusOperatorStateState `json:"state"`
|
||||
// descriptiveState is an optional more descriptive state field which has no requirements on format
|
||||
DescriptiveState *string `json:"descriptiveState,omitempty"`
|
||||
// details contains any extra information that is operator-specific
|
||||
Details map[string]interface{} `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// NewCorrelationstatusOperatorState creates a new CorrelationstatusOperatorState object.
|
||||
func NewCorrelationstatusOperatorState() *CorrelationstatusOperatorState {
|
||||
return &CorrelationstatusOperatorState{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type CorrelationStatus struct {
|
||||
// operatorStates is a map of operator ID to operator state evaluations.
|
||||
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
|
||||
OperatorStates map[string]CorrelationstatusOperatorState `json:"operatorStates,omitempty"`
|
||||
// additionalFields is reserved for future use
|
||||
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
|
||||
}
|
||||
|
||||
// NewCorrelationStatus creates a new CorrelationStatus object.
|
||||
func NewCorrelationStatus() *CorrelationStatus {
|
||||
return &CorrelationStatus{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type CorrelationStatusOperatorStateState string
|
||||
|
||||
const (
|
||||
CorrelationStatusOperatorStateStateSuccess CorrelationStatusOperatorStateState = "success"
|
||||
CorrelationStatusOperatorStateStateInProgress CorrelationStatusOperatorStateState = "in_progress"
|
||||
CorrelationStatusOperatorStateStateFailed CorrelationStatusOperatorStateState = "failed"
|
||||
)
|
||||
@@ -10,24 +10,24 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
|
||||
v0alpha1 "github.com/grafana/grafana/apps/correlations/pkg/apis/correlation/v0alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
rawSchemaCorrelationv0alpha1 = []byte(`{"ConfigSpec":{"additionalProperties":false,"description":"there was a deprecated field here called type, we will need to move that for conversion and provisioning","properties":{"field":{"type":"string"},"target":{"$ref":"#/components/schemas/TargetSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationSpec"},"type":"array"}},"required":["field","target"],"type":"object"},"Correlation":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"CorrelationType":{"enum":["query","external"],"type":"string"},"DataSourceRef":{"additionalProperties":false,"properties":{"group":{"description":"same as pluginId","type":"string"},"name":{"description":"same as grafana uid","type":"string"}},"required":["group","name"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"TargetSpec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"TransformationSpec":{"additionalProperties":false,"properties":{"expression":{"type":"string"},"field":{"type":"string"},"mapValue":{"type":"string"},"type":{"type":"string"}},"required":["type","expression","field","mapValue"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"config":{"$ref":"#/components/schemas/ConfigSpec"},"description":{"type":"string"},"label":{"type":"string"},"provisioned":{"type":"boolean"},"source_ds_ref":{"$ref":"#/components/schemas/DataSourceRef"},"target_ds_ref":{"$ref":"#/components/schemas/DataSourceRef"},"type":{"$ref":"#/components/schemas/CorrelationType"}},"required":["source_ds_ref","label","config","provisioned","type"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
|
||||
rawSchemaCorrelationv0alpha1 = []byte(`{"ConfigSpec":{"additionalProperties":false,"description":"there was a deprecated field here called type, we will need to move that for conversion and provisioning","properties":{"field":{"type":"string"},"target":{"$ref":"#/components/schemas/TargetSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationSpec"},"type":"array"}},"required":["field","target"],"type":"object"},"Correlation":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"CorrelationType":{"enum":["query","external"],"type":"string"},"DataSourceRef":{"additionalProperties":false,"properties":{"group":{"description":"same as pluginId","type":"string"},"name":{"description":"same as grafana uid","type":"string"}},"required":["group","name"],"type":"object"},"TargetSpec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"TransformationSpec":{"additionalProperties":false,"properties":{"expression":{"type":"string"},"field":{"type":"string"},"mapValue":{"type":"string"},"type":{"type":"string"}},"required":["type","expression","field","mapValue"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"config":{"$ref":"#/components/schemas/ConfigSpec"},"description":{"type":"string"},"label":{"type":"string"},"provisioned":{"type":"boolean"},"source_ds_ref":{"$ref":"#/components/schemas/DataSourceRef"},"target_ds_ref":{"$ref":"#/components/schemas/DataSourceRef"},"type":{"$ref":"#/components/schemas/CorrelationType"}},"required":["source_ds_ref","label","config","provisioned","type"],"type":"object"}}`)
|
||||
versionSchemaCorrelationv0alpha1 app.VersionSchema
|
||||
_ = json.Unmarshal(rawSchemaCorrelationv0alpha1, &versionSchemaCorrelationv0alpha1)
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "correlation",
|
||||
Group: "correlations.grafana.app",
|
||||
AppName: "correlation",
|
||||
Group: "correlations.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -17,8 +18,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "correlation",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).Error("Informer processing error", "error", err)
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).Error("Informer processing error", "error", err)
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* This file was generated by grafana-app-sdk. DO NOT EDIT.
|
||||
*/
|
||||
import { Spec } from './types.spec.gen';
|
||||
import { Status } from './types.status.gen';
|
||||
|
||||
export interface Metadata {
|
||||
name: string;
|
||||
@@ -45,5 +44,4 @@ export interface Correlation {
|
||||
apiVersion: string;
|
||||
metadata: Metadata;
|
||||
spec: Spec;
|
||||
status: Status;
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
export interface OperatorState {
|
||||
// lastEvaluation is the ResourceVersion last evaluated
|
||||
lastEvaluation: string;
|
||||
// state describes the state of the lastEvaluation.
|
||||
// It is limited to three possible states for machine evaluation.
|
||||
state: "success" | "in_progress" | "failed";
|
||||
// descriptiveState is an optional more descriptive state field which has no requirements on format
|
||||
descriptiveState?: string;
|
||||
// details contains any extra information that is operator-specific
|
||||
details?: Record<string, any>;
|
||||
}
|
||||
|
||||
export const defaultOperatorState = (): OperatorState => ({
|
||||
lastEvaluation: "",
|
||||
state: "success",
|
||||
});
|
||||
|
||||
export interface Status {
|
||||
// operatorStates is a map of operator ID to operator state evaluations.
|
||||
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
|
||||
operatorStates?: Record<string, OperatorState>;
|
||||
// additionalFields is reserved for future use
|
||||
additionalFields?: Record<string, any>;
|
||||
}
|
||||
|
||||
export const defaultStatus = (): Status => ({
|
||||
});
|
||||
|
||||
@@ -4,8 +4,8 @@ go 1.24.6
|
||||
|
||||
require (
|
||||
cuelang.org/go v0.11.1
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
|
||||
@@ -31,7 +31,7 @@ require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/elazarl/goproxy v1.7.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -51,7 +51,7 @@ require (
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||
@@ -134,7 +134,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
+10
-10
@@ -36,8 +36,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=
|
||||
github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
@@ -95,14 +95,14 @@ github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25d
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0 h1:/KCrsZkj9pEGwIGovqAz1A8rjI2A2YT+ZpvgfZN0LAA=
|
||||
@@ -386,8 +386,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@@ -69,6 +70,8 @@ type DashboardHit struct {
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// The k8s name (eg, grafana UID) for the parent folder
|
||||
Folder string `json:"folder,omitempty"`
|
||||
// The resource is managed
|
||||
ManagedBy ManagedBy `json:"managedBy,omitzero,omitempty"`
|
||||
// Stick untyped extra fields in this object (including the sort value)
|
||||
Field *common.Unstructured `json:"field,omitzero,omitempty"`
|
||||
// When using "real" search, this is the score
|
||||
@@ -77,6 +80,15 @@ type DashboardHit struct {
|
||||
Explain *common.Unstructured `json:"explain,omitzero,omitempty"`
|
||||
}
|
||||
|
||||
type ManagedBy struct {
|
||||
Kind utils.ManagerKind `json:"kind"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (m ManagedBy) IsZero() bool {
|
||||
return m.Kind == "" && m.ID == ""
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
type FacetResult struct {
|
||||
Field string `json:"field,omitempty"`
|
||||
|
||||
@@ -76,6 +76,7 @@ func (in *DashboardHit) DeepCopyInto(out *DashboardHit) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.ManagedBy = in.ManagedBy
|
||||
if in.Field != nil {
|
||||
in, out := &in.Field, &out.Field
|
||||
*out = (*in).DeepCopy()
|
||||
|
||||
@@ -35,6 +35,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelList": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelList(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelSpec": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelSpec(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.LibraryPanelStatus": schema_pkg_apis_dashboard_v0alpha1_LibraryPanelStatus(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy": schema_pkg_apis_dashboard_v0alpha1_ManagedBy(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SearchResults": schema_pkg_apis_dashboard_v0alpha1_SearchResults(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortBy": schema_pkg_apis_dashboard_v0alpha1_SortBy(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortableField": schema_pkg_apis_dashboard_v0alpha1_SortableField(ref),
|
||||
@@ -337,6 +338,13 @@ func schema_pkg_apis_dashboard_v0alpha1_DashboardHit(ref common.ReferenceCallbac
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"managedBy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The resource is managed",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy"),
|
||||
},
|
||||
},
|
||||
"field": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Stick untyped extra fields in this object (including the sort value)",
|
||||
@@ -361,7 +369,7 @@ func schema_pkg_apis_dashboard_v0alpha1_DashboardHit(ref common.ReferenceCallbac
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured"},
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.ManagedBy", "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1027,6 +1035,32 @@ func schema_pkg_apis_dashboard_v0alpha1_LibraryPanelStatus(ref common.ReferenceC
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v0alpha1_ManagedBy(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"id": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"kind"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v0alpha1_SearchResults(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
||||
@@ -21,8 +21,9 @@ import (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "dashboard",
|
||||
Group: "dashboard.grafana.app",
|
||||
AppName: "dashboard",
|
||||
Group: "dashboard.grafana.app",
|
||||
PreferredVersion: "v1beta1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
@@ -128,22 +128,18 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Set default span (line 1063 in TS)
|
||||
span := GetFloatValue(panel, "span", defaultPanelSpan)
|
||||
// Check if panel already has gridPos but no valid span
|
||||
// If span is missing or zero, and gridPos exists, preserve gridPos dimensions
|
||||
var panelWidth, panelHeight int
|
||||
span := GetFloatValue(panel, "span", 0)
|
||||
existingGridPos, hasGridPos := panel["gridPos"].(map[string]interface{})
|
||||
|
||||
// Handle minSpan conversion (lines 1064-1066 in TS)
|
||||
if minSpan, hasMinSpan := panel["minSpan"]; hasMinSpan {
|
||||
if minSpanFloat, ok := ConvertToFloat(minSpan); ok && minSpanFloat > 0 {
|
||||
panel["minSpan"] = int(math.Min(float64(gridColumnCount), (float64(gridColumnCount)/12.0)*minSpanFloat))
|
||||
}
|
||||
}
|
||||
|
||||
panelWidth := int(math.Floor(span * widthFactor))
|
||||
panelHeight := rowGridHeight
|
||||
if panelHeightValue, hasHeight := panel["height"]; hasHeight {
|
||||
if h, ok := ConvertToFloat(panelHeightValue); ok {
|
||||
panelHeight = getGridHeight(h)
|
||||
}
|
||||
if hasGridPos && span == 0 {
|
||||
// Panel already has gridPos but no valid span - preserve its dimensions
|
||||
panelWidth = GetIntValue(existingGridPos, "w", int(defaultPanelSpan*widthFactor))
|
||||
panelHeight = GetIntValue(existingGridPos, "h", rowGridHeight)
|
||||
} else {
|
||||
panelWidth, panelHeight = calculatePanelDimensionsFromSpan(span, panel, widthFactor, rowGridHeight)
|
||||
}
|
||||
|
||||
panelPos := rowArea.getPanelPosition(panelHeight, panelWidth)
|
||||
@@ -315,3 +311,27 @@ func getGridHeight(height float64) int {
|
||||
}
|
||||
return int(math.Ceil(height / panelHeightStep))
|
||||
}
|
||||
|
||||
func calculatePanelDimensionsFromSpan(span float64, panel map[string]interface{}, widthFactor float64, defaultHeight int) (int, int) {
|
||||
// Set default span if still 0
|
||||
if span == 0 {
|
||||
span = defaultPanelSpan
|
||||
}
|
||||
|
||||
if minSpan, hasMinSpan := panel["minSpan"]; hasMinSpan {
|
||||
if minSpanFloat, ok := ConvertToFloat(minSpan); ok && minSpanFloat > 0 {
|
||||
panel["minSpan"] = int(math.Min(float64(gridColumnCount), (float64(gridColumnCount)/12.0)*minSpanFloat))
|
||||
}
|
||||
}
|
||||
|
||||
panelWidth := int(math.Floor(span * widthFactor))
|
||||
panelHeight := defaultHeight
|
||||
|
||||
if panelHeightValue, hasHeight := panel["height"]; hasHeight {
|
||||
if h, ok := ConvertToFloat(panelHeightValue); ok {
|
||||
panelHeight = getGridHeight(h)
|
||||
}
|
||||
}
|
||||
|
||||
return panelWidth, panelHeight
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// V34 migrates CloudWatch queries that use multiple statistics into separate queries.
|
||||
//
|
||||
@@ -113,9 +116,24 @@ func migrateCloudWatchQueriesInPanel(panel map[string]interface{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add CloudWatch fields if missing (set to 0 if not present)
|
||||
t["metricEditorMode"] = GetIntValue(t, "metricEditorMode", 0)
|
||||
t["metricQueryType"] = GetIntValue(t, "metricQueryType", 0)
|
||||
// Add CloudWatch fields if missing (matches frontend migrateCloudWatchQuery logic)
|
||||
if _, hasMetricQueryType := t["metricQueryType"]; !hasMetricQueryType {
|
||||
t["metricQueryType"] = 0 // MetricQueryType.Search
|
||||
}
|
||||
|
||||
if _, hasMetricEditorMode := t["metricEditorMode"]; !hasMetricEditorMode {
|
||||
metricQueryType := GetIntValue(t, "metricQueryType", 0)
|
||||
if metricQueryType == 1 { // MetricQueryType.Insights
|
||||
t["metricEditorMode"] = 1 // MetricEditorMode.Code
|
||||
} else {
|
||||
expression := GetStringValue(t, "expression")
|
||||
if expression != "" {
|
||||
t["metricEditorMode"] = 1 // MetricEditorMode.Code
|
||||
} else {
|
||||
t["metricEditorMode"] = 0 // MetricEditorMode.Builder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get valid statistics (including null and empty strings)
|
||||
validStats, isEmpty := getValidStatistics(t["statistics"])
|
||||
@@ -137,19 +155,20 @@ func migrateCloudWatchQueriesInPanel(panel map[string]interface{}) {
|
||||
// No valid statistics - keep query as-is
|
||||
newTargets = append(newTargets, t)
|
||||
case 1:
|
||||
// Single statistic - set statistic field if not null
|
||||
if statString := GetStringValue(map[string]interface{}{"stat": validStats[0]}, "stat"); statString != "" {
|
||||
t["statistic"] = statString
|
||||
// Single statistic - set statistic field
|
||||
// Frontend doesn't set statistic property for null values
|
||||
if validStats[0] != nil {
|
||||
t["statistic"] = validStats[0]
|
||||
}
|
||||
newTargets = append(newTargets, t)
|
||||
default:
|
||||
// Multiple statistics - create separate queries
|
||||
for i, stat := range validStats {
|
||||
newQuery := copyMap(t)
|
||||
// Set statistic field
|
||||
// Frontend doesn't set statistic property for null values
|
||||
if stat != nil {
|
||||
if statString, ok := stat.(string); ok {
|
||||
newQuery["statistic"] = statString
|
||||
}
|
||||
newQuery["statistic"] = stat
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
@@ -210,10 +229,11 @@ func migrateCloudWatchAnnotationQueries(dashboard map[string]interface{}) {
|
||||
delete(a, "statistics")
|
||||
annotationsList[i] = a
|
||||
case 1:
|
||||
// Single statistic - set statistic field if not null
|
||||
// Single statistic - set statistic field (matches frontend behavior)
|
||||
delete(a, "statistics")
|
||||
if statString := GetStringValue(map[string]interface{}{"stat": validStats[0]}, "stat"); statString != "" {
|
||||
a["statistic"] = statString
|
||||
// Frontend doesn't set statistic property for null values
|
||||
if validStats[0] != nil {
|
||||
a["statistic"] = validStats[0]
|
||||
}
|
||||
annotationsList[i] = a
|
||||
default:
|
||||
@@ -221,11 +241,10 @@ func migrateCloudWatchAnnotationQueries(dashboard map[string]interface{}) {
|
||||
delete(a, "statistics")
|
||||
for j, stat := range validStats {
|
||||
newAnnotation := copyMap(a)
|
||||
|
||||
// Set statistic field (matches frontend behavior)
|
||||
// Frontend doesn't set statistic property for null values
|
||||
if stat != nil {
|
||||
if statString, ok := stat.(string); ok {
|
||||
newAnnotation["statistic"] = statString
|
||||
}
|
||||
newAnnotation["statistic"] = stat
|
||||
}
|
||||
|
||||
// Add suffix to name
|
||||
@@ -260,14 +279,9 @@ func getValidStatistics(statisticsField interface{}) ([]interface{}, bool) {
|
||||
return nil, true // Return nil with true flag to indicate "empty array"
|
||||
}
|
||||
|
||||
var valid []interface{}
|
||||
for _, stat := range statistics {
|
||||
// Include null and strings (including empty strings)
|
||||
if stat == nil || isString(stat) {
|
||||
valid = append(valid, stat)
|
||||
}
|
||||
}
|
||||
return valid, false
|
||||
// Frontend processes ALL values in statistics array, regardless of type
|
||||
// It doesn't filter out invalid types - it processes them as-is
|
||||
return statistics, false
|
||||
}
|
||||
|
||||
// getSuffixForStat returns the appropriate suffix for annotation names
|
||||
@@ -281,7 +295,20 @@ func getSuffixForStat(stat interface{}) string {
|
||||
}
|
||||
return statString
|
||||
}
|
||||
return ""
|
||||
// For non-string types, convert to string representation like JavaScript does
|
||||
switch v := stat.(type) {
|
||||
case map[string]interface{}:
|
||||
return "[object Object]" // JavaScript behavior for objects
|
||||
case []interface{}:
|
||||
return "" // JavaScript behavior for arrays (empty string)
|
||||
case bool:
|
||||
if v {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
default:
|
||||
return fmt.Sprintf("%v", stat) // Numbers and other types
|
||||
}
|
||||
}
|
||||
|
||||
// copyMap creates a shallow copy of a map
|
||||
@@ -293,12 +320,6 @@ func copyMap(original map[string]interface{}) map[string]interface{} {
|
||||
return copy
|
||||
}
|
||||
|
||||
// isString checks if value is a string
|
||||
func isString(value interface{}) bool {
|
||||
_, ok := value.(string)
|
||||
return ok
|
||||
}
|
||||
|
||||
// isCloudWatchQuery checks if a query target is a CloudWatch query.
|
||||
func isCloudWatchQuery(target map[string]interface{}) bool {
|
||||
// Check for required CloudWatch query fields
|
||||
|
||||
@@ -185,7 +185,7 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles invalid statistics in CloudWatch annotation queries",
|
||||
name: "handles annotation with empty statistics array",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
@@ -195,7 +195,7 @@ func TestV34(t *testing.T) {
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": []interface{}{123, "Sum", nil},
|
||||
"statistics": []interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -205,15 +205,7 @@ func TestV34(t *testing.T) {
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - Sum",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": "Sum",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - null",
|
||||
"name": "CloudWatch Annotation",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
@@ -224,7 +216,7 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles multiple valid statistics mixed with invalid ones in annotation",
|
||||
name: "handles annotation with single statistic",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
@@ -234,7 +226,7 @@ func TestV34(t *testing.T) {
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": []interface{}{123, "Sum", nil, "Average"},
|
||||
"statistics": []interface{}{"Average"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -244,22 +236,7 @@ func TestV34(t *testing.T) {
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - Sum",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": "Sum",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - null",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - Average",
|
||||
"name": "CloudWatch Annotation",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
@@ -271,7 +248,7 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles CloudWatch annotation with all invalid statistics",
|
||||
name: "handles annotation with null statistic",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
@@ -281,7 +258,7 @@ func TestV34(t *testing.T) {
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": []interface{}{123, nil, map[string]interface{}{"invalid": "value"}},
|
||||
"statistics": []interface{}{nil},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -296,6 +273,87 @@ func TestV34(t *testing.T) {
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
// No statistic property for null
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles annotation with all suffix types (for getSuffixForStat coverage)",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": []interface{}{123, true, false, map[string]interface{}{}, []interface{}{}, "", "Average"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - 123",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": 123,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - true",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - false",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": false,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - [object Object]",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": map[string]interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - ",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": []interface{}{},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - ",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": "",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "CloudWatch Annotation - Average",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistic": "Average",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -468,94 +526,6 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles invalid statistics values gracefully",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": []interface{}{123, nil, "Average", map[string]interface{}{"invalid": "value"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"refId": "B",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistic": "Average",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles CloudWatch query with all invalid statistics",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": []interface{}{123, nil, map[string]interface{}{"invalid": "value"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preserves other query properties during migration",
|
||||
input: map[string]interface{}{
|
||||
@@ -768,6 +738,88 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preserves existing metricQueryType (hasOwnProperty test)",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 1, // Already exists - should be preserved
|
||||
"statistics": []interface{}{"Average"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 1, // Preserved
|
||||
"metricEditorMode": 1, // Set to Code due to Insights
|
||||
"statistic": "Average",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preserves existing metricEditorMode (hasOwnProperty test)",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricEditorMode": 1, // Already exists - should be preserved
|
||||
"statistics": []interface{}{"Average"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"refId": "A",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricEditorMode": 1, // Preserved
|
||||
"metricQueryType": 0, // Set to default
|
||||
"statistic": "Average",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preserves existing metricEditorMode and metricQueryType values",
|
||||
input: map[string]interface{}{
|
||||
@@ -826,6 +878,174 @@ func TestV34(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles refId generation with existing refIds",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{"refId": "A", "expr": "prometheus"},
|
||||
map[string]interface{}{"refId": "C", "expr": "prometheus"}, // Skip B to test gap filling
|
||||
map[string]interface{}{
|
||||
"refId": "D",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": []interface{}{"Average", "Maximum"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{"refId": "A", "expr": "prometheus"},
|
||||
map[string]interface{}{"refId": "C", "expr": "prometheus"},
|
||||
map[string]interface{}{
|
||||
"refId": "D",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistic": "Average",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"refId": "B", // Should use the available B
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistic": "Maximum",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles non-CloudWatch annotation (skips migration)",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "Regular Annotation",
|
||||
"datasource": "prometheus",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"annotations": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "Regular Annotation",
|
||||
"datasource": "prometheus",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles missing annotations list",
|
||||
input: map[string]interface{}{
|
||||
"annotations": map[string]interface{}{},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"annotations": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "handles missing annotations entirely",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tests generateNextRefId double letter generation",
|
||||
input: map[string]interface{}{
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": func() []interface{} {
|
||||
targets := []interface{}{}
|
||||
// Create A-Z refIds
|
||||
for c := 'A'; c <= 'Z'; c++ {
|
||||
targets = append(targets, map[string]interface{}{
|
||||
"refId": string(c),
|
||||
"expr": "prometheus",
|
||||
})
|
||||
}
|
||||
// Add CloudWatch query that will need double letter refId
|
||||
targets = append(targets, map[string]interface{}{
|
||||
"refId": "AA",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": []interface{}{"Average", "Maximum"},
|
||||
})
|
||||
return targets
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": int(34),
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"targets": func() []interface{} {
|
||||
targets := []interface{}{}
|
||||
// Create A-Z refIds
|
||||
for c := 'A'; c <= 'Z'; c++ {
|
||||
targets = append(targets, map[string]interface{}{
|
||||
"refId": string(c),
|
||||
"expr": "prometheus",
|
||||
})
|
||||
}
|
||||
// Add the migrated CloudWatch queries
|
||||
targets = append(targets, map[string]interface{}{
|
||||
"refId": "AA",
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistic": "Average",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
})
|
||||
targets = append(targets, map[string]interface{}{
|
||||
"refId": "AB", // Next available double letter
|
||||
"dimensions": map[string]interface{}{"InstanceId": "i-123"},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistic": "Maximum",
|
||||
"metricEditorMode": 0,
|
||||
"metricQueryType": 0,
|
||||
})
|
||||
return targets
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
runMigrationTests(t, tests, schemaversion.V34)
|
||||
}
|
||||
|
||||
+171
@@ -71,6 +71,40 @@
|
||||
"prefixMatching": false,
|
||||
"statistics": ["InvalidStat", "Sum", null, "Average"]
|
||||
},
|
||||
{
|
||||
"name": "CloudWatch Annotation with Null in Statistics",
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": [null, "Average", ""]
|
||||
},
|
||||
{
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics",
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"prefixMatching": false,
|
||||
"statistics": [123, true, {}]
|
||||
},
|
||||
{
|
||||
"name": "Non-CloudWatch Annotation",
|
||||
"enable": true,
|
||||
@@ -348,6 +382,143 @@
|
||||
{
|
||||
"id": 10,
|
||||
"type": "timeseries",
|
||||
"title": "CloudWatch Query Missing Editor Fields",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-missing-fields"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": ["Average"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "timeseries",
|
||||
"title": "CloudWatch Query with Expression (Code Mode)",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-with-expression"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
|
||||
"statistics": ["Average", "Maximum"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "timeseries",
|
||||
"title": "CloudWatch Insights Query Missing Editor Mode",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-insights"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 1,
|
||||
"statistics": ["Average"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"type": "timeseries",
|
||||
"title": "CloudWatch Query with Null Statistics",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": [null, "Average", "", "Maximum"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "timeseries",
|
||||
"title": "CloudWatch Query with Only Invalid Statistics",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "default-ds-uid",
|
||||
"type": "prometheus",
|
||||
"apiVersion": "v1"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"namespace": "AWS/EC2",
|
||||
"region": "us-east-1",
|
||||
"metricName": "CPUUtilization",
|
||||
"statistics": [123, true, {}, []]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "timeseries",
|
||||
"title": "Non-CloudWatch Panel",
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
|
||||
Vendored
+367
-1
@@ -80,6 +80,39 @@
|
||||
"region": "us-east-1",
|
||||
"statistic": "InvalidStat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - null",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - 123",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": 123
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
@@ -171,6 +204,74 @@
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - Average",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - ",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": ""
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - true",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - [object Object]",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -631,9 +732,274 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 10,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-missing-fields"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query Missing Editor Fields",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 11,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-with-expression"
|
||||
},
|
||||
"expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-with-expression"
|
||||
},
|
||||
"expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Maximum"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Expression (Code Mode)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 12,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-insights"
|
||||
},
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 1,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Insights Query Missing Editor Mode",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 13,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "C",
|
||||
"region": "us-east-1",
|
||||
"statistic": ""
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "D",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Maximum"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Null Statistics",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 14,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": 123
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "C",
|
||||
"region": "us-east-1",
|
||||
"statistic": {}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "D",
|
||||
"region": "us-east-1",
|
||||
"statistic": []
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Only Invalid Statistics",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"id": 15,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
|
||||
Vendored
+367
-1
@@ -80,6 +80,39 @@
|
||||
"region": "us-east-1",
|
||||
"statistic": "InvalidStat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - null",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - 123",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": 123
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
@@ -171,6 +204,74 @@
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - Average",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "orange",
|
||||
"name": "CloudWatch Annotation with Null in Statistics - ",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": ""
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - true",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-annotation"
|
||||
},
|
||||
"enable": true,
|
||||
"iconColor": "pink",
|
||||
"name": "CloudWatch Annotation Only Invalid Statistics - [object Object]",
|
||||
"namespace": "AWS/EC2",
|
||||
"prefixMatching": false,
|
||||
"region": "us-east-1",
|
||||
"statistic": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -631,9 +732,274 @@
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 10,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-missing-fields"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query Missing Editor Fields",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 11,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-with-expression"
|
||||
},
|
||||
"expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-with-expression"
|
||||
},
|
||||
"expression": "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Maximum"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Expression (Code Mode)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 12,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-insights"
|
||||
},
|
||||
"metricEditorMode": 1,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 1,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Insights Query Missing Editor Mode",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 13,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Average"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "C",
|
||||
"region": "us-east-1",
|
||||
"statistic": ""
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-null-stats"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "D",
|
||||
"region": "us-east-1",
|
||||
"statistic": "Maximum"
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Null Statistics",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"id": 14,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "A",
|
||||
"region": "us-east-1",
|
||||
"statistic": 123
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "B",
|
||||
"region": "us-east-1",
|
||||
"statistic": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "C",
|
||||
"region": "us-east-1",
|
||||
"statistic": {}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"dimensions": {
|
||||
"InstanceId": "i-invalid-only"
|
||||
},
|
||||
"metricEditorMode": 0,
|
||||
"metricName": "CPUUtilization",
|
||||
"metricQueryType": 0,
|
||||
"namespace": "AWS/EC2",
|
||||
"refId": "D",
|
||||
"region": "us-east-1",
|
||||
"statistic": []
|
||||
}
|
||||
],
|
||||
"title": "CloudWatch Query with Only Invalid Statistics",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"id": 15,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/folder
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
@@ -55,7 +55,7 @@ require (
|
||||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
|
||||
+6
-6
@@ -6,8 +6,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
|
||||
@@ -31,8 +31,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
|
||||
@@ -152,8 +152,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -18,8 +18,9 @@ import (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "folder",
|
||||
Group: "folder.grafana.app",
|
||||
AppName: "folder",
|
||||
Group: "folder.grafana.app",
|
||||
PreferredVersion: "v1beta1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v1beta1",
|
||||
|
||||
@@ -8,6 +8,7 @@ generate: install-app-sdk update-app-sdk ## Run Grafana App SDK code generation
|
||||
--grouping=group \
|
||||
--defencoding=none \
|
||||
--noschemasinmanifest \
|
||||
--genoperatorstate=false \
|
||||
--postprocess
|
||||
|
||||
.PHONY: deps
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
# https://docs.tilt.dev/api.html#api.version_settings
|
||||
version_settings(constraint='>=0.22.2')
|
||||
|
||||
custom_build(
|
||||
'iam-folder-reconciler',
|
||||
command='docker buildx build --tag $EXPECTED_REF -f ./apps/iam/local/Dockerfile .',
|
||||
deps=[
|
||||
'apps/iam',
|
||||
'pkg',
|
||||
],
|
||||
disable_push=True,
|
||||
dir='../..',
|
||||
)
|
||||
|
||||
k8s_yaml([filename for filename in listdir('local/yamls') if filename.lower().endswith(('.yaml', '.yml'))])
|
||||
|
||||
# Port forward Grafana to localhost:3000
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
FROM golang:1.24-alpine AS builder
|
||||
|
||||
WORKDIR /build
|
||||
COPY go.mod go.sum ./
|
||||
COPY vendor* ./vendor
|
||||
RUN test -f vendor/modules.txt || go mod download
|
||||
|
||||
COPY cmd cmd
|
||||
COPY pkg pkg
|
||||
|
||||
RUN go build -o "target/operator" cmd/operator/*.go
|
||||
|
||||
FROM alpine AS runtime
|
||||
COPY --from=builder /build/target/operator /usr/bin/operator
|
||||
|
||||
ENTRYPOINT ["/usr/bin/operator"]
|
||||
@@ -1,31 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
|
||||
"github.com/grafana/authlib/authn"
|
||||
)
|
||||
|
||||
type authRoundTripper struct {
|
||||
tokenExchangeClient *authn.TokenExchangeClient
|
||||
transport http.RoundTripper
|
||||
}
|
||||
|
||||
func (t *authRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
tokenResponse, err := t.tokenExchangeClient.Exchange(req.Context(), authn.TokenExchangeRequest{
|
||||
Audiences: []string{"folder.grafana.app"},
|
||||
Namespace: "*",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to exchange token: %w", err)
|
||||
}
|
||||
|
||||
// clone the request as RTs are not expected to mutate the passed request
|
||||
req = utilnet.CloneRequest(req)
|
||||
|
||||
req.Header.Set("X-Access-Token", "Bearer "+tokenResponse.Token)
|
||||
return t.transport.RoundTrip(req)
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/plugin/kubeconfig"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"github.com/grafana/grafana/pkg/services/authz"
|
||||
)
|
||||
|
||||
const (
|
||||
ConnTypeGRPC = "grpc"
|
||||
ConnTypeHTTP = "http"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
OTelConfig simple.OpenTelemetryConfig
|
||||
WebhookServer WebhookServerConfig
|
||||
KubeConfig *kubeconfig.NamespacedConfig
|
||||
ZanzanaClient authz.ZanzanaClientConfig
|
||||
FolderReconciler FolderReconcilerConfig
|
||||
}
|
||||
|
||||
type WebhookServerConfig struct {
|
||||
Port int
|
||||
TLSCertPath string
|
||||
TLSKeyPath string
|
||||
}
|
||||
|
||||
type FolderReconcilerConfig struct {
|
||||
Namespace string
|
||||
MaxConcurrentWorkers uint64
|
||||
}
|
||||
|
||||
func LoadConfigFromEnv() (*Config, error) {
|
||||
cfg := Config{}
|
||||
cfg.OTelConfig.ServiceName = os.Getenv("OTEL_SERVICE_NAME")
|
||||
switch strings.ToLower(os.Getenv("OTEL_CONN_TYPE")) {
|
||||
case ConnTypeGRPC:
|
||||
cfg.OTelConfig.ConnType = ConnTypeGRPC
|
||||
case ConnTypeHTTP:
|
||||
cfg.OTelConfig.ConnType = ConnTypeHTTP
|
||||
case "":
|
||||
// Default
|
||||
cfg.OTelConfig.ConnType = ConnTypeHTTP
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown OTEL_CONN_TYPE '%s'", os.Getenv("OTEL_CONN_TYPE"))
|
||||
}
|
||||
cfg.OTelConfig.Host = os.Getenv("OTEL_HOST")
|
||||
portStr := os.Getenv("OTEL_PORT")
|
||||
if portStr == "" {
|
||||
if cfg.OTelConfig.ConnType == ConnTypeGRPC {
|
||||
// Default OTel GRPC port
|
||||
cfg.OTelConfig.Port = 4317
|
||||
} else {
|
||||
// Default OTel HTTP port
|
||||
cfg.OTelConfig.Port = 4318
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
cfg.OTelConfig.Port, err = strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid OTEL_PORT '%s': %w", portStr, err)
|
||||
}
|
||||
}
|
||||
|
||||
whPortStr := os.Getenv("WEBHOOK_PORT")
|
||||
if whPortStr == "" {
|
||||
cfg.WebhookServer.Port = 8443
|
||||
} else {
|
||||
var err error
|
||||
cfg.WebhookServer.Port, err = strconv.Atoi(whPortStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid WEBHOOK_PORT '%s': %w", whPortStr, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.WebhookServer.TLSCertPath = os.Getenv("WEBHOOK_CERT_PATH")
|
||||
cfg.WebhookServer.TLSKeyPath = os.Getenv("WEBHOOK_KEY_PATH")
|
||||
|
||||
// Load the kube config
|
||||
kubeConfigFile := os.Getenv("KUBE_CONFIG_FILE")
|
||||
if kubeConfigFile != "" {
|
||||
kubeConfig, err := LoadKubeConfigFromFile(kubeConfigFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load kubernetes configuration from file '%s': %w", kubeConfigFile, err)
|
||||
}
|
||||
cfg.KubeConfig = kubeConfig
|
||||
} else if folderAppURL := os.Getenv("FOLDER_APP_URL"); folderAppURL != "" {
|
||||
exchangeUrl := os.Getenv("TOKEN_EXCHANGE_URL")
|
||||
authToken := os.Getenv("AUTH_TOKEN")
|
||||
namespace := os.Getenv("FOLDER_APP_NAMESPACE")
|
||||
if exchangeUrl == "" || authToken == "" {
|
||||
return nil, fmt.Errorf("TOKEN_EXCHANGE_URL and AUTH_TOKEN must be set when FOLDER_APP_URL is set")
|
||||
}
|
||||
|
||||
kubeConfig, err := LoadKubeConfigFromFolderAppURL(folderAppURL, exchangeUrl, authToken, namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load kubernetes configuration from folder app URL '%s': %w", folderAppURL, err)
|
||||
}
|
||||
cfg.KubeConfig = kubeConfig
|
||||
} else {
|
||||
kubeConfig, err := LoadInClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load in-cluster kubernetes configuration: %w", err)
|
||||
}
|
||||
cfg.KubeConfig = kubeConfig
|
||||
}
|
||||
|
||||
cfg.ZanzanaClient.URL = os.Getenv("ZANZANA_ADDR")
|
||||
cfg.ZanzanaClient.Token = os.Getenv("ZANZANA_TOKEN")
|
||||
cfg.ZanzanaClient.TokenExchangeURL = os.Getenv("TOKEN_EXCHANGE_URL")
|
||||
cfg.ZanzanaClient.ServerCertFile = os.Getenv("ZANZANA_SERVER_CERT_FILE")
|
||||
|
||||
cfg.FolderReconciler.Namespace = os.Getenv("FOLDER_RECONCILER_NAMESPACE")
|
||||
maxConcurrentWorkersStr := os.Getenv("FOLDER_RECONCILER_MAX_CONCURRENT_WORKERS")
|
||||
if maxConcurrentWorkersStr == "" {
|
||||
cfg.FolderReconciler.MaxConcurrentWorkers = 20
|
||||
} else {
|
||||
maxConcurrentWorkers, err := strconv.ParseUint(maxConcurrentWorkersStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid FOLDER_RECONCILER_MAX_CONCURRENT_WORKERS '%s': %w", maxConcurrentWorkersStr, err)
|
||||
}
|
||||
cfg.FolderReconciler.MaxConcurrentWorkers = maxConcurrentWorkers
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/transport"
|
||||
|
||||
"github.com/grafana/authlib/authn"
|
||||
"github.com/grafana/grafana-app-sdk/plugin/kubeconfig"
|
||||
)
|
||||
|
||||
// LoadInClusterConfig loads a kubernetes in-cluster config.
|
||||
// Since the in-cluster config doesn't have a namespace, it defaults to "default"
|
||||
func LoadInClusterConfig() (*kubeconfig.NamespacedConfig, error) {
|
||||
cfg, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.APIPath = "/apis"
|
||||
return &kubeconfig.NamespacedConfig{
|
||||
RestConfig: *cfg,
|
||||
Namespace: "default",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoadKubeConfigFromEnv loads a NamespacedConfig from the value of an environment variable
|
||||
func LoadKubeConfigFromFolderAppURL(folderAppURL, exchangeUrl, authToken, namespace string) (*kubeconfig.NamespacedConfig, error) {
|
||||
tokenExchangeClient, err := authn.NewTokenExchangeClient(authn.TokenExchangeConfig{
|
||||
TokenExchangeURL: exchangeUrl,
|
||||
Token: authToken,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create token exchange client: %w", err)
|
||||
}
|
||||
|
||||
return &kubeconfig.NamespacedConfig{
|
||||
RestConfig: rest.Config{
|
||||
APIPath: "/apis",
|
||||
Host: folderAppURL,
|
||||
WrapTransport: transport.WrapperFunc(func(rt http.RoundTripper) http.RoundTripper {
|
||||
return &authRoundTripper{
|
||||
tokenExchangeClient: tokenExchangeClient,
|
||||
transport: rt,
|
||||
}
|
||||
}),
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
},
|
||||
Namespace: namespace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoadKubeConfigFromFile loads a NamespacedConfig from a file on-disk (such as a mounted secret)
|
||||
func LoadKubeConfigFromFile(configPath string) (*kubeconfig.NamespacedConfig, error) {
|
||||
// Load the kubeconfig file
|
||||
config, err := clientcmd.LoadFromFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load kubeconfig from %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
// Build the REST config from the kubeconfig
|
||||
restConfig, err := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create REST config: %w", err)
|
||||
}
|
||||
|
||||
// Get the namespace from the current context, default to "default" if not set
|
||||
namespace := "default"
|
||||
if config.CurrentContext != "" {
|
||||
if context, exists := config.Contexts[config.CurrentContext]; exists && context.Namespace != "" {
|
||||
namespace = context.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
restConfig.APIPath = "/apis"
|
||||
|
||||
return &kubeconfig.NamespacedConfig{
|
||||
RestConfig: *restConfig,
|
||||
Namespace: namespace,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/k8s"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"github.com/grafana/grafana/apps/iam/pkg/app"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure the default logger to use slog
|
||||
logging.DefaultLogger = logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
}))
|
||||
|
||||
//Load the config from the environment
|
||||
cfg, err := LoadConfigFromEnv()
|
||||
if err != nil {
|
||||
logging.DefaultLogger.With("error", err).Error("Unable to load config from environment")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Set up tracing
|
||||
if cfg.OTelConfig.Host != "" {
|
||||
err = simple.SetTraceProvider(simple.OpenTelemetryConfig{
|
||||
Host: cfg.OTelConfig.Host,
|
||||
Port: cfg.OTelConfig.Port,
|
||||
ConnType: cfg.OTelConfig.ConnType,
|
||||
ServiceName: cfg.OTelConfig.ServiceName,
|
||||
})
|
||||
if err != nil {
|
||||
logging.DefaultLogger.With("error", err).Error("Unable to set trace provider")
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the operator config and the runner
|
||||
operatorConfig := operator.RunnerConfig{
|
||||
KubeConfig: cfg.KubeConfig.RestConfig,
|
||||
WebhookConfig: operator.RunnerWebhookConfig{
|
||||
Port: cfg.WebhookServer.Port,
|
||||
TLSConfig: k8s.TLSConfig{
|
||||
CertPath: cfg.WebhookServer.TLSCertPath,
|
||||
KeyPath: cfg.WebhookServer.TLSKeyPath,
|
||||
},
|
||||
},
|
||||
MetricsConfig: operator.RunnerMetricsConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
runner, err := operator.NewRunner(operatorConfig)
|
||||
if err != nil {
|
||||
logging.DefaultLogger.With("error", err).Error("Unable to create operator runner")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Context and cancel for the operator's Run method
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||
defer cancel()
|
||||
|
||||
// Create app config from operator config
|
||||
appCfg := app.AppConfig{
|
||||
ZanzanaClientCfg: cfg.ZanzanaClient,
|
||||
Namespace: cfg.FolderReconciler.Namespace,
|
||||
InformerConfig: app.InformerConfig{
|
||||
MaxConcurrentWorkers: cfg.FolderReconciler.MaxConcurrentWorkers,
|
||||
},
|
||||
MetricsRegisterer: prometheus.DefaultRegisterer,
|
||||
}
|
||||
|
||||
// Run
|
||||
logging.DefaultLogger.Info("Starting operator")
|
||||
err = runner.Run(ctx, app.Provider(appCfg))
|
||||
if err != nil {
|
||||
logging.DefaultLogger.With("error", err).Error("Operator exited with error")
|
||||
panic(err)
|
||||
}
|
||||
logging.DefaultLogger.Info("Normal operator exit")
|
||||
}
|
||||
+8
-9
@@ -21,18 +21,15 @@ replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator
|
||||
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604
|
||||
|
||||
require (
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c
|
||||
github.com/grafana/grafana v6.1.6+incompatible
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana-app-sdk/plugin v0.45.0
|
||||
github.com/grafana/grafana/apps/folder v0.0.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
go.opentelemetry.io/otel v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/client-go v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
)
|
||||
|
||||
@@ -148,7 +145,7 @@ require (
|
||||
github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/elazarl/goproxy v1.7.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
@@ -204,8 +201,9 @@ require (
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // indirect
|
||||
github.com/grafana/alerting v0.0.0-20251002001425-eeed80da0165 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect
|
||||
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/grafana-aws-sdk v1.2.0 // indirect
|
||||
@@ -424,7 +422,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
@@ -439,6 +437,7 @@ require (
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||
k8s.io/apiserver v0.34.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
k8s.io/component-base v0.34.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kms v0.34.1 // indirect
|
||||
|
||||
+12
-14
@@ -438,8 +438,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=
|
||||
github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
@@ -721,24 +721,22 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d h1:zzEty7HgfXbQ/RiBCJFMqaZiJlqiXuz/Zbc6/H6ksuM=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/alerting v0.0.0-20251002001425-eeed80da0165 h1:wfehM99Xlpltl9MQx8SITkgFgHmPGqrXoBCVLk/Q6NA=
|
||||
github.com/grafana/alerting v0.0.0-20251002001425-eeed80da0165/go.mod h1:VGjS5gDwWEADPP6pF/drqLxEImgeuHlEW5u8E5EfIrM=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA=
|
||||
github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg=
|
||||
github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s=
|
||||
github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grafana/grafana-app-sdk/plugin v0.45.0 h1:rK4FL5h7SqGBDeUdrUjHVGnwgN6w8deQAKx8gJ27Iew=
|
||||
github.com/grafana/grafana-app-sdk/plugin v0.45.0/go.mod h1:fZ6lWVMWr0EpkmyocxZ7MTTc9x6b2jYM93+gjlMgVD4=
|
||||
github.com/grafana/grafana-aws-sdk v1.2.0 h1:LLR4/g91WBuCRwm2cbWfCREq565+GxIFe08nqqIcIuw=
|
||||
github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A=
|
||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 h1:0TYrkzAc3u0HX+9GK86cGrLTUAcmQfl3/LEB3tL+SOA=
|
||||
@@ -1996,8 +1994,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
|
||||
@@ -14,8 +14,8 @@ RoleBindingSpec: {
|
||||
name: string
|
||||
}
|
||||
|
||||
subjects: [...#Subject]
|
||||
roleRef: #RoleRef
|
||||
subject: #Subject
|
||||
roleRefs: [...#RoleRef]
|
||||
}
|
||||
|
||||
GlobalRoleBindingSpec: {
|
||||
@@ -32,6 +32,6 @@ GlobalRoleBindingSpec: {
|
||||
name: string
|
||||
}
|
||||
|
||||
subjects: [...#Subject]
|
||||
roleRef: #RoleRef
|
||||
subject: #Subject
|
||||
roleRefs: [...#RoleRef]
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ TeamBindingSpec: {
|
||||
#Subject: {
|
||||
// uid of the identity
|
||||
name: string
|
||||
// permission of the identity in the team
|
||||
permission: TeamPermission
|
||||
}
|
||||
|
||||
subjects: [...#Subject]
|
||||
subject: #Subject
|
||||
teamRef: TeamRef
|
||||
|
||||
// permission of the identity in the team
|
||||
permission: TeamPermission
|
||||
}
|
||||
|
||||
TeamRef:{
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Build stage
|
||||
FROM golang:1.24.6-alpine AS builder
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install bash (required for update-workspace.sh) and build tools (required for CGO)
|
||||
RUN apk add --no-cache bash build-base
|
||||
|
||||
# Copy source code
|
||||
COPY ./apps ./apps
|
||||
COPY ./pkg ./pkg
|
||||
COPY ./conf ./conf
|
||||
COPY ./go.mod ./go.mod
|
||||
COPY ./go.sum ./go.sum
|
||||
COPY ./go.work ./go.work
|
||||
COPY ./go.work.sum ./go.work.sum
|
||||
COPY ./build.go ./build.go
|
||||
COPY ./package.json ./package.json
|
||||
|
||||
# Update workspace
|
||||
COPY scripts/go-workspace/update-workspace.sh ./scripts/go-workspace/update-workspace.sh
|
||||
RUN bash ./scripts/go-workspace/update-workspace.sh
|
||||
|
||||
# Build the application in dev mode to output binaries directly to ./bin/
|
||||
RUN go run build.go -dev build-backend
|
||||
|
||||
# Final stage
|
||||
FROM alpine:latest
|
||||
|
||||
# Install ca-certificates for HTTPS requests and wget for health checks
|
||||
RUN apk --no-cache add ca-certificates tzdata wget
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S appgroup && \
|
||||
adduser -u 1001 -S appuser -G appgroup
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /usr/share/grafana
|
||||
|
||||
# Copy all built binaries and conf from builder stage
|
||||
COPY --from=builder /app/bin/ ./bin/
|
||||
COPY --from=builder /app/conf/ ./conf/
|
||||
|
||||
# Create necessary directories and add binaries to PATH
|
||||
RUN mkdir -p /etc/grafana-config && \
|
||||
chown -R appuser:appgroup /usr/share/grafana /etc/grafana-config
|
||||
|
||||
# Switch to non-root user
|
||||
USER appuser
|
||||
|
||||
# Add binaries to PATH
|
||||
ENV PATH="/usr/share/grafana/bin:${PATH}"
|
||||
|
||||
# Expose ports for metrics and profiling
|
||||
EXPOSE 8080 6060
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/metrics || exit 1
|
||||
|
||||
# Run the application with the command from the YAML (can be overridden)
|
||||
CMD ["grafana", "server", "target", "--config=/etc/grafana-config/operator.ini", "--homepath=/usr/share/grafana"]
|
||||
@@ -56,7 +56,8 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- grafana-server
|
||||
- grafana
|
||||
- server
|
||||
- target
|
||||
- --config=/etc/grafana-config/operator.ini
|
||||
- --homepath=/usr/share/grafana
|
||||
@@ -78,7 +79,7 @@ spec:
|
||||
secretKeyRef:
|
||||
name: iam-operator-secrets
|
||||
key: grpc_auth_token
|
||||
image: grafana/grafana-dev:12.3.0-17863745596
|
||||
image: iam-folder-reconciler
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: iam-folder-reconciler
|
||||
volumeMounts:
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type CoreRoleClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *CoreRoleClient) Patch(ctx context.Context, identifier resource.Identifi
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *CoreRoleClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CoreRoleStatus, opts resource.UpdateOptions) (*CoreRole, error) {
|
||||
return c.client.Update(ctx, &CoreRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: CoreRoleKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CoreRoleClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type CoreRole struct {
|
||||
|
||||
// Spec is the spec of the CoreRole
|
||||
Spec CoreRoleSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status CoreRoleStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *CoreRole) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *CoreRole) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *CoreRole) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *CoreRole) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *CoreRole) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *CoreRole) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(CoreRoleStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type CoreRoleStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *CoreRole) DeepCopyInto(dst *CoreRole) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *CoreRoleSpec) DeepCopy() *CoreRoleSpec {
|
||||
func (s *CoreRoleSpec) DeepCopyInto(dst *CoreRoleSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of CoreRoleStatus
|
||||
func (s *CoreRoleStatus) DeepCopy() *CoreRoleStatus {
|
||||
cpy := &CoreRoleStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies CoreRoleStatus into another CoreRoleStatus object
|
||||
func (s *CoreRoleStatus) DeepCopyInto(dst *CoreRoleStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type GlobalRoleClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *GlobalRoleClient) Patch(ctx context.Context, identifier resource.Identi
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *GlobalRoleClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus GlobalRoleStatus, opts resource.UpdateOptions) (*GlobalRole, error) {
|
||||
return c.client.Update(ctx, &GlobalRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: GlobalRoleKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *GlobalRoleClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type GlobalRole struct {
|
||||
|
||||
// Spec is the spec of the GlobalRole
|
||||
Spec GlobalRoleSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status GlobalRoleStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *GlobalRole) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *GlobalRole) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *GlobalRole) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *GlobalRole) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *GlobalRole) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *GlobalRole) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(GlobalRoleStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type GlobalRoleStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *GlobalRole) DeepCopyInto(dst *GlobalRole) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *GlobalRoleSpec) DeepCopy() *GlobalRoleSpec {
|
||||
func (s *GlobalRoleSpec) DeepCopyInto(dst *GlobalRoleSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of GlobalRoleStatus
|
||||
func (s *GlobalRoleStatus) DeepCopy() *GlobalRoleStatus {
|
||||
cpy := &GlobalRoleStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies GlobalRoleStatus into another GlobalRoleStatus object
|
||||
func (s *GlobalRoleStatus) DeepCopyInto(dst *GlobalRoleStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type GlobalRoleBindingClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *GlobalRoleBindingClient) Patch(ctx context.Context, identifier resource
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *GlobalRoleBindingClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus GlobalRoleBindingStatus, opts resource.UpdateOptions) (*GlobalRoleBinding, error) {
|
||||
return c.client.Update(ctx, &GlobalRoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: GlobalRoleBindingKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *GlobalRoleBindingClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type GlobalRoleBinding struct {
|
||||
|
||||
// Spec is the spec of the GlobalRoleBinding
|
||||
Spec GlobalRoleBindingSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status GlobalRoleBindingStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *GlobalRoleBinding) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *GlobalRoleBinding) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *GlobalRoleBinding) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *GlobalRoleBinding) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *GlobalRoleBinding) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *GlobalRoleBinding) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(GlobalRoleBindingStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type GlobalRoleBindingStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *GlobalRoleBinding) DeepCopyInto(dst *GlobalRoleBinding) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *GlobalRoleBindingSpec) DeepCopy() *GlobalRoleBindingSpec {
|
||||
func (s *GlobalRoleBindingSpec) DeepCopyInto(dst *GlobalRoleBindingSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of GlobalRoleBindingStatus
|
||||
func (s *GlobalRoleBindingStatus) DeepCopy() *GlobalRoleBindingStatus {
|
||||
cpy := &GlobalRoleBindingStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies GlobalRoleBindingStatus into another GlobalRoleBindingStatus object
|
||||
func (s *GlobalRoleBindingStatus) DeepCopyInto(dst *GlobalRoleBindingStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -30,15 +30,15 @@ func NewGlobalRoleBindingspecRoleRef() *GlobalRoleBindingspecRoleRef {
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GlobalRoleBindingSpec struct {
|
||||
Subjects []GlobalRoleBindingspecSubject `json:"subjects"`
|
||||
RoleRef GlobalRoleBindingspecRoleRef `json:"roleRef"`
|
||||
Subject GlobalRoleBindingspecSubject `json:"subject"`
|
||||
RoleRefs []GlobalRoleBindingspecRoleRef `json:"roleRefs"`
|
||||
}
|
||||
|
||||
// NewGlobalRoleBindingSpec creates a new GlobalRoleBindingSpec object.
|
||||
func NewGlobalRoleBindingSpec() *GlobalRoleBindingSpec {
|
||||
return &GlobalRoleBindingSpec{
|
||||
Subjects: []GlobalRoleBindingspecSubject{},
|
||||
RoleRef: *NewGlobalRoleBindingspecRoleRef(),
|
||||
Subject: *NewGlobalRoleBindingspecSubject(),
|
||||
RoleRefs: []GlobalRoleBindingspecRoleRef{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -205,6 +206,30 @@ var TeamBindingResourceInfo = utils.NewResourceInfo(
|
||||
},
|
||||
)
|
||||
|
||||
var RoleBindingInfo = utils.NewResourceInfo(GROUP, VERSION,
|
||||
"rolebindings", "rolebinding", "RoleBinding",
|
||||
func() runtime.Object { return &RoleBinding{} },
|
||||
func() runtime.Object { return &RoleBindingList{} },
|
||||
utils.TableColumns{
|
||||
Definition: []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Format: "name"},
|
||||
{Name: "Created At", Type: "date"},
|
||||
},
|
||||
Reader: func(obj any) ([]interface{}, error) {
|
||||
roleBinding, ok := obj.(*RoleBinding)
|
||||
if ok {
|
||||
if roleBinding != nil {
|
||||
return []interface{}{
|
||||
roleBinding.Name,
|
||||
roleBinding.CreationTimestamp.UTC().Format(time.RFC3339),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("expected role binding")
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
var (
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
@@ -237,6 +262,8 @@ func AddAuthZKnownTypes(scheme *runtime.Scheme) error {
|
||||
&CoreRoleList{},
|
||||
&Role{},
|
||||
&RoleList{},
|
||||
&RoleBinding{},
|
||||
&RoleBindingList{},
|
||||
|
||||
// What is this about?
|
||||
&metav1.PartialObjectMetadata{},
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type ResourcePermissionClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *ResourcePermissionClient) Patch(ctx context.Context, identifier resourc
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *ResourcePermissionClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ResourcePermissionStatus, opts resource.UpdateOptions) (*ResourcePermission, error) {
|
||||
return c.client.Update(ctx, &ResourcePermission{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: ResourcePermissionKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *ResourcePermissionClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type ResourcePermission struct {
|
||||
|
||||
// Spec is the spec of the ResourcePermission
|
||||
Spec ResourcePermissionSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status ResourcePermissionStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *ResourcePermission) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *ResourcePermission) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *ResourcePermission) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *ResourcePermission) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *ResourcePermission) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *ResourcePermission) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(ResourcePermissionStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type ResourcePermissionStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *ResourcePermission) DeepCopyInto(dst *ResourcePermission) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *ResourcePermissionSpec) DeepCopy() *ResourcePermissionSpec {
|
||||
func (s *ResourcePermissionSpec) DeepCopyInto(dst *ResourcePermissionSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of ResourcePermissionStatus
|
||||
func (s *ResourcePermissionStatus) DeepCopy() *ResourcePermissionStatus {
|
||||
cpy := &ResourcePermissionStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies ResourcePermissionStatus into another ResourcePermissionStatus object
|
||||
func (s *ResourcePermissionStatus) DeepCopyInto(dst *ResourcePermissionStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type RoleClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *RoleClient) Patch(ctx context.Context, identifier resource.Identifier,
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *RoleClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus RoleStatus, opts resource.UpdateOptions) (*Role, error) {
|
||||
return c.client.Update(ctx, &Role{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: RoleKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *RoleClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type Role struct {
|
||||
|
||||
// Spec is the spec of the Role
|
||||
Spec RoleSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status RoleStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *Role) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *Role) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *Role) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *Role) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *Role) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *Role) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(RoleStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type RoleStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *Role) DeepCopyInto(dst *Role) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *RoleSpec) DeepCopy() *RoleSpec {
|
||||
func (s *RoleSpec) DeepCopyInto(dst *RoleSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of RoleStatus
|
||||
func (s *RoleStatus) DeepCopy() *RoleStatus {
|
||||
cpy := &RoleStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies RoleStatus into another RoleStatus object
|
||||
func (s *RoleStatus) DeepCopyInto(dst *RoleStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type RoleBindingClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *RoleBindingClient) Patch(ctx context.Context, identifier resource.Ident
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *RoleBindingClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus RoleBindingStatus, opts resource.UpdateOptions) (*RoleBinding, error) {
|
||||
return c.client.Update(ctx, &RoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: RoleBindingKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *RoleBindingClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type RoleBinding struct {
|
||||
|
||||
// Spec is the spec of the RoleBinding
|
||||
Spec RoleBindingSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status RoleBindingStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *RoleBinding) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *RoleBinding) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *RoleBinding) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *RoleBinding) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *RoleBinding) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *RoleBinding) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(RoleBindingStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type RoleBindingStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *RoleBinding) DeepCopyInto(dst *RoleBinding) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *RoleBindingSpec) DeepCopy() *RoleBindingSpec {
|
||||
func (s *RoleBindingSpec) DeepCopyInto(dst *RoleBindingSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of RoleBindingStatus
|
||||
func (s *RoleBindingStatus) DeepCopy() *RoleBindingStatus {
|
||||
cpy := &RoleBindingStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies RoleBindingStatus into another RoleBindingStatus object
|
||||
func (s *RoleBindingStatus) DeepCopyInto(dst *RoleBindingStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -30,15 +30,15 @@ func NewRoleBindingspecRoleRef() *RoleBindingspecRoleRef {
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type RoleBindingSpec struct {
|
||||
Subjects []RoleBindingspecSubject `json:"subjects"`
|
||||
RoleRef RoleBindingspecRoleRef `json:"roleRef"`
|
||||
Subject RoleBindingspecSubject `json:"subject"`
|
||||
RoleRefs []RoleBindingspecRoleRef `json:"roleRefs"`
|
||||
}
|
||||
|
||||
// NewRoleBindingSpec creates a new RoleBindingSpec object.
|
||||
func NewRoleBindingSpec() *RoleBindingSpec {
|
||||
return &RoleBindingSpec{
|
||||
Subjects: []RoleBindingspecSubject{},
|
||||
RoleRef: *NewRoleBindingspecRoleRef(),
|
||||
Subject: *NewRoleBindingspecSubject(),
|
||||
RoleRefs: []RoleBindingspecRoleRef{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type ServiceAccountClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *ServiceAccountClient) Patch(ctx context.Context, identifier resource.Id
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *ServiceAccountClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ServiceAccountStatus, opts resource.UpdateOptions) (*ServiceAccount, error) {
|
||||
return c.client.Update(ctx, &ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: ServiceAccountKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *ServiceAccountClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type ServiceAccount struct {
|
||||
|
||||
// Spec is the spec of the ServiceAccount
|
||||
Spec ServiceAccountSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status ServiceAccountStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *ServiceAccount) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *ServiceAccount) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *ServiceAccount) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *ServiceAccount) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *ServiceAccount) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *ServiceAccount) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(ServiceAccountStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type ServiceAccountStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *ServiceAccount) DeepCopyInto(dst *ServiceAccount) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *ServiceAccountSpec) DeepCopy() *ServiceAccountSpec {
|
||||
func (s *ServiceAccountSpec) DeepCopyInto(dst *ServiceAccountSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of ServiceAccountStatus
|
||||
func (s *ServiceAccountStatus) DeepCopy() *ServiceAccountStatus {
|
||||
cpy := &ServiceAccountStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies ServiceAccountStatus into another ServiceAccountStatus object
|
||||
func (s *ServiceAccountStatus) DeepCopyInto(dst *ServiceAccountStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type TeamClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *TeamClient) Patch(ctx context.Context, identifier resource.Identifier,
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *TeamClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus TeamStatus, opts resource.UpdateOptions) (*Team, error) {
|
||||
return c.client.Update(ctx, &Team{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: TeamKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *TeamClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type Team struct {
|
||||
|
||||
// Spec is the spec of the Team
|
||||
Spec TeamSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status TeamStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *Team) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *Team) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *Team) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *Team) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *Team) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *Team) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(TeamStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type TeamStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *Team) DeepCopyInto(dst *Team) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *TeamSpec) DeepCopy() *TeamSpec {
|
||||
func (s *TeamSpec) DeepCopyInto(dst *TeamSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of TeamStatus
|
||||
func (s *TeamStatus) DeepCopy() *TeamStatus {
|
||||
cpy := &TeamStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies TeamStatus into another TeamStatus object
|
||||
func (s *TeamStatus) DeepCopyInto(dst *TeamStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type TeamBindingClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *TeamBindingClient) Patch(ctx context.Context, identifier resource.Ident
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *TeamBindingClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus TeamBindingStatus, opts resource.UpdateOptions) (*TeamBinding, error) {
|
||||
return c.client.Update(ctx, &TeamBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: TeamBindingKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *TeamBindingClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type TeamBinding struct {
|
||||
|
||||
// Spec is the spec of the TeamBinding
|
||||
Spec TeamBindingSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status TeamBindingStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *TeamBinding) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *TeamBinding) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *TeamBinding) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *TeamBinding) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *TeamBinding) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *TeamBinding) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(TeamBindingStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type TeamBindingStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *TeamBinding) DeepCopyInto(dst *TeamBinding) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *TeamBindingSpec) DeepCopy() *TeamBindingSpec {
|
||||
func (s *TeamBindingSpec) DeepCopyInto(dst *TeamBindingSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of TeamBindingStatus
|
||||
func (s *TeamBindingStatus) DeepCopy() *TeamBindingStatus {
|
||||
cpy := &TeamBindingStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies TeamBindingStatus into another TeamBindingStatus object
|
||||
func (s *TeamBindingStatus) DeepCopyInto(dst *TeamBindingStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ package v0alpha1
|
||||
type TeamBindingspecSubject struct {
|
||||
// uid of the identity
|
||||
Name string `json:"name"`
|
||||
// permission of the identity in the team
|
||||
Permission TeamBindingTeamPermission `json:"permission"`
|
||||
}
|
||||
|
||||
// NewTeamBindingspecSubject creates a new TeamBindingspecSubject object.
|
||||
@@ -15,14 +13,6 @@ func NewTeamBindingspecSubject() *TeamBindingspecSubject {
|
||||
return &TeamBindingspecSubject{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamBindingTeamPermission string
|
||||
|
||||
const (
|
||||
TeamBindingTeamPermissionAdmin TeamBindingTeamPermission = "admin"
|
||||
TeamBindingTeamPermissionMember TeamBindingTeamPermission = "member"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamBindingTeamRef struct {
|
||||
// Name is the unique identifier for a team.
|
||||
@@ -34,16 +24,26 @@ func NewTeamBindingTeamRef() *TeamBindingTeamRef {
|
||||
return &TeamBindingTeamRef{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamBindingTeamPermission string
|
||||
|
||||
const (
|
||||
TeamBindingTeamPermissionAdmin TeamBindingTeamPermission = "admin"
|
||||
TeamBindingTeamPermissionMember TeamBindingTeamPermission = "member"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamBindingSpec struct {
|
||||
Subjects []TeamBindingspecSubject `json:"subjects"`
|
||||
TeamRef TeamBindingTeamRef `json:"teamRef"`
|
||||
Subject TeamBindingspecSubject `json:"subject"`
|
||||
TeamRef TeamBindingTeamRef `json:"teamRef"`
|
||||
// permission of the identity in the team
|
||||
Permission TeamBindingTeamPermission `json:"permission"`
|
||||
}
|
||||
|
||||
// NewTeamBindingSpec creates a new TeamBindingSpec object.
|
||||
func NewTeamBindingSpec() *TeamBindingSpec {
|
||||
return &TeamBindingSpec{
|
||||
Subjects: []TeamBindingspecSubject{},
|
||||
TeamRef: *NewTeamBindingTeamRef(),
|
||||
Subject: *NewTeamBindingspecSubject(),
|
||||
TeamRef: *NewTeamBindingTeamRef(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type UserClient struct {
|
||||
@@ -76,24 +75,6 @@ func (c *UserClient) Patch(ctx context.Context, identifier resource.Identifier,
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *UserClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus UserStatus, opts resource.UpdateOptions) (*User, error) {
|
||||
return c.client.Update(ctx, &User{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: UserKind().Kind(),
|
||||
APIVersion: GroupVersion.Identifier(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
Subresource: "status",
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *UserClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||
return c.client.Delete(ctx, identifier, opts)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ type User struct {
|
||||
|
||||
// Spec is the spec of the User
|
||||
Spec UserSpec `json:"spec" yaml:"spec"`
|
||||
|
||||
Status UserStatus `json:"status" yaml:"status"`
|
||||
}
|
||||
|
||||
func (o *User) GetSpec() any {
|
||||
@@ -39,15 +37,11 @@ func (o *User) SetSpec(spec any) error {
|
||||
}
|
||||
|
||||
func (o *User) GetSubresources() map[string]any {
|
||||
return map[string]any{
|
||||
"status": o.Status,
|
||||
}
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
func (o *User) GetSubresource(name string) (any, bool) {
|
||||
switch name {
|
||||
case "status":
|
||||
return o.Status, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
@@ -55,13 +49,6 @@ func (o *User) GetSubresource(name string) (any, bool) {
|
||||
|
||||
func (o *User) SetSubresource(name string, value any) error {
|
||||
switch name {
|
||||
case "status":
|
||||
cast, ok := value.(UserStatus)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot set status type %#v, not of type UserStatus", value)
|
||||
}
|
||||
o.Status = cast
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||
}
|
||||
@@ -233,7 +220,6 @@ func (o *User) DeepCopyInto(dst *User) {
|
||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||
o.Spec.DeepCopyInto(&dst.Spec)
|
||||
o.Status.DeepCopyInto(&dst.Status)
|
||||
}
|
||||
|
||||
// Interface compliance compile-time check
|
||||
@@ -305,15 +291,3 @@ func (s *UserSpec) DeepCopy() *UserSpec {
|
||||
func (s *UserSpec) DeepCopyInto(dst *UserSpec) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
// DeepCopy creates a full deep copy of UserStatus
|
||||
func (s *UserStatus) DeepCopy() *UserStatus {
|
||||
cpy := &UserStatus{}
|
||||
s.DeepCopyInto(cpy)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// DeepCopyInto deep copies UserStatus into another UserStatus object
|
||||
func (s *UserStatus) DeepCopyInto(dst *UserStatus) {
|
||||
resource.CopyObjectInto(dst, s)
|
||||
}
|
||||
|
||||
@@ -109,18 +109,12 @@ func schema_pkg_apis_iam_v0alpha1_CoreRole(ref common.ReferenceCallback) common.
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.CoreRoleSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.CoreRoleStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.CoreRoleSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.CoreRoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.CoreRoleSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,18 +381,12 @@ func schema_pkg_apis_iam_v0alpha1_GlobalRole(ref common.ReferenceCallback) commo
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,18 +423,12 @@ func schema_pkg_apis_iam_v0alpha1_GlobalRoleBinding(ref common.ReferenceCallback
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,27 +486,27 @@ func schema_pkg_apis_iam_v0alpha1_GlobalRoleBindingSpec(ref common.ReferenceCall
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"subjects": {
|
||||
"subject": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingspecSubject"),
|
||||
},
|
||||
},
|
||||
"roleRefs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingspecSubject"),
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingspecRoleRef"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"roleRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.GlobalRoleBindingspecRoleRef"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"subjects", "roleRef"},
|
||||
Required: []string{"subject", "roleRefs"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
@@ -948,18 +930,12 @@ func schema_pkg_apis_iam_v0alpha1_ResourcePermission(ref common.ReferenceCallbac
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ResourcePermissionSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ResourcePermissionStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ResourcePermissionSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ResourcePermissionStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ResourcePermissionSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,18 +1223,12 @@ func schema_pkg_apis_iam_v0alpha1_Role(ref common.ReferenceCallback) common.Open
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1295,18 +1265,12 @@ func schema_pkg_apis_iam_v0alpha1_RoleBinding(ref common.ReferenceCallback) comm
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,27 +1328,27 @@ func schema_pkg_apis_iam_v0alpha1_RoleBindingSpec(ref common.ReferenceCallback)
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"subjects": {
|
||||
"subject": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingspecSubject"),
|
||||
},
|
||||
},
|
||||
"roleRefs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingspecSubject"),
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingspecRoleRef"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"roleRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.RoleBindingspecRoleRef"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"subjects", "roleRef"},
|
||||
Required: []string{"subject", "roleRefs"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
@@ -1808,18 +1772,12 @@ func schema_pkg_apis_iam_v0alpha1_ServiceAccount(ref common.ReferenceCallback) c
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ServiceAccountSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ServiceAccountStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ServiceAccountSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ServiceAccountStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.ServiceAccountSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2040,18 +1998,12 @@ func schema_pkg_apis_iam_v0alpha1_Team(ref common.ReferenceCallback) common.Open
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2088,18 +2040,12 @@ func schema_pkg_apis_iam_v0alpha1_TeamBinding(ref common.ReferenceCallback) comm
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2157,17 +2103,10 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref common.ReferenceCallback)
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"subjects": {
|
||||
"subject": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject"),
|
||||
},
|
||||
},
|
||||
"teamRef": {
|
||||
@@ -2176,8 +2115,16 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref common.ReferenceCallback)
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingTeamRef"),
|
||||
},
|
||||
},
|
||||
"permission": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "permission of the identity in the team",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"subjects", "teamRef"},
|
||||
Required: []string{"subject", "teamRef", "permission"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
@@ -2264,16 +2211,8 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingspecSubject(ref common.ReferenceCal
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"permission": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "permission of the identity in the team",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"name", "permission"},
|
||||
Required: []string{"name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -2547,18 +2486,12 @@ func schema_pkg_apis_iam_v0alpha1_User(ref common.ReferenceCallback) common.Open
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"metadata", "spec", "status"},
|
||||
Required: []string{"metadata", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec", "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.UserSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,9 @@ import (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "iam",
|
||||
Group: "iam.grafana.app",
|
||||
AppName: "iam",
|
||||
Group: "iam.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
+10
-11
@@ -36,7 +36,7 @@ func Provider(appCfg app.SpecificConfig) app.Provider {
|
||||
}
|
||||
|
||||
func generateInformerSupplier(informerConfig InformerConfig, metrics *reconcilers.ReconcilerMetrics) simple.InformerSupplier {
|
||||
return func(kind resource.Kind, clients resource.ClientGenerator, options operator.ListWatchOptions) (operator.Informer, error) {
|
||||
return func(kind resource.Kind, clients resource.ClientGenerator, options operator.InformerOptions) (operator.Informer, error) {
|
||||
client, err := clients.ClientFor(kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -44,9 +44,7 @@ func generateInformerSupplier(informerConfig InformerConfig, metrics *reconciler
|
||||
|
||||
informer, err := operator.NewKubernetesBasedInformer(
|
||||
kind, client,
|
||||
operator.KubernetesBasedInformerOptions{
|
||||
ListWatchOptions: options,
|
||||
},
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -79,7 +77,6 @@ func New(cfg app.Config) (app.App, error) {
|
||||
|
||||
folderReconciler, err := reconcilers.NewFolderReconciler(reconcilers.ReconcilerConfig{
|
||||
ZanzanaCfg: appSpecificConfig.ZanzanaClientCfg,
|
||||
KubeConfig: &cfg.KubeConfig,
|
||||
Metrics: metrics,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -93,12 +90,14 @@ func New(cfg app.Config) (app.App, error) {
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerSupplier: generateInformerSupplier(appSpecificConfig.InformerConfig, metrics),
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).With("error", err).Error("Informer processing error")
|
||||
if metrics != nil {
|
||||
// Use "unknown" for action since top-level informer errors don't have specific actions
|
||||
metrics.RecordReconcileFailure("unknown", "informer")
|
||||
}
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).With("error", err).Error("Informer processing error")
|
||||
if metrics != nil {
|
||||
// Use "unknown" for action since top-level informer errors don't have specific actions
|
||||
metrics.RecordReconcileFailure("unknown", "informer")
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
UnmanagedKinds: []simple.AppUnmanagedKind{
|
||||
|
||||
@@ -8,19 +8,14 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/services/authz"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// FolderStore interface for retrieving folder information
|
||||
type FolderStore interface {
|
||||
GetFolderParent(ctx context.Context, namespace, uid string) (string, error)
|
||||
}
|
||||
|
||||
// PermissionStore interface for managing folder permissions
|
||||
type PermissionStore interface {
|
||||
GetFolderParents(ctx context.Context, namespace, folderUID string) ([]string, error)
|
||||
@@ -31,13 +26,11 @@ type PermissionStore interface {
|
||||
// ReconcilerConfig represents the app-specific configuration
|
||||
type ReconcilerConfig struct {
|
||||
ZanzanaCfg authz.ZanzanaClientConfig
|
||||
KubeConfig *rest.Config
|
||||
Metrics *ReconcilerMetrics
|
||||
}
|
||||
|
||||
type FolderReconciler struct {
|
||||
permissionStore PermissionStore
|
||||
folderStore FolderStore
|
||||
metrics *ReconcilerMetrics
|
||||
}
|
||||
|
||||
@@ -50,12 +43,10 @@ func NewFolderReconciler(cfg ReconcilerConfig) (operator.Reconciler, error) {
|
||||
}
|
||||
|
||||
// Create dependencies
|
||||
folderStore := NewAPIFolderStore(cfg.KubeConfig)
|
||||
permissionStore := NewZanzanaPermissionStore(zanzanaClient)
|
||||
|
||||
folderReconciler := &FolderReconciler{
|
||||
permissionStore: permissionStore,
|
||||
folderStore: folderStore,
|
||||
metrics: cfg.Metrics,
|
||||
}
|
||||
|
||||
@@ -137,11 +128,11 @@ func (r *FolderReconciler) handleUpdateFolder(ctx context.Context, folder *folde
|
||||
folderUID := folder.Name
|
||||
namespace := folder.Namespace
|
||||
|
||||
parentUID, err := r.folderStore.GetFolderParent(ctx, namespace, folderUID)
|
||||
parentUID, err := getFolderParent(ctx, folder)
|
||||
if err != nil {
|
||||
logger.Error("Error getting folder parent", "error", err)
|
||||
if r.metrics != nil {
|
||||
r.metrics.RecordReconcileFailure(action, "folder_store")
|
||||
r.metrics.RecordReconcileFailure(action, "failure_informer")
|
||||
}
|
||||
return operator.ReconcileResult{}, err
|
||||
}
|
||||
@@ -217,3 +208,21 @@ func validateFolder(folder *foldersKind.Folder) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFolderParent(ctx context.Context, folder *foldersKind.Folder) (string, error) {
|
||||
tracer := otel.GetTracerProvider().Tracer("iam-folder-reconciler")
|
||||
_, span := tracer.Start(ctx, "get-folder-parent",
|
||||
trace.WithAttributes(
|
||||
attribute.String("folder.uid", folder.Name),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
folderMeta, err := utils.MetaAccessor(folder)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "failed to get folder meta accessor")
|
||||
return "", err
|
||||
}
|
||||
return folderMeta.GetFolder(), nil
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package reconcilers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
var _ FolderStore = (*APIFolderStore)(nil)
|
||||
|
||||
func NewAPIFolderStore(config *rest.Config) FolderStore {
|
||||
return &APIFolderStore{config}
|
||||
}
|
||||
|
||||
type APIFolderStore struct {
|
||||
config *rest.Config
|
||||
}
|
||||
|
||||
func (s *APIFolderStore) GetFolderParent(ctx context.Context, namespace, uid string) (string, error) {
|
||||
tracer := otel.GetTracerProvider().Tracer("iam-folder-reconciler")
|
||||
ctx, span := tracer.Start(ctx, "APIFolderStore.GetFolderParent",
|
||||
trace.WithAttributes(
|
||||
attribute.String("folder.uid", uid),
|
||||
attribute.String("folder.namespace", namespace),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
client, err := s.client(namespace)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "failed to create kubernetes client")
|
||||
return "", fmt.Errorf("create resource client: %w", err)
|
||||
}
|
||||
|
||||
// Get the folder by UID
|
||||
unstructuredObj, err := client.Get(ctx, uid, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "failed to get folder from kubernetes API")
|
||||
return "", fmt.Errorf("get folder %s: %w", uid, err)
|
||||
}
|
||||
|
||||
object, err := utils.MetaAccessor(unstructuredObj)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "failed to get meta accessor from folder object")
|
||||
return "", fmt.Errorf("get meta accessor: %w", err)
|
||||
}
|
||||
|
||||
parentUID := object.GetFolder()
|
||||
span.SetAttributes(attribute.String("folder.parent_uid", parentUID))
|
||||
span.SetStatus(codes.Ok, "successfully retrieved folder parent")
|
||||
span.AddEvent("folder.parent.retrieved", trace.WithAttributes(
|
||||
attribute.String("parent.uid", parentUID),
|
||||
))
|
||||
|
||||
return parentUID, nil
|
||||
}
|
||||
|
||||
func (s *APIFolderStore) client(namespace string) (dynamic.ResourceInterface, error) {
|
||||
client, err := dynamic.NewForConfig(s.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client.Resource(foldersKind.FolderResourceInfo.GroupVersionResource()).Namespace(namespace), nil
|
||||
}
|
||||
@@ -22,7 +22,6 @@ func NewReconcilerMetrics(registerer prometheus.Registerer, namespace string) *R
|
||||
"success_no_changes_needed",
|
||||
"failure_informer",
|
||||
"failure_permission_store",
|
||||
"failure_folder_store",
|
||||
"failure_unknown",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/investigations
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -78,7 +78,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
||||
@@ -10,8 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
@@ -46,8 +46,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -76,7 +76,7 @@ func (c *InvestigationClient) Patch(ctx context.Context, identifier resource.Ide
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *InvestigationClient) UpdateStatus(ctx context.Context, newStatus InvestigationStatus, opts resource.UpdateOptions) (*Investigation, error) {
|
||||
func (c *InvestigationClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus InvestigationStatus, opts resource.UpdateOptions) (*Investigation, error) {
|
||||
return c.client.Update(ctx, &Investigation{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: InvestigationKind().Kind(),
|
||||
@@ -84,6 +84,8 @@ func (c *InvestigationClient) UpdateStatus(ctx context.Context, newStatus Invest
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
|
||||
+3
-1
@@ -76,7 +76,7 @@ func (c *InvestigationIndexClient) Patch(ctx context.Context, identifier resourc
|
||||
return c.client.Patch(ctx, identifier, req, opts)
|
||||
}
|
||||
|
||||
func (c *InvestigationIndexClient) UpdateStatus(ctx context.Context, newStatus InvestigationIndexStatus, opts resource.UpdateOptions) (*InvestigationIndex, error) {
|
||||
func (c *InvestigationIndexClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus InvestigationIndexStatus, opts resource.UpdateOptions) (*InvestigationIndex, error) {
|
||||
return c.client.Update(ctx, &InvestigationIndex{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: InvestigationIndexKind().Kind(),
|
||||
@@ -84,6 +84,8 @@ func (c *InvestigationIndexClient) UpdateStatus(ctx context.Context, newStatus I
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: opts.ResourceVersion,
|
||||
Namespace: identifier.Namespace,
|
||||
Name: identifier.Name,
|
||||
},
|
||||
Status: newStatus,
|
||||
}, resource.UpdateOptions{
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
|
||||
v0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1"
|
||||
)
|
||||
@@ -27,8 +28,9 @@ var (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "investigations",
|
||||
Group: "investigations.grafana.app",
|
||||
AppName: "investigations",
|
||||
Group: "investigations.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
@@ -50,6 +52,10 @@ var appManifestData = app.ManifestData{
|
||||
Schema: &versionSchemaInvestigationIndexv0alpha1,
|
||||
},
|
||||
},
|
||||
Routes: app.ManifestVersionRoutes{
|
||||
Namespaced: map[string]spec3.PathProps{},
|
||||
Cluster: map[string]spec3.PathProps{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -79,6 +85,7 @@ var customRouteToGoResponseType = map[string]any{}
|
||||
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
||||
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
||||
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
||||
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
|
||||
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
path = path[1:]
|
||||
@@ -97,8 +104,22 @@ func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goTyp
|
||||
return goType, exists
|
||||
}
|
||||
|
||||
var customRouteToGoRequestBodyType = map[string]any{}
|
||||
|
||||
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||
return goType, exists
|
||||
}
|
||||
|
||||
type GoTypeAssociator struct{}
|
||||
|
||||
func NewGoTypeAssociator() *GoTypeAssociator {
|
||||
return &GoTypeAssociator{}
|
||||
}
|
||||
|
||||
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
||||
return ManifestGoTypeAssociator(kind, version)
|
||||
}
|
||||
@@ -108,3 +129,6 @@ func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb str
|
||||
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
||||
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
||||
}
|
||||
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
|
||||
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/operator"
|
||||
"github.com/grafana/grafana-app-sdk/resource"
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -18,8 +19,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "investigation",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(_ context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(_ context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/playlist
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk v0.46.0
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/client-go v0.34.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
@@ -16,7 +16,7 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||
@@ -79,7 +79,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
||||
@@ -10,8 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
@@ -46,8 +46,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0/go.mod h1:1pYGEBrgG8i6pKmmsNXvtAr15jZ4iLtyHU4yj7T6XaI=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
@@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -25,8 +25,9 @@ var (
|
||||
)
|
||||
|
||||
var appManifestData = app.ManifestData{
|
||||
AppName: "playlist",
|
||||
Group: "playlist.grafana.app",
|
||||
AppName: "playlist",
|
||||
Group: "playlist.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
||||
@@ -50,8 +50,10 @@ func New(cfg app.Config) (app.App, error) {
|
||||
Name: "playlist",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user