Simplify local development config for iam-app-operator (#110164)

This commit is contained in:
Mihai Turdean
2025-08-28 11:38:47 -06:00
committed by GitHub
parent 43648d20c3
commit d0412d9a0d
11 changed files with 79 additions and 186 deletions
+2
View File
@@ -0,0 +1,2 @@
# Local development overrides
local/yamls/iam-secrets.yaml
+2 -28
View File
@@ -1,7 +1,5 @@
include ../sdk.mk
OPERATOR_DOCKERIMAGE := "github.com/grafana/grafana/apps/iam/operator"
.PHONY: generate
generate: install-app-sdk update-app-sdk ## Run Grafana App SDK code generation
@$(APP_SDK_BIN) generate \
@@ -17,17 +15,9 @@ deps:
@go mod tidy
@GOWORK=off go mod vendor
.PHONY: build
build: build/operator
.PHONY: build/operator
build/operator:
docker build -t $(OPERATOR_DOCKERIMAGE) -f cmd/operator/Dockerfile .
.PHONY: local/up
local/up:
@./local/scripts/cluster.sh create "local/k3d-config.json"
@cd local && tilt up
@tilt up
.PHONY: local/generate
local/generate:
@@ -35,20 +25,4 @@ local/generate:
.PHONY: local/down
local/down:
@cd local && tilt down
.PHONY: local/deploy_plugin
local/deploy_plugin:
-tilt disable grafana
cp -R plugin/dist local/mounted-files/plugin/dist
-tilt enable grafana
.PHONY: local/push_operator
local/push_operator: build/operator
# Tag the docker image as part of localhost, which is what the generated k8s uses to avoid confusion with the real operator image
@docker tag "$(OPERATOR_DOCKERIMAGE):latest" "localhost/$(OPERATOR_DOCKERIMAGE):latest"
@./local/scripts/push_image.sh "localhost/$(OPERATOR_DOCKERIMAGE):latest"
.PHONY: local/clean
local/clean: local/down
@./local/scripts/cluster.sh delete
@tilt down
+16
View File
@@ -0,0 +1,16 @@
# version_settings() enforces a minimum Tilt version
# https://docs.tilt.dev/api.html#api.version_settings
version_settings(constraint='>=0.22.2')
custom_build(
'grafana-iam-operator',
command='docker build -t $EXPECTED_REF -f cmd/operator/Dockerfile .',
deps=[
'cmd/operator',
'pkg',
],
disable_push=True,
)
k8s_yaml([filename for filename in listdir('local/yamls') if filename.lower().endswith(('.yaml', '.yml'))])
+3 -3
View File
@@ -89,11 +89,11 @@ func LoadConfigFromEnv() (*Config, error) {
}
cfg.KubeConfig = kubeConfig
} else if folderAppURL := os.Getenv("FOLDER_APP_URL"); folderAppURL != "" {
exchangeUrl := os.Getenv("AUTH_TOKEN_EXCHANGE_URL")
exchangeUrl := os.Getenv("TOKEN_EXCHANGE_URL")
authToken := os.Getenv("AUTH_TOKEN")
namespace := os.Getenv("FOLDER_APP_NAMESPACE")
if exchangeUrl == "" || authToken == "" {
return nil, fmt.Errorf("AUTH_TOKEN_EXCHANGE_URL and AUTH_TOKEN must be set when FOLDER_APP_URL is set")
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)
@@ -111,7 +111,7 @@ func LoadConfigFromEnv() (*Config, error) {
cfg.ZanzanaClient.Address = os.Getenv("ZANZANA_ADDR")
cfg.ZanzanaClient.Token = os.Getenv("ZANZANA_TOKEN")
cfg.ZanzanaClient.TokenExchangeURL = os.Getenv("ZANZANA_TOKEN_EXCHANGE_URL")
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")
-57
View File
@@ -1,57 +0,0 @@
# version_settings() enforces a minimum Tilt version
# https://docs.tilt.dev/api.html#api.version_settings
version_settings(constraint='>=0.22.2')
def name(c):
return c['metadata']['name']
def namespace(c):
if 'namespace' in c['metadata']:
return c['metadata']['namespace']
return ''
def decode(yaml):
resources = decode_yaml_stream(yaml)
# workaround a bug in decode_yaml_stream where it returns duplicates
# This bug has been fixed in Tilt v0.17.3+
filtered = []
names = {}
for r in resources:
if r == None:
continue
n = '%s:%s:%s' % (name(r), r['kind'], namespace(r))
if n in names:
continue
names[n] = True
filtered.append(r)
return filtered
def find_overlapping(o, yamls):
for elem in yamls:
if name(o) == name(elem) and o['kind'] == elem['kind'] and namespace(o) == namespace(elem):
return elem
return None
yaml_objects = []
# Parse all YAML files in our "yamls" directory
for filename in listdir('yamls'):
if filename.lower().endswith(('.yaml', '.yml')):
decoded = decode(read_file(filename))
for o in decoded:
present = find_overlapping(o, yaml_objects)
if present != None:
print("Overlapping resource found: %s", filename)
exit(1)
yaml_objects += decoded
bundle = encode_yaml_stream(yaml_objects)
# k8s_yaml automatically creates resources in Tilt for the entities
# and will inject any images referenced in the Tiltfile when deploying
# https://docs.tilt.dev/api.html#api.k8s_yaml
k8s_yaml(bundle)
-16
View File
@@ -1,16 +0,0 @@
{
"apiVersion": "k3d.io/v1alpha3",
"kind": "Simple",
"kubeAPI": {
"hostPort": "8556"
},
"options": {
"k3d": {
"wait": true
},
"kubeconfig": {
"switchCurrentContext": true,
"updateDefaultKubeconfig": true
}
}
}
-43
View File
@@ -1,43 +0,0 @@
#!/usr/bin/env bash
set -eufo pipefail
CLUSTER_NAME="grafana-iam-operator"
create_cluster() {
K3D_CONFIG="${1:-k3d-config.json}"
if ! k3d cluster list "${CLUSTER_NAME}" >/dev/null 2>&1; then
# Array of extra options to add to the k3d cluster create command
EXTRA_K3D_OPTS=()
# Bug in k3d for btrfs filesystems workaround, see https://k3d.io/v5.2.2/faq/faq/#issues-with-btrfs
# Apple is APFS/HFS and stat has a different API, so we might as well skip that
if [[ "${OSTYPE}" != "darwin*" ]]; then
ROOTFS="$(stat -f --format="%T" "/")"
if [[ "${ROOTFS}" == "btrfs" ]]; then
EXTRA_K3D_OPTS+=("-v" "/dev/mapper:/dev/mapper")
fi
fi
k3d cluster create "${CLUSTER_NAME}" --config "${K3D_CONFIG}" ${EXTRA_K3D_OPTS[@]+"${EXTRA_K3D_OPTS[@]}"}
else
echo "Cluster already exists"
fi
}
delete_cluster() {
k3d cluster delete "${CLUSTER_NAME}"
}
if [ $# -lt 1 ]; then
echo "Usage: ./cluster.sh [create|delete]"
exit 1
fi
if [ $1 == "create" ]; then
create_cluster $2
elif [ $1 == "delete" ]; then
delete_cluster
else
echo "Unknown argument ${1}"
fi
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -eufo pipefail
CLUSTER_NAME="grafana-iam-operator"
IMAGE="$1"
if [[ "$IMAGE" == "" ]]; then
echo "usage: push_image.sh <image_name:tag>"
exit 1
fi
k3d image import "${IMAGE}" -c "${CLUSTER_NAME}"
+19 -6
View File
@@ -23,7 +23,7 @@ spec:
spec:
serviceAccount: operator
containers:
- image: localhost/github.com/grafana/grafana/apps/iam/operator:latest
- image: grafana-iam-operator
imagePullPolicy: IfNotPresent
name: iam-app-operator
command: ["/bin/sh"]
@@ -31,15 +31,28 @@ spec:
- -c
- exec /usr/bin/operator
env:
- name: KUBE_FEATURE_WatchListClient
value: "false"
- name: ZANZANA_ADDR
value: zanzana.default.svc.cluster.local:50051
- name: FOLDER_APP_URL
value: https://host.docker.internal:6446
- name: AUTH_TOKEN_EXCHANGE_URL
- name: FOLDER_APP_NAMESPACE
value: grafana-folder
- name: TOKEN_EXCHANGE_URL
value: http://host.docker.internal:8080/v1/sign-access-token
- name: AUTH_TOKEN
value: ""
- name: FOLDER_APP_NAMESPACE
value: "grafana-folder"
valueFrom:
secretKeyRef:
name: iam-app-operator-secrets
key: auth-token
- name: ZANZANA_TOKEN
valueFrom:
secretKeyRef:
name: iam-app-operator-secrets
key: zanzana-token
- name: FOLDER_RECONCILER_NAMESPACE
value: "default"
valueFrom:
secretKeyRef:
name: iam-app-operator-secrets
key: folder-reconciler-namespace
+28 -16
View File
@@ -88,12 +88,8 @@ metadata:
name: zanzana
data:
grafana.ini: |
app_mode = development
target = zanzana-server
[log]
level = info
[database]
type = postgres
host = postgres.default.svc:5432
@@ -103,17 +99,27 @@ data:
[feature_toggles]
zanzana = true
authZGRPCServer = true
[zanzana.server]
allow_insecure = true
check_query_cache = true
http_addr = 0.0.0.0:8080
[grpc_server]
enabled = true
address = 0.0.0.0:50051
enable_logging = true
use_tls = false
[log]
level = debug
[server]
http_port = 8080
[zanzana.server]
check_query_cache = true
check_query_cache_enabled = true
check_query_cache_ttl = 10s
list_objects_deadline = 3s
list_objects_max_results = 1000
signing_keys_url = http://host.docker.internal:8080/v1/keys
use_streamed_list_objects = false
---
apiVersion: v1
kind: Service
@@ -124,10 +130,10 @@ metadata:
name: zanzana
spec:
ports:
- name: http
- name: zanzana-http-metrics
port: 8080
targetPort: 8080
- name: grpc
- name: zanzana-grpc
port: 50051
targetPort: 50051
selector:
@@ -162,17 +168,23 @@ spec:
image: grafana/grafana-dev:12.2.0-257970
imagePullPolicy: IfNotPresent
name: zanzana
ports:
- containerPort: 50051
name: grpc
- containerPort: 8080
name: http-metrics
readinessProbe:
grpc:
port: 50051
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- mountPath: /etc/grafana-config
name: zanzana-config
- mountPath: /var/lib/grafana
name: zanzana-storage
serviceAccount: zanzana
volumes:
- configMap:
name: zanzana-config
name: zanzana-config
- emptyDir: {}
name: zanzana-storage
---
+9 -5
View File
@@ -43,6 +43,12 @@ func New(cfg app.Config) (app.App, error) {
logging.DefaultLogger.Info("FolderReconciler created")
reconcilerOptions := simple.BasicReconcileOptions{}
if cfg.SpecificConfig.(AppConfig).FolderReconcilerNamespace != "" {
reconcilerOptions.Namespace = cfg.SpecificConfig.(AppConfig).FolderReconcilerNamespace
}
config := simple.AppConfig{
Name: cfg.ManifestData.AppName,
KubeConfig: cfg.KubeConfig,
@@ -54,11 +60,9 @@ func New(cfg app.Config) (app.App, error) {
},
UnmanagedKinds: []simple.AppUnmanagedKind{
{
Kind: foldersKind.FolderKind(),
Reconciler: folderReconciler,
ReconcileOptions: simple.BasicReconcileOptions{
Namespace: cfg.SpecificConfig.(AppConfig).FolderReconcilerNamespace,
},
Kind: foldersKind.FolderKind(),
Reconciler: folderReconciler,
ReconcileOptions: reconcilerOptions,
},
},
}