mirror of https://github.com/grafana/grafana.git
Merge remote-tracking branch 'origin/main' into team-user-folder-validation
CodeQL checks / Detect whether code changed (push) Waiting to run
Details
CodeQL checks / Analyze (actions) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (go) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (javascript) (push) Blocked by required conditions
Details
CodeQL checks / Detect whether code changed (push) Waiting to run
Details
CodeQL checks / Analyze (actions) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (go) (push) Blocked by required conditions
Details
CodeQL checks / Analyze (javascript) (push) Blocked by required conditions
Details
This commit is contained in:
commit
829770e6eb
|
@ -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
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
# START Technical documentation
|
||||
/.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
|
||||
|
||||
|
@ -86,6 +88,7 @@
|
|||
/apps/preferences/ @grafana/grafana-app-platform-squad @grafana/grafana-frontend-platform
|
||||
/apps/shorturl/ @grafana/sharing-squad
|
||||
/apps/secret/ @grafana/grafana-operator-experience-squad
|
||||
/apps/scope/ @grafana/grafana-operator-experience-squad
|
||||
/apps/investigations/ @fcjack @matryer @svennergr
|
||||
/apps/advisor/ @grafana/plugins-platform-backend
|
||||
/apps/iam/ @grafana/access-squad
|
||||
|
@ -627,6 +630,7 @@
|
|||
/packages/grafana-runtime/rollup.config.ts @grafana/grafana-frontend-platform
|
||||
/packages/grafana-runtime/src/index.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
|
||||
/packages/grafana-runtime/src/internal/index.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
|
||||
/packages/grafana-runtime/src/internal/openFeature @grafana/grafana-frontend-platform
|
||||
/packages/grafana-runtime/src/unstable.ts @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
|
||||
/packages/grafana-runtime/tsconfig.build.json @grafana/grafana-frontend-platform
|
||||
/packages/grafana-runtime/tsconfig.json @grafana/grafana-frontend-platform
|
||||
|
@ -1279,6 +1283,7 @@ embed.go @grafana/grafana-as-code
|
|||
/.github/license_finder.yaml @bergquist
|
||||
/.github/actionlint.yaml @grafana/grafana-developer-enablement-squad
|
||||
/.github/workflows/pr-test-docker.yml @grafana/grafana-developer-enablement-squad
|
||||
/.github/workflows/update-schema-types.yml @grafana/plugins-platform-frontend
|
||||
|
||||
# Generated files not requiring owner approval
|
||||
/packages/grafana-data/src/types/featureToggles.gen.ts @grafanabot
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
name: Update Schema Types
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- docs/sources/developers/plugins/plugin.schema.json
|
||||
workflow_dispatch:
|
||||
|
||||
# These permissions are needed to assume roles from Github's OIDC.
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
bundle-schema-types:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: grafana/plugin-actions/bundle-schema-types@main
|
|
@ -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 -->
|
|
@ -99,6 +99,7 @@ COPY apps/correlations apps/correlations
|
|||
COPY apps/preferences apps/preferences
|
||||
COPY apps/provisioning apps/provisioning
|
||||
COPY apps/secret apps/secret
|
||||
COPY apps/scope apps/scope
|
||||
COPY apps/investigations apps/investigations
|
||||
COPY apps/advisor apps/advisor
|
||||
COPY apps/dashboard apps/dashboard
|
||||
|
|
5
Makefile
5
Makefile
|
@ -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,10 +49,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "advisor",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
log.WithContext(ctx).Error("Informer processing error", "error", err)
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: advisorv0alpha1.CheckKind(),
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -36,6 +36,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
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,10 +23,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "alerting.notification",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
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=
|
||||
|
|
|
@ -30,6 +30,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
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,10 +23,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "alerting.rules",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
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,17 +10,16 @@ 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)
|
||||
)
|
||||
|
@ -28,6 +27,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
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,10 +18,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "correlation",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).Error("Informer processing error", "error", err)
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: correlationsv0alpha1.CorrelationKind(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
var appManifestData = app.ManifestData{
|
||||
AppName: "dashboard",
|
||||
Group: "dashboard.grafana.app",
|
||||
PreferredVersion: "v1beta1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
|
|
@ -198,7 +198,7 @@ func sortPanelsByGridPos(dashboard map[string]interface{}) {
|
|||
return
|
||||
}
|
||||
|
||||
sort.Slice(panels, func(i, j int) bool {
|
||||
sort.SliceStable(panels, func(i, j int) bool {
|
||||
panelA := panels[i]
|
||||
panelB := panels[j]
|
||||
|
||||
|
@ -831,7 +831,7 @@ func cleanupPanelList(panels []interface{}) {
|
|||
|
||||
// sortPanelsByGridPosition sorts panels by grid position (matches frontend sortPanelsByGridPos behavior)
|
||||
func sortPanelsByGridPosition(panels []interface{}) {
|
||||
sort.Slice(panels, func(i, j int) bool {
|
||||
sort.SliceStable(panels, func(i, j int) bool {
|
||||
panelA, okA := panels[i].(map[string]interface{})
|
||||
panelB, okB := panels[j].(map[string]interface{})
|
||||
if !okA || !okB {
|
||||
|
|
|
@ -49,10 +49,15 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
maxPanelID := getMaxPanelID(rows)
|
||||
nextRowID := maxPanelID + 1
|
||||
|
||||
// Get existing panels
|
||||
var finalPanels []interface{}
|
||||
if existingPanels, ok := dashboard["panels"].([]interface{}); ok {
|
||||
finalPanels = existingPanels
|
||||
// Match frontend: dashboard.panels already exists with top-level panels
|
||||
// The frontend's this.dashboard.panels is initialized in the constructor with existing panels
|
||||
// Then upgradeToGridLayout adds more panels to it
|
||||
|
||||
// Initialize panels array - make a copy to avoid modifying the original
|
||||
panels := []interface{}{}
|
||||
if existingPanels, ok := dashboard["panels"].([]interface{}); ok && len(existingPanels) > 0 {
|
||||
// Copy existing panels to preserve order
|
||||
panels = append(panels, existingPanels...)
|
||||
}
|
||||
|
||||
// Add special "row" panels if even one row is collapsed, repeated or has visible title (line 1028 in TS)
|
||||
|
@ -72,7 +77,14 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
|
||||
height := getRowHeight(row)
|
||||
rowGridHeight := getGridHeight(height)
|
||||
isCollapsed := GetBoolValue(row, "collapse")
|
||||
// Check if collapse property exists and get its value
|
||||
collapseValue, hasCollapseProperty := row["collapse"]
|
||||
isCollapsed := false
|
||||
if hasCollapseProperty {
|
||||
if b, ok := collapseValue.(bool); ok {
|
||||
isCollapsed = b
|
||||
}
|
||||
}
|
||||
|
||||
var rowPanel map[string]interface{}
|
||||
|
||||
|
@ -110,9 +122,9 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
},
|
||||
}
|
||||
|
||||
// Set collapsed property only if the original row had a collapse property
|
||||
// This matches the frontend behavior: rowPanel.collapsed = row.collapse
|
||||
if _, hasCollapse := row["collapse"]; hasCollapse {
|
||||
// Match frontend behavior: rowPanel.collapsed = row.collapse (line 1065 in TS)
|
||||
// Only set collapsed property if the original row had a collapse property
|
||||
if hasCollapseProperty {
|
||||
rowPanel["collapsed"] = isCollapsed
|
||||
}
|
||||
nextRowID++
|
||||
|
@ -128,23 +140,13 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
continue
|
||||
}
|
||||
|
||||
// Set default span (line 1063 in TS)
|
||||
span := GetFloatValue(panel, "span", defaultPanelSpan)
|
||||
|
||||
// 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))
|
||||
}
|
||||
// Match frontend logic: panel.span = panel.span || DEFAULT_PANEL_SPAN (line 1082 in TS)
|
||||
span := GetFloatValue(panel, "span", 0)
|
||||
if span == 0 {
|
||||
span = defaultPanelSpan
|
||||
}
|
||||
|
||||
panelWidth := int(math.Floor(span * widthFactor))
|
||||
panelHeight := rowGridHeight
|
||||
if panelHeightValue, hasHeight := panel["height"]; hasHeight {
|
||||
if h, ok := ConvertToFloat(panelHeightValue); ok {
|
||||
panelHeight = getGridHeight(h)
|
||||
}
|
||||
}
|
||||
panelWidth, panelHeight := calculatePanelDimensionsFromSpan(span, panel, widthFactor, rowGridHeight)
|
||||
|
||||
panelPos := rowArea.getPanelPosition(panelHeight, panelWidth)
|
||||
yPos = rowArea.yPos
|
||||
|
@ -161,21 +163,21 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
// Remove span (line 1080 in TS)
|
||||
delete(panel, "span")
|
||||
|
||||
// Exact logic from lines 1082-1086 in TS
|
||||
// Match frontend logic: lines 1101-1105 in TS
|
||||
if rowPanel != nil && isCollapsed {
|
||||
// Add to collapsed row's nested panels
|
||||
// Add to collapsed row's nested panels (line 1102)
|
||||
if rowPanelPanels, ok := rowPanel["panels"].([]interface{}); ok {
|
||||
rowPanel["panels"] = append(rowPanelPanels, panel)
|
||||
}
|
||||
} else {
|
||||
// Add directly to dashboard panels
|
||||
finalPanels = append(finalPanels, panel)
|
||||
// Add directly to panels array like frontend (line 1104)
|
||||
panels = append(panels, panel)
|
||||
}
|
||||
}
|
||||
|
||||
// Add row panel after processing all panels (lines 1089-1091 in TS)
|
||||
// Add row panel after regular panels from this row (lines 1108-1110 in TS)
|
||||
if rowPanel != nil {
|
||||
finalPanels = append(finalPanels, rowPanel)
|
||||
panels = append(panels, rowPanel)
|
||||
}
|
||||
|
||||
// Update yPos (lines 1093-1095 in TS)
|
||||
|
@ -185,7 +187,7 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
|
|||
}
|
||||
|
||||
// Update the dashboard
|
||||
dashboard["panels"] = finalPanels
|
||||
dashboard["panels"] = panels
|
||||
delete(dashboard, "rows")
|
||||
}
|
||||
|
||||
|
@ -315,3 +317,24 @@ 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) {
|
||||
// span should already be normalized by caller (line 1082 in DashboardMigrator.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 := defaultHeight
|
||||
|
||||
if panelHeightValue, hasHeight := panel["height"]; hasHeight {
|
||||
if h, ok := ConvertToFloat(panelHeightValue); ok {
|
||||
panelHeight = getGridHeight(h)
|
||||
}
|
||||
}
|
||||
|
||||
return panelWidth, panelHeight
|
||||
}
|
||||
|
|
|
@ -1532,6 +1532,123 @@ func TestV16(t *testing.T) {
|
|||
// rows field should be removed
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should handle span zero by defaulting to DEFAULT_PANEL_SPAN",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 15,
|
||||
"rows": []interface{}{
|
||||
map[string]interface{}{
|
||||
"collapse": false,
|
||||
"showTitle": true, // Need this to create row panel
|
||||
"title": "Test Row",
|
||||
"height": 250,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"type": "graph",
|
||||
"span": 0, // This should be defaulted to 4 (DEFAULT_PANEL_SPAN)
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"type": "stat",
|
||||
"span": 6, // Normal span value
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 16,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"type": "graph",
|
||||
"gridPos": map[string]interface{}{
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"w": 8, // span 0 -> DEFAULT_PANEL_SPAN (4) -> 4 * 2 = 8 width
|
||||
"h": 7, // default height
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"type": "stat",
|
||||
"gridPos": map[string]interface{}{
|
||||
"x": 8, // After first panel
|
||||
"y": 1,
|
||||
"w": 12, // span 6 -> 6 * 2 = 12 width
|
||||
"h": 7, // default height
|
||||
},
|
||||
},
|
||||
// Row panel should be created because showTitle is true
|
||||
map[string]interface{}{
|
||||
"id": 3,
|
||||
"type": "row",
|
||||
"title": "Test Row",
|
||||
"collapsed": false, // Set because input has "collapse": false
|
||||
"repeat": "",
|
||||
"panels": []interface{}{},
|
||||
"gridPos": map[string]interface{}{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 24,
|
||||
"h": 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should not set collapsed property when input row has no collapse property",
|
||||
input: map[string]interface{}{
|
||||
"schemaVersion": 15,
|
||||
"rows": []interface{}{
|
||||
map[string]interface{}{
|
||||
// No "collapse" property in input
|
||||
"showTitle": true,
|
||||
"title": "Test Row",
|
||||
"height": 250,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"type": "graph",
|
||||
"span": 12,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"schemaVersion": 16,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"type": "graph",
|
||||
"gridPos": map[string]interface{}{
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"w": 24, // span 12 -> 12 * 2 = 24 width
|
||||
"h": 7, // default height
|
||||
},
|
||||
},
|
||||
// Row panel should be created because showTitle is true
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"type": "row",
|
||||
"title": "Test Row",
|
||||
// No "collapsed" property because input had no "collapse" property
|
||||
"repeat": "",
|
||||
"panels": []interface{}{},
|
||||
"gridPos": map[string]interface{}{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 24,
|
||||
"h": 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runMigrationTests(t, tests, schemaversion.V16)
|
||||
|
|
|
@ -0,0 +1,687 @@
|
|||
{
|
||||
"__requires": [
|
||||
{
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"type": "grafana",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": false,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"links": [
|
||||
{
|
||||
"icon": "external link",
|
||||
"targetBlank": true,
|
||||
"title": "External Documentation",
|
||||
"type": "link",
|
||||
"url": "https://example.com/docs"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"options": {
|
||||
"content": "This dashboard demonstrates various monitoring components for application observability and performance metrics.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Application Monitoring",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"refresh": "10s",
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"collapsed": false,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 5
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"content": "This service handles background processing tasks for the application system. It manages various types of operations including data synchronization, resource management, and batch processing.\n\nSupported operation types:\n1. Sync: Synchronizes data between different systems\n2. Process: Handles batch data processing tasks\n3. Cleanup: Removes outdated or temporary resources\n4. Update: Applies configuration changes across services\n\nService dependencies:\n- Data API: For reading and writing application data\n- Configuration Service: For managing system settings\n- Queue Service: For handling task scheduling\n- Storage Service: For persistent data management\n- Auth Service: For authentication and authorization\n- Metrics Service: For collecting operational statistics\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"span": 0,
|
||||
"title": "Service Overview",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"content": "Error monitoring helps identify issues in the system. This section displays error logs and success rates for operations.",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"span": 0,
|
||||
"title": "Error Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 0.95
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
}
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 3,
|
||||
"x": 0,
|
||||
"y": 19
|
||||
},
|
||||
"id": 8,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "sum by (action) (app_jobs_processed_total{outcome=\"success\", cluster=\"$cluster\", namespace=\"default\"})\n/\nsum by (action) (app_jobs_processed_total{cluster=\"$cluster\", namespace=\"default\"})\n",
|
||||
"legendFormat": "{{action}}"
|
||||
}
|
||||
],
|
||||
"title": "Job Success Rate",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 10,
|
||||
"x": 3,
|
||||
"y": 19
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt | level=\"error\""
|
||||
}
|
||||
],
|
||||
"title": "Errors",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 11,
|
||||
"x": 13,
|
||||
"y": 19
|
||||
},
|
||||
"id": 10,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt"
|
||||
}
|
||||
],
|
||||
"title": "All",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 28
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"content": "Performance monitoring examines factors that affect system response times, including operation duration, queue lengths, and processing delays. This section provides metrics and traces for performance analysis.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"span": 0,
|
||||
"title": "Performance Analysis",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Number of concurrent processing threads available for handling operations",
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 0,
|
||||
"y": 31
|
||||
},
|
||||
"id": 12,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "max(app_worker_threads_active{cluster=\"$cluster\", namespace=\"default\"})",
|
||||
"instant": true
|
||||
}
|
||||
],
|
||||
"title": "Concurrent Job Drivers",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "tempo",
|
||||
"uid": "${tempo}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 19,
|
||||
"x": 5,
|
||||
"y": 31
|
||||
},
|
||||
"id": 13,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"id": "span-name",
|
||||
"operator": "=",
|
||||
"scope": "span",
|
||||
"tag": "name",
|
||||
"value": [
|
||||
"provisioning.sync.process"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "k8s-cluster-name",
|
||||
"operator": "=",
|
||||
"scope": "resource",
|
||||
"tag": "k8s.cluster.name",
|
||||
"value": [
|
||||
"$cluster"
|
||||
]
|
||||
}
|
||||
],
|
||||
"query": "{name=\"app.operation.process\"}",
|
||||
"queryType": "traceqlSearch"
|
||||
}
|
||||
],
|
||||
"title": "Recent Operation Traces",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
}
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 55
|
||||
},
|
||||
"id": 14,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) > 0",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.9, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) > 0",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) > 0",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) > 0",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg of job durations",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {
|
||||
"mode": "seriesToRows",
|
||||
"reducers": [
|
||||
"mean"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "seriesToRows"
|
||||
},
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"renameByName": {
|
||||
"Field": "Type",
|
||||
"Mean": "Avg Duration",
|
||||
"Metric": "Legend",
|
||||
"Value": "Duration"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 16,
|
||||
"x": 8,
|
||||
"y": 55
|
||||
},
|
||||
"id": 15,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Job Duration",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Total number of jobs waiting to be processed",
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 65
|
||||
},
|
||||
"id": 16,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "clamp_min(sum(app_operation_queue_size{cluster=\"$cluster\", namespace=\"default\"}), 0)",
|
||||
"legendFormat": "Queue size"
|
||||
}
|
||||
],
|
||||
"title": "Queue Size",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "s"
|
||||
}
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 65
|
||||
},
|
||||
"id": 17,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "avg(histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le)))",
|
||||
"legendFormat": "Queue size"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg Queue Wait Time",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "How long a job is in the queue before being picked up",
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 16,
|
||||
"x": 8,
|
||||
"y": 65
|
||||
},
|
||||
"id": 18,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.99",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.95",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.5",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.1",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Queue Wait Time",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 52
|
||||
},
|
||||
"id": 19,
|
||||
"options": {
|
||||
"content": "Resource utilization monitoring for application containers",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"span": 0,
|
||||
"title": "Resource Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 7,
|
||||
"x": 0,
|
||||
"y": 55
|
||||
},
|
||||
"id": 20,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "count by (cluster, channel)(label_replace(label_replace(kube_pod_container_info{namespace=\"default\", container=\"app-worker\", pod=~\"app-worker.*\", cluster=~\"$cluster\"}, \"version\", \"$1\", \"image\", \".+:(.+)\"), \"channel\", \"$1\", \"container\", \".+-(.+)\"))",
|
||||
"legendFormat": "{{cluster}}"
|
||||
}
|
||||
],
|
||||
"title": "Running Pod(s)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 7,
|
||||
"y": 55
|
||||
},
|
||||
"id": 21,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Request"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Limit"
|
||||
},
|
||||
{
|
||||
"expr": "max(container_memory_usage_bytes{namespace=\"default\",cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"}) by (pod)",
|
||||
"legendFormat": "Container usage {{pod}}"
|
||||
}
|
||||
],
|
||||
"title": "Memory Utilization",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 9,
|
||||
"x": 15,
|
||||
"y": 55
|
||||
},
|
||||
"id": 22,
|
||||
"span": 0,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container, cpu)",
|
||||
"legendFormat": "Usage {{pod}}"
|
||||
},
|
||||
{
|
||||
"expr": "sum(irate(container_cpu_cfs_throttled_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container)",
|
||||
"legendFormat": "Throttling {{pod}}"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU limit"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU request"
|
||||
}
|
||||
],
|
||||
"title": "CPU Utilization",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": true,
|
||||
"title": "Application Service",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 15,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"as-code"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"hide": 0,
|
||||
"label": "Data source",
|
||||
"name": "datasource",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"name": "prom",
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "loki-datasource"
|
||||
},
|
||||
"name": "loki",
|
||||
"query": "loki",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "tempo-datasource",
|
||||
"value": "tempo-datasource"
|
||||
},
|
||||
"name": "tempo",
|
||||
"query": "tempo",
|
||||
"refresh": 1,
|
||||
"regex": ".*tempo.*",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "demo-cluster",
|
||||
"value": "demo-cluster"
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"name": "cluster",
|
||||
"query": "label_values(app_worker_threads_active,cluster)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"timezone": "utc",
|
||||
"title": "Span Zero Demo Dashboard",
|
||||
"uid": "span-zero-demo-dashboard",
|
||||
"version": 0
|
||||
}
|
881
apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json
vendored
Normal file
881
apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json
vendored
Normal file
|
@ -0,0 +1,881 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": false,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [
|
||||
{
|
||||
"icon": "external link",
|
||||
"targetBlank": true,
|
||||
"title": "External Documentation",
|
||||
"type": "link",
|
||||
"url": "https://example.com/docs"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"content": "This dashboard demonstrates various monitoring components for application observability and performance metrics.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Application Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 23,
|
||||
"panels": [],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Application Service",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"content": "This service handles background processing tasks for the application system. It manages various types of operations including data synchronization, resource management, and batch processing.\n\nSupported operation types:\n1. Sync: Synchronizes data between different systems\n2. Process: Handles batch data processing tasks\n3. Cleanup: Removes outdated or temporary resources\n4. Update: Applies configuration changes across services\n\nService dependencies:\n- Data API: For reading and writing application data\n- Configuration Service: For managing system settings\n- Queue Service: For handling task scheduling\n- Storage Service: For persistent data management\n- Auth Service: For authentication and authorization\n- Metrics Service: For collecting operational statistics\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Service Overview",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 1
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"content": "Error monitoring helps identify issues in the system. This section displays error logs and success rates for operations.",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Error Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 0.95
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "sum by (action) (app_jobs_processed_total{outcome=\"success\", cluster=\"$cluster\", namespace=\"default\"})\n/\nsum by (action) (app_jobs_processed_total{cluster=\"$cluster\", namespace=\"default\"})\n",
|
||||
"legendFormat": "{{action}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Job Success Rate",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt | level=\"error\"",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
"id": 10,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "All",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 8
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"content": "Performance monitoring examines factors that affect system response times, including operation duration, queue lengths, and processing delays. This section provides metrics and traces for performance analysis.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Performance Analysis",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Number of concurrent processing threads available for handling operations",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 15
|
||||
},
|
||||
"id": 12,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(app_worker_threads_active{cluster=\"$cluster\", namespace=\"default\"})",
|
||||
"instant": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Concurrent Job Drivers",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "tempo",
|
||||
"uid": "${tempo}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 15
|
||||
},
|
||||
"id": 13,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "tempo",
|
||||
"uid": "${tempo}"
|
||||
},
|
||||
"filters": [
|
||||
{
|
||||
"id": "span-name",
|
||||
"operator": "=",
|
||||
"scope": "span",
|
||||
"tag": "name",
|
||||
"value": [
|
||||
"provisioning.sync.process"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "k8s-cluster-name",
|
||||
"operator": "=",
|
||||
"scope": "resource",
|
||||
"tag": "k8s.cluster.name",
|
||||
"value": [
|
||||
"$cluster"
|
||||
]
|
||||
}
|
||||
],
|
||||
"query": "{name=\"app.operation.process\"}",
|
||||
"queryType": "traceqlSearch",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Recent Operation Traces",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 15
|
||||
},
|
||||
"id": 14,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.9, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg of job durations",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {
|
||||
"mode": "seriesToRows",
|
||||
"reducers": [
|
||||
"mean"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "seriesToRows"
|
||||
},
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"renameByName": {
|
||||
"Field": "Type",
|
||||
"Mean": "Avg Duration",
|
||||
"Metric": "Legend",
|
||||
"Value": "Duration"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 22
|
||||
},
|
||||
"id": 15,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Job Duration",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Total number of jobs waiting to be processed",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 22
|
||||
},
|
||||
"id": 16,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "clamp_min(sum(app_operation_queue_size{cluster=\"$cluster\", namespace=\"default\"}), 0)",
|
||||
"legendFormat": "Queue size",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Queue Size",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 22
|
||||
},
|
||||
"id": 17,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "avg(histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le)))",
|
||||
"legendFormat": "Queue size",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg Queue Wait Time",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "How long a job is in the queue before being picked up",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 29
|
||||
},
|
||||
"id": 18,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.99",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.95",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.5",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.1",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Queue Wait Time",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 29
|
||||
},
|
||||
"id": 19,
|
||||
"options": {
|
||||
"content": "Resource utilization monitoring for application containers",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"apiVersion": "v1",
|
||||
"type": "prometheus",
|
||||
"uid": "default-ds-uid"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Resource Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 29
|
||||
},
|
||||
"id": 20,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "count by (cluster, channel)(label_replace(label_replace(kube_pod_container_info{namespace=\"default\", container=\"app-worker\", pod=~\"app-worker.*\", cluster=~\"$cluster\"}, \"version\", \"$1\", \"image\", \".+:(.+)\"), \"channel\", \"$1\", \"container\", \".+-(.+)\"))",
|
||||
"legendFormat": "{{cluster}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Running Pod(s)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 36
|
||||
},
|
||||
"id": 21,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Request",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Limit",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(container_memory_usage_bytes{namespace=\"default\",cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"}) by (pod)",
|
||||
"legendFormat": "Container usage {{pod}}",
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"title": "Memory Utilization",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 36
|
||||
},
|
||||
"id": 22,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container, cpu)",
|
||||
"legendFormat": "Usage {{pod}}",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "sum(irate(container_cpu_cfs_throttled_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container)",
|
||||
"legendFormat": "Throttling {{pod}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU limit",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU request",
|
||||
"refId": "D"
|
||||
}
|
||||
],
|
||||
"title": "CPU Utilization",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "10s",
|
||||
"schemaVersion": 42,
|
||||
"tags": [
|
||||
"as-code"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"hide": 0,
|
||||
"label": "Data source",
|
||||
"name": "datasource",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"name": "prom",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "loki-datasource"
|
||||
},
|
||||
"name": "loki",
|
||||
"options": [],
|
||||
"query": "loki",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "tempo-datasource",
|
||||
"value": "tempo-datasource"
|
||||
},
|
||||
"name": "tempo",
|
||||
"options": [],
|
||||
"query": "tempo",
|
||||
"refresh": 1,
|
||||
"regex": ".*tempo.*",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "demo-cluster",
|
||||
"value": "demo-cluster"
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"name": "cluster",
|
||||
"options": [],
|
||||
"query": "label_values(app_worker_threads_active,cluster)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "utc",
|
||||
"title": "Span Zero Demo Dashboard",
|
||||
"uid": "span-zero-demo-dashboard",
|
||||
"weekStart": ""
|
||||
}
|
694
apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json
vendored
Normal file
694
apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json
vendored
Normal file
|
@ -0,0 +1,694 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": false,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [
|
||||
{
|
||||
"icon": "external link",
|
||||
"targetBlank": true,
|
||||
"title": "External Documentation",
|
||||
"type": "link",
|
||||
"url": "https://example.com/docs"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"content": "This dashboard demonstrates various monitoring components for application observability and performance metrics.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Application Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 23,
|
||||
"panels": [],
|
||||
"title": "Application Service",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"content": "This service handles background processing tasks for the application system. It manages various types of operations including data synchronization, resource management, and batch processing.\n\nSupported operation types:\n1. Sync: Synchronizes data between different systems\n2. Process: Handles batch data processing tasks\n3. Cleanup: Removes outdated or temporary resources\n4. Update: Applies configuration changes across services\n\nService dependencies:\n- Data API: For reading and writing application data\n- Configuration Service: For managing system settings\n- Queue Service: For handling task scheduling\n- Storage Service: For persistent data management\n- Auth Service: For authentication and authorization\n- Metrics Service: For collecting operational statistics\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Service Overview",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 1
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"content": "Error monitoring helps identify issues in the system. This section displays error logs and success rates for operations.",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Error Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "red",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 0.95
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "sum by (action) (app_jobs_processed_total{outcome=\"success\", cluster=\"$cluster\", namespace=\"default\"})\n/\nsum by (action) (app_jobs_processed_total{cluster=\"$cluster\", namespace=\"default\"})\n",
|
||||
"legendFormat": "{{action}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Job Success Rate",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt | level=\"error\"",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Errors",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "${loki}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
"id": 10,
|
||||
"options": {
|
||||
"enableLogDetails": true,
|
||||
"showTime": false,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"expr": "{namespace=\"default\", cluster=\"$cluster\", job=\"app-service\"} | logfmt",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "All",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 8
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"content": "Performance monitoring examines factors that affect system response times, including operation duration, queue lengths, and processing delays. This section provides metrics and traces for performance analysis.\n",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Performance Analysis",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Number of concurrent processing threads available for handling operations",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 15
|
||||
},
|
||||
"id": 12,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "max(app_worker_threads_active{cluster=\"$cluster\", namespace=\"default\"})",
|
||||
"instant": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Concurrent Job Drivers",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "tempo",
|
||||
"uid": "${tempo}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 15
|
||||
},
|
||||
"id": 13,
|
||||
"targets": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"id": "span-name",
|
||||
"operator": "=",
|
||||
"scope": "span",
|
||||
"tag": "name",
|
||||
"value": [
|
||||
"provisioning.sync.process"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "k8s-cluster-name",
|
||||
"operator": "=",
|
||||
"scope": "resource",
|
||||
"tag": "k8s.cluster.name",
|
||||
"value": [
|
||||
"$cluster"
|
||||
]
|
||||
}
|
||||
],
|
||||
"query": "{name=\"app.operation.process\"}",
|
||||
"queryType": "traceqlSearch",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Recent Operation Traces",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 15
|
||||
},
|
||||
"id": 14,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.9, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le, resources_changed_bucket, action)) and on(resources_changed_bucket, action) sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (resources_changed_bucket, action) \u003e 0",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg of job durations",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "reduce",
|
||||
"options": {
|
||||
"mode": "seriesToRows",
|
||||
"reducers": [
|
||||
"mean"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "seriesToRows"
|
||||
},
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"renameByName": {
|
||||
"Field": "Type",
|
||||
"Mean": "Avg Duration",
|
||||
"Metric": "Legend",
|
||||
"Value": "Duration"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 22
|
||||
},
|
||||
"id": 15,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.99 - size {{resources_changed_bucket}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.95 - size {{resources_changed_bucket}}",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.5 - size {{resources_changed_bucket}}",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_duration_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[5m])) by (le, resources_changed_bucket, action))",
|
||||
"legendFormat": "{{action}} q0.1 - size {{resources_changed_bucket}}",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Job Duration",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "Total number of jobs waiting to be processed",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 22
|
||||
},
|
||||
"id": 16,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "clamp_min(sum(app_operation_queue_size{cluster=\"$cluster\", namespace=\"default\"}), 0)",
|
||||
"legendFormat": "Queue size",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Queue Size",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 22
|
||||
},
|
||||
"id": 17,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "avg(histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[7d])) by (le)))",
|
||||
"legendFormat": "Queue size",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": "7d",
|
||||
"title": "7d avg Queue Wait Time",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"description": "How long a job is in the queue before being picked up",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 29
|
||||
},
|
||||
"id": 18,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.99, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.99",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.95, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.95",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.5, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.5",
|
||||
"refId": "D"
|
||||
},
|
||||
{
|
||||
"expr": "histogram_quantile(0.1, sum(rate(app_operation_queue_wait_seconds_bucket{cluster=\"$cluster\", namespace=\"default\"}[$__rate_interval])) by (le))",
|
||||
"legendFormat": "q0.1",
|
||||
"refId": "E"
|
||||
}
|
||||
],
|
||||
"title": "Queue Wait Time",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 29
|
||||
},
|
||||
"id": 19,
|
||||
"options": {
|
||||
"content": "Resource utilization monitoring for application containers",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"title": "Resource Monitoring",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 29
|
||||
},
|
||||
"id": 20,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "count by (cluster, channel)(label_replace(label_replace(kube_pod_container_info{namespace=\"default\", container=\"app-worker\", pod=~\"app-worker.*\", cluster=~\"$cluster\"}, \"version\", \"$1\", \"image\", \".+:(.+)\"), \"channel\", \"$1\", \"container\", \".+-(.+)\"))",
|
||||
"legendFormat": "{{cluster}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Running Pod(s)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 36
|
||||
},
|
||||
"id": 21,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Request",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", resource=\"memory\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"})",
|
||||
"legendFormat": "Memory Limit",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "max(container_memory_usage_bytes{namespace=\"default\",cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker.*\"}) by (pod)",
|
||||
"legendFormat": "Container usage {{pod}}",
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"title": "Memory Utilization",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 36
|
||||
},
|
||||
"id": 22,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container, cpu)",
|
||||
"legendFormat": "Usage {{pod}}",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"expr": "sum(irate(container_cpu_cfs_throttled_seconds_total{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\"}[$__rate_interval])) by (pod, container)",
|
||||
"legendFormat": "Throttling {{pod}}",
|
||||
"refId": "B"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_limits{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU limit",
|
||||
"refId": "C"
|
||||
},
|
||||
{
|
||||
"expr": "max(kube_pod_container_resource_requests{namespace=\"default\", cluster=~\"$cluster\", container=\"app-worker\", pod=~\"app-worker-.*\", resource=\"cpu\"})",
|
||||
"legendFormat": "CPU request",
|
||||
"refId": "D"
|
||||
}
|
||||
],
|
||||
"title": "CPU Utilization",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"refresh": "10s",
|
||||
"schemaVersion": 16,
|
||||
"tags": [
|
||||
"as-code"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"hide": 0,
|
||||
"label": "Data source",
|
||||
"name": "datasource",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "prometheus-datasource"
|
||||
},
|
||||
"name": "prom",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"value": "loki-datasource"
|
||||
},
|
||||
"name": "loki",
|
||||
"options": [],
|
||||
"query": "loki",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "tempo-datasource",
|
||||
"value": "tempo-datasource"
|
||||
},
|
||||
"name": "tempo",
|
||||
"options": [],
|
||||
"query": "tempo",
|
||||
"refresh": 1,
|
||||
"regex": ".*tempo.*",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "demo-cluster",
|
||||
"value": "demo-cluster"
|
||||
},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${prom}"
|
||||
},
|
||||
"name": "cluster",
|
||||
"options": [],
|
||||
"query": "label_values(app_worker_threads_active,cluster)",
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"timezone": "utc",
|
||||
"title": "Span Zero Demo Dashboard",
|
||||
"uid": "span-zero-demo-dashboard",
|
||||
"weekStart": ""
|
||||
}
|
|
@ -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,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=
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
var appManifestData = app.ManifestData{
|
||||
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")
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
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{},
|
||||
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"},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,27 +2103,28 @@ func schema_pkg_apis_iam_v0alpha1_TeamBindingSpec(ref common.ReferenceCallback)
|
|||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"subjects": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
"subject": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamBindingspecSubject"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"teamRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
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"},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
var appManifestData = app.ManifestData{
|
||||
AppName: "iam",
|
||||
Group: "iam.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
|
|
@ -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,6 +90,7 @@ func New(cfg app.Config) (app.App, error) {
|
|||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerSupplier: generateInformerSupplier(appSpecificConfig.InformerConfig, metrics),
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
logging.FromContext(ctx).With("error", err).Error("Informer processing error")
|
||||
if metrics != nil {
|
||||
|
@ -101,6 +99,7 @@ func New(cfg app.Config) (app.App, error) {
|
|||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
UnmanagedKinds: []simple.AppUnmanagedKind{
|
||||
{
|
||||
Kind: foldersKind.FolderKind(),
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
@ -29,6 +30,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
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,10 +19,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "investigation",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(_ context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: investigationsv0alpha1.InvestigationKind(),
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -27,6 +27,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
AppName: "playlist",
|
||||
Group: "playlist.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
|
|
@ -50,10 +50,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "playlist",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
klog.ErrorS(err, "Informer processing error")
|
||||
},
|
||||
},
|
||||
},
|
||||
ManagedKinds: []simple.AppManagedKind{
|
||||
{
|
||||
Kind: playlistv0alpha1.PlaylistKind(),
|
||||
|
|
|
@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/plugins
|
|||
go 1.24.4
|
||||
|
||||
require (
|
||||
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/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/apiserver v0.34.1
|
||||
|
@ -19,7 +19,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
|
||||
|
@ -35,7 +35,7 @@ require (
|
|||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/uuid v1.6.0 // 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/grafana-app-sdk/logging v0.45.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
|
@ -86,7 +86,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
|
||||
|
|
|
@ -12,8 +12,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=
|
||||
|
@ -50,14 +50,14 @@ 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/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/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde h1:ydSrBIOCxJQ84+JU+cyYsOLL40QeXrB7rYfsY/ezU4w=
|
||||
|
@ -219,8 +219,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=
|
||||
|
|
|
@ -30,6 +30,7 @@ var (
|
|||
var appManifestData = app.ManifestData{
|
||||
AppName: "plugins",
|
||||
Group: "plugins.grafana.app",
|
||||
PreferredVersion: "v0alpha1",
|
||||
Versions: []app.ManifestVersion{
|
||||
{
|
||||
Name: "v0alpha1",
|
||||
|
|
|
@ -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"
|
||||
|
@ -26,10 +27,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||
Name: "plugins",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
InformerConfig: simple.AppInformerConfig{
|
||||
InformerOptions: operator.InformerOptions{
|
||||
ErrorHandler: func(ctx context.Context, err error) {
|
||||
klog.ErrorS(err, "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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue