Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
87a06dac66 | |||
366ceece24 | |||
8b2425d16d | |||
101bf971a7 | |||
c4a43b82d3 | |||
1f285f6492 | |||
2d71a4a132 | |||
264b30e8a2 | |||
7f56a3db56 | |||
9d02a2d90b | |||
3c13eb0d6b |
76 changed files with 4166 additions and 3470 deletions
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
|
@ -28,4 +28,4 @@ jobs:
|
|||
- name: Run linter
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: v1.61
|
||||
version: v1.63.4
|
||||
|
|
80
.github/workflows/postgres.yml
vendored
Normal file
80
.github/workflows/postgres.yml
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
name: Postgres image
|
||||
on:
|
||||
schedule:
|
||||
# every Thursday 2:30am
|
||||
- cron: "30 2 * * 2"
|
||||
push:
|
||||
paths:
|
||||
- .github/workflows/postgres.yml
|
||||
- postgres/**
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
MINOR_VERSIONS: '{"15": "12","17": "4"}'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- arm64
|
||||
- amd64
|
||||
postgres_major:
|
||||
- "15"
|
||||
- "17"
|
||||
runs-on: ubuntu-latest-${{ matrix.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Login to container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.icb4dc0.de
|
||||
username: ${{ secrets.HARBOR_USER }}
|
||||
password: ${{ secrets.HARBOR_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: postgres/Dockerfile
|
||||
push: true
|
||||
tags: registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-${{ matrix.arch }}
|
||||
build-args: |
|
||||
POSTGRES_MAJOR=${{ matrix.postgres_major }}
|
||||
POSTGRES_MINOR=${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}
|
||||
|
||||
manifest:
|
||||
strategy:
|
||||
matrix:
|
||||
postgres_major:
|
||||
- "15"
|
||||
- "17"
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- name: Login to container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.icb4dc0.de
|
||||
username: ${{ secrets.HARBOR_USER }}
|
||||
password: ${{ secrets.HARBOR_TOKEN }}
|
||||
|
||||
- name: Install skopeo
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y skopeo
|
||||
|
||||
- name: Create manifest
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }} \
|
||||
-t registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }} \
|
||||
registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-arm64 \
|
||||
registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-amd64
|
||||
|
||||
skopeo delete docker://registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-arm64
|
||||
skopeo delete docker://registry.icb4dc0.de/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-amd64
|
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
|
@ -36,7 +36,6 @@ jobs:
|
|||
- name: Init go
|
||||
run: |
|
||||
go mod download
|
||||
go mod download -modfile tools/go.mod
|
||||
|
||||
- name: Snapshot release
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
|
|
5
.github/workflows/test-e2e.yml
vendored
5
.github/workflows/test-e2e.yml
vendored
|
@ -43,3 +43,8 @@ jobs:
|
|||
run: |
|
||||
go mod tidy
|
||||
make test-e2e
|
||||
|
||||
- name: Cleanup kind cluster
|
||||
if: always()
|
||||
run: |
|
||||
kind delete cluster
|
||||
|
|
110
.golangci.yml
110
.golangci.yml
|
@ -1,36 +1,18 @@
|
|||
version: "2"
|
||||
run:
|
||||
timeout: 5m
|
||||
allow-parallel-runners: true
|
||||
|
||||
issues:
|
||||
# don't skip warning about doc comments
|
||||
# don't exclude the default set of lint
|
||||
exclude-use-default: false
|
||||
# restore some of the defaults
|
||||
# (fill in the rest as needed)
|
||||
exclude-rules:
|
||||
- path: "api/*"
|
||||
linters:
|
||||
- lll
|
||||
- path: "internal/*"
|
||||
linters:
|
||||
- dupl
|
||||
- lll
|
||||
linters:
|
||||
disable-all: true
|
||||
default: none
|
||||
enable:
|
||||
- copyloopvar
|
||||
- dupl
|
||||
- errcheck
|
||||
- copyloopvar
|
||||
- ginkgolinter
|
||||
- goconst
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- goheader
|
||||
- gosimple
|
||||
# enable when the TODOs are fixed
|
||||
# - godox
|
||||
- goheader
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
|
@ -39,43 +21,65 @@ linters:
|
|||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
|
||||
linters-settings:
|
||||
revive:
|
||||
settings:
|
||||
goheader:
|
||||
values:
|
||||
const:
|
||||
AUTHOR: Peter Kurfer
|
||||
template-path: hack/header.tmpl
|
||||
importas:
|
||||
alias:
|
||||
- pkg: k8s.io/api/(\w+)/(v[\w\d]+)
|
||||
alias: $1$2
|
||||
- pkg: k8s.io/apimachinery/pkg/apis/meta/v1
|
||||
alias: metav1
|
||||
no-unaliased: true
|
||||
no-extra-aliases: true
|
||||
revive:
|
||||
rules:
|
||||
- name: comment-spacings
|
||||
exclusions:
|
||||
generated: lax
|
||||
rules:
|
||||
- name: comment-spacings
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(code.icb4dc0.de/prskr/supabase-operator)
|
||||
- alias
|
||||
- blank
|
||||
- dot
|
||||
goimports:
|
||||
local-prefixes: code.icb4dc0.de/prskr/supabase-operator
|
||||
goheader:
|
||||
values:
|
||||
const:
|
||||
AUTHOR: Peter Kurfer
|
||||
template-path: hack/header.tmpl
|
||||
|
||||
importas:
|
||||
no-unaliased: true
|
||||
no-extra-aliases: true
|
||||
alias:
|
||||
- pkg: k8s.io/api/(\w+)/(v[\w\d]+)
|
||||
alias: $1$2
|
||||
- pkg: "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
alias: metav1
|
||||
|
||||
- linters:
|
||||
- lll
|
||||
path: api/*
|
||||
- linters:
|
||||
- dupl
|
||||
- lll
|
||||
path: internal/*
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
severity:
|
||||
default-severity: error
|
||||
default: error
|
||||
rules:
|
||||
- linters:
|
||||
- godox
|
||||
severity: info
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(code.icb4dc0.de/prskr/supabase-operator)
|
||||
- alias
|
||||
- blank
|
||||
- dot
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- code.icb4dc0.de/prskr/supabase-operator
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# git hook pre commit
|
||||
pre-commit = [
|
||||
"go mod tidy -go=1.23.5",
|
||||
"go mod tidy -go=1.24",
|
||||
"go run mage.go GenerateAll",
|
||||
"husky lint-staged",
|
||||
# "golangci-lint run",
|
||||
|
|
|
@ -4,6 +4,19 @@
|
|||
"initialization_options": {
|
||||
"local": "code.icb4dc0.de/prskr/supabase-operator"
|
||||
}
|
||||
},
|
||||
"golangci-lint": {
|
||||
"initialization_options": {
|
||||
"command": [
|
||||
"go",
|
||||
"tool",
|
||||
"golangci-lint",
|
||||
"run",
|
||||
"--output.json.path",
|
||||
"stderr",
|
||||
"--issues-exit-code=1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Build the manager binary
|
||||
FROM golang:1.23.4 AS builder
|
||||
FROM golang:1.24-alpine AS builder
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
|
@ -16,10 +16,7 @@ COPY [ "go.*", "./" ]
|
|||
COPY [ "api", "api" ]
|
||||
COPY [ "assets/migrations", "assets/migrations" ]
|
||||
COPY [ "cmd", "cmd" ]
|
||||
COPY [ "infrastructure", "infrastructure" ]
|
||||
COPY [ "internal", "internal" ]
|
||||
COPY [ "magefiles", "magefiles" ]
|
||||
COPY [ "tools", "tools" ]
|
||||
|
||||
# Build
|
||||
# the GOARCH has not a default value to allow the binary be built according to the host where the command
|
||||
|
|
64
Makefile
64
Makefile
|
@ -44,11 +44,11 @@ help: ## Display this help.
|
|||
##@ Development
|
||||
|
||||
.PHONY: manifests
|
||||
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||
manifests: ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||
|
||||
.PHONY: generate
|
||||
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||
generate: ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||
|
||||
.PHONY: fmt
|
||||
|
@ -60,7 +60,7 @@ vet: ## Run go vet against code.
|
|||
go vet ./...
|
||||
|
||||
.PHONY: test
|
||||
test: manifests generate fmt vet envtest ## Run tests.
|
||||
test: manifests generate fmt vet ## Run tests.
|
||||
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
|
||||
|
||||
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
|
||||
|
@ -81,11 +81,11 @@ test-e2e: manifests generate fmt vet ## Run the e2e tests. Expected an isolated
|
|||
go test ./test/e2e/ -v -ginkgo.v
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint ## Run golangci-lint linter
|
||||
lint: ## Run golangci-lint linter
|
||||
$(GOLANGCI_LINT) run
|
||||
|
||||
.PHONY: lint-fix
|
||||
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
|
||||
lint-fix: ## Run golangci-lint linter and perform fixes
|
||||
$(GOLANGCI_LINT) run --fix
|
||||
|
||||
##@ Build
|
||||
|
@ -127,7 +127,7 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
|
|||
rm Dockerfile.cross
|
||||
|
||||
.PHONY: build-installer
|
||||
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
|
||||
build-installer: manifests generate ## Generate a consolidated YAML with CRDs and deployment.
|
||||
mkdir -p dist
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||
$(KUSTOMIZE) build config/default > dist/install.yaml
|
||||
|
@ -148,7 +148,7 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
|
|||
|
||||
.PHONY: deploy
|
||||
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||
cd config/manager && $(KUSTOMIZE) edit set image supabase-operator=${IMG}
|
||||
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
|
||||
|
||||
.PHONY: undeploy
|
||||
|
@ -164,49 +164,7 @@ $(LOCALBIN):
|
|||
|
||||
## Tool Binaries
|
||||
KUBECTL ?= kubectl
|
||||
KUSTOMIZE ?= $(LOCALBIN)/kustomize
|
||||
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
|
||||
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
|
||||
|
||||
## Tool Versions
|
||||
KUSTOMIZE_VERSION ?= v5.5.0
|
||||
CONTROLLER_TOOLS_VERSION ?= v0.16.4
|
||||
ENVTEST_VERSION ?= release-0.19
|
||||
GOLANGCI_LINT_VERSION ?= v1.61.0
|
||||
|
||||
.PHONY: kustomize
|
||||
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
|
||||
$(KUSTOMIZE): $(LOCALBIN)
|
||||
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
|
||||
|
||||
.PHONY: controller-gen
|
||||
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
|
||||
$(CONTROLLER_GEN): $(LOCALBIN)
|
||||
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
|
||||
|
||||
.PHONY: envtest
|
||||
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
|
||||
$(ENVTEST): $(LOCALBIN)
|
||||
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
||||
$(GOLANGCI_LINT): $(LOCALBIN)
|
||||
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
|
||||
|
||||
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
|
||||
# $1 - target path with name of binary
|
||||
# $2 - package url which can be installed
|
||||
# $3 - specific version of package
|
||||
define go-install-tool
|
||||
@[ -f "$(1)-$(3)" ] || { \
|
||||
set -e; \
|
||||
package=$(2)@$(3) ;\
|
||||
echo "Downloading $${package}" ;\
|
||||
rm -f $(1) || true ;\
|
||||
GOBIN=$(LOCALBIN) go install $${package} ;\
|
||||
mv $(1) $(1)-$(3) ;\
|
||||
} ;\
|
||||
ln -sf $(1)-$(3) $(1)
|
||||
endef
|
||||
KUSTOMIZE ?= go tool kustomize
|
||||
CONTROLLER_GEN ?= go tool controller-gen
|
||||
ENVTEST ?= go tool setup-envtest
|
||||
GOLANGCI_LINT = go tool golangci-lint
|
||||
|
|
|
@ -37,7 +37,7 @@ This operator tries to be as un-opionionated as possible and thereofore does not
|
|||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
- go version v1.23.x+
|
||||
- go version v1.24.x+
|
||||
- docker version 27.+.
|
||||
- kubectl version v1.30.0+.
|
||||
- Access to a Kubernetes v1.30.+ cluster.
|
||||
|
|
10
Tiltfile
10
Tiltfile
|
@ -22,6 +22,8 @@ local_resource(
|
|||
resource_deps=[]
|
||||
)
|
||||
|
||||
k8s_kind('Cluster', api_version='postgresql.cnpg.io/v1')
|
||||
|
||||
docker_build_with_restart(
|
||||
'supabase-operator',
|
||||
'.',
|
||||
|
@ -39,10 +41,11 @@ k8s_resource('supabase-controller-manager')
|
|||
k8s_resource(
|
||||
workload='supabase-control-plane',
|
||||
port_forwards=18000,
|
||||
resource_deps=[]
|
||||
)
|
||||
|
||||
k8s_resource(
|
||||
objects=["cluster-example:Cluster:supabase-demo"],
|
||||
workload='cluster-example',
|
||||
new_name='Postgres cluster',
|
||||
port_forwards=5432
|
||||
)
|
||||
|
@ -62,6 +65,11 @@ k8s_resource(
|
|||
objects=["gateway-sample:APIGateway:supabase-demo"],
|
||||
extra_pod_selectors={"app.kubernetes.io/component": "api-gateway"},
|
||||
port_forwards=[3000, 8000, 19000],
|
||||
links=[
|
||||
link("https://localhost:3000", "Studio"),
|
||||
link("http://localhost:8000", "API"),
|
||||
link("http://localhost:19000", "Envoy Admin Interface")
|
||||
],
|
||||
new_name='API Gateway',
|
||||
resource_deps=[
|
||||
'supabase-controller-manager'
|
||||
|
|
|
@ -80,7 +80,7 @@ type EnvoySpec struct {
|
|||
// ControlPlane - configure the control plane where Envoy will retrieve its configuration from
|
||||
ControlPlane *ControlPlaneSpec `json:"controlPlane"`
|
||||
// WorkloadTemplate - customize the Envoy deployment
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
// DisableIPv6 - disable IPv6 for the Envoy instance
|
||||
// this will force Envoy to use IPv4 for upstream hosts (mostly for the OAuth2 token endpoint)
|
||||
DisableIPv6 bool `json:"disableIPv6,omitempty"`
|
||||
|
@ -128,10 +128,13 @@ const (
|
|||
)
|
||||
|
||||
type DashboardOAuth2Spec struct {
|
||||
// OpenIDIssuer - if set the defaulter will fetch the discovery document and fill
|
||||
// TokenEndpoint and AuthorizationEndpoint based on the discovery document
|
||||
OpenIDIssuer string `json:"openIdIssuer,omitempty"`
|
||||
// TokenEndpoint - endpoint where Envoy will retrieve the OAuth2 access and identity token from
|
||||
TokenEndpoint string `json:"tokenEndpoint"`
|
||||
TokenEndpoint string `json:"tokenEndpoint,omitempty"`
|
||||
// AuthorizationEndpoint - endpoint where the user will be redirected to authenticate
|
||||
AuthorizationEndpoint string `json:"authorizationEndpoint"`
|
||||
AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
|
||||
// ClientID - client ID to authenticate with the OAuth2 provider
|
||||
ClientID string `json:"clientId"`
|
||||
// Scopes - scopes to request from the OAuth2 provider (e.g. "openid", "profile", ...) - optional
|
||||
|
@ -142,11 +145,24 @@ type DashboardOAuth2Spec struct {
|
|||
ClientSecretRef *corev1.SecretKeySelector `json:"clientSecretRef"`
|
||||
}
|
||||
|
||||
type DashboardBasicAuthSpec struct{}
|
||||
type DashboardBasicAuthSpec struct {
|
||||
// UsersInline - [htpasswd format](https://httpd.apache.org/docs/2.4/programs/htpasswd.html)
|
||||
// +kubebuilder:validation:items:Pattern="^[\\w_.]+:\\{SHA\\}[A-z0-9]+=*$"
|
||||
UsersInline []string `json:"usersInline,omitempty"`
|
||||
// PlaintextUsersSecretRef - name of a secret that contains plaintext credentials in key-value form
|
||||
// if not empty, credentials will be merged with inline users
|
||||
PlaintextUsersSecretRef string `json:"plaintextUsersSecretRef,omitempty"`
|
||||
}
|
||||
|
||||
type DashboardAuthSpec struct {
|
||||
OAuth2 *DashboardOAuth2Spec `json:"oauth2,omitempty"`
|
||||
Basic *DashboardBasicAuthSpec `json:"basic,omitempty"`
|
||||
// OAuth2 - configure oauth2 authentication for the dashhboard listener
|
||||
// if configured, will be preferred over Basic authentication configuration
|
||||
// effectively disabling basic auth
|
||||
OAuth2 *DashboardOAuth2Spec `json:"oauth2,omitempty"`
|
||||
// Basic - HTTP basic auth configuration, this should only be used in exceptions
|
||||
// e.g. during evaluations or for local development
|
||||
// only used if no other authentication is configured
|
||||
Basic *DashboardBasicAuthSpec `json:"basic,omitempty"`
|
||||
}
|
||||
|
||||
type DashboardEndpointSpec struct {
|
||||
|
@ -188,6 +204,14 @@ func (s *DashboardEndpointSpec) OAuth2() *DashboardOAuth2Spec {
|
|||
return s.Auth.OAuth2
|
||||
}
|
||||
|
||||
func (s *DashboardEndpointSpec) Basic() *DashboardBasicAuthSpec {
|
||||
if s == nil || s.Auth == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.Auth.Basic
|
||||
}
|
||||
|
||||
// APIGatewaySpec defines the desired state of APIGateway.
|
||||
type APIGatewaySpec struct {
|
||||
// Envoy - configure the envoy instance and most importantly the control-plane
|
||||
|
|
|
@ -91,16 +91,16 @@ type ContainerTemplate struct {
|
|||
AdditionalEnv []corev1.EnvVar `json:"additionalEnv,omitempty"`
|
||||
}
|
||||
|
||||
type WorkloadTemplate struct {
|
||||
type WorkloadSpec struct {
|
||||
Replicas *int32 `json:"replicas,omitempty"`
|
||||
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"`
|
||||
AdditionalLabels map[string]string `json:"additionalLabels,omitempty"`
|
||||
// Workload - customize the container template of the workload
|
||||
Workload *ContainerTemplate `json:"workload,omitempty"`
|
||||
// ContainerSpec - customize the container template of the workload
|
||||
ContainerSpec *ContainerTemplate `json:"container,omitempty"`
|
||||
AdditionalVolumes []corev1.Volume `json:"additionalVolumes,omitempty"`
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) ReplicaCount() *int32 {
|
||||
func (t *WorkloadSpec) ReplicaCount() *int32 {
|
||||
if t != nil && t.Replicas != nil {
|
||||
return t.Replicas
|
||||
}
|
||||
|
@ -108,20 +108,20 @@ func (t *WorkloadTemplate) ReplicaCount() *int32 {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
|
||||
if t == nil || t.Workload == nil || len(t.Workload.AdditionalEnv) == 0 {
|
||||
func (t *WorkloadSpec) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
|
||||
if t == nil || t.ContainerSpec == nil || len(t.ContainerSpec.AdditionalEnv) == 0 {
|
||||
return basicEnv
|
||||
}
|
||||
|
||||
existingKeys := make(map[string]bool, len(basicEnv)+len(t.Workload.AdditionalEnv))
|
||||
existingKeys := make(map[string]bool, len(basicEnv)+len(t.ContainerSpec.AdditionalEnv))
|
||||
|
||||
merged := append(make([]corev1.EnvVar, 0, len(basicEnv)+len(t.Workload.AdditionalEnv)), basicEnv...)
|
||||
merged := append(make([]corev1.EnvVar, 0, len(basicEnv)+len(t.ContainerSpec.AdditionalEnv)), basicEnv...)
|
||||
|
||||
for _, v := range basicEnv {
|
||||
existingKeys[v.Name] = true
|
||||
}
|
||||
|
||||
for _, v := range t.Workload.AdditionalEnv {
|
||||
for _, v := range t.ContainerSpec.AdditionalEnv {
|
||||
if _, alreadyPresent := existingKeys[v.Name]; alreadyPresent {
|
||||
continue
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func (t *WorkloadTemplate) MergeEnv(basicEnv []corev1.EnvVar) []corev1.EnvVar {
|
|||
return merged
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) MergeLabels(initial map[string]string, toAppend ...map[string]string) map[string]string {
|
||||
func (t *WorkloadSpec) MergeLabels(initial map[string]string, toAppend ...map[string]string) map[string]string {
|
||||
result := make(map[string]string)
|
||||
|
||||
maps.Copy(result, initial)
|
||||
|
@ -156,47 +156,47 @@ func (t *WorkloadTemplate) MergeLabels(initial map[string]string, toAppend ...ma
|
|||
return result
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) Image(defaultImage string) string {
|
||||
if t != nil && t.Workload != nil && t.Workload.Image != "" {
|
||||
return t.Workload.Image
|
||||
func (t *WorkloadSpec) Image(defaultImage string) string {
|
||||
if t != nil && t.ContainerSpec != nil && t.ContainerSpec.Image != "" {
|
||||
return t.ContainerSpec.Image
|
||||
}
|
||||
|
||||
return defaultImage
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) ImagePullPolicy() corev1.PullPolicy {
|
||||
if t != nil && t.Workload != nil && t.Workload.PullPolicy != "" {
|
||||
return t.Workload.PullPolicy
|
||||
func (t *WorkloadSpec) ImagePullPolicy() corev1.PullPolicy {
|
||||
if t != nil && t.ContainerSpec != nil && t.ContainerSpec.PullPolicy != "" {
|
||||
return t.ContainerSpec.PullPolicy
|
||||
}
|
||||
|
||||
return corev1.PullIfNotPresent
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) PullSecrets() []corev1.LocalObjectReference {
|
||||
if t != nil && t.Workload != nil && len(t.Workload.ImagePullSecrets) > 0 {
|
||||
return t.Workload.ImagePullSecrets
|
||||
func (t *WorkloadSpec) PullSecrets() []corev1.LocalObjectReference {
|
||||
if t != nil && t.ContainerSpec != nil && len(t.ContainerSpec.ImagePullSecrets) > 0 {
|
||||
return t.ContainerSpec.ImagePullSecrets
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) Resources() corev1.ResourceRequirements {
|
||||
if t != nil && t.Workload != nil {
|
||||
return t.Workload.Resources
|
||||
func (t *WorkloadSpec) Resources() corev1.ResourceRequirements {
|
||||
if t != nil && t.ContainerSpec != nil {
|
||||
return t.ContainerSpec.Resources
|
||||
}
|
||||
|
||||
return corev1.ResourceRequirements{}
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) AdditionalVolumeMounts(defaultMounts ...corev1.VolumeMount) []corev1.VolumeMount {
|
||||
if t != nil && t.Workload != nil {
|
||||
return append(defaultMounts, t.Workload.VolumeMounts...)
|
||||
func (t *WorkloadSpec) AdditionalVolumeMounts(defaultMounts ...corev1.VolumeMount) []corev1.VolumeMount {
|
||||
if t != nil && t.ContainerSpec != nil {
|
||||
return append(defaultMounts, t.ContainerSpec.VolumeMounts...)
|
||||
}
|
||||
|
||||
return defaultMounts
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) Volumes(defaultVolumes ...corev1.Volume) []corev1.Volume {
|
||||
func (t *WorkloadSpec) Volumes(defaultVolumes ...corev1.Volume) []corev1.Volume {
|
||||
if t == nil {
|
||||
return defaultVolumes
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ func (t *WorkloadTemplate) Volumes(defaultVolumes ...corev1.Volume) []corev1.Vol
|
|||
return append(defaultVolumes, t.AdditionalVolumes...)
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) PodSecurityContext() *corev1.PodSecurityContext {
|
||||
func (t *WorkloadSpec) PodSecurityContext() *corev1.PodSecurityContext {
|
||||
if t != nil && t.SecurityContext != nil {
|
||||
return t.SecurityContext
|
||||
}
|
||||
|
@ -214,9 +214,9 @@ func (t *WorkloadTemplate) PodSecurityContext() *corev1.PodSecurityContext {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *WorkloadTemplate) ContainerSecurityContext(uid, gid int64) *corev1.SecurityContext {
|
||||
if t != nil && t.Workload != nil && t.Workload.SecurityContext != nil {
|
||||
return t.Workload.SecurityContext
|
||||
func (t *WorkloadSpec) ContainerSecurityContext(uid, gid int64) *corev1.SecurityContext {
|
||||
if t != nil && t.ContainerSpec != nil && t.ContainerSpec.SecurityContext != nil {
|
||||
return t.ContainerSpec.SecurityContext
|
||||
}
|
||||
|
||||
return &corev1.SecurityContext{
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -25,6 +26,7 @@ import (
|
|||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -59,7 +61,7 @@ type DatabaseRoles struct {
|
|||
|
||||
type Database struct {
|
||||
DSN *string `json:"dsn,omitempty"`
|
||||
DSNSecretRef *corev1.SecretKeySelector `json:"dsnSecretRef,omitempty"`
|
||||
DSNSecretRef *corev1.SecretKeySelector `json:"dsnSecretRef"`
|
||||
Roles DatabaseRoles `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -167,8 +169,8 @@ type PostgrestSpec struct {
|
|||
// MaxRows - maximum number of rows PostgREST will load at a time
|
||||
// +kubebuilder:default=1000
|
||||
MaxRows int `json:"maxRows,omitempty"`
|
||||
// WorkloadTemplate - customize the PostgREST workload
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
// WorkloadSpec - customize the PostgREST workload
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
}
|
||||
|
||||
type AuthProviderMeta struct {
|
||||
|
@ -365,12 +367,12 @@ func (p *AuthProviders) Vars(apiExternalURL string) []corev1.EnvVar {
|
|||
}
|
||||
|
||||
type AuthSpec struct {
|
||||
AdditionalRedirectUrls []string `json:"additionalRedirectUrls,omitempty"`
|
||||
DisableSignup *bool `json:"disableSignup,omitempty"`
|
||||
AnonymousUsersEnabled *bool `json:"anonymousUsersEnabled,omitempty"`
|
||||
Providers *AuthProviders `json:"providers,omitempty"`
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
EmailSignupDisabled *bool `json:"emailSignupDisabled,omitempty"`
|
||||
AdditionalRedirectUrls []string `json:"additionalRedirectUrls,omitempty"`
|
||||
DisableSignup *bool `json:"disableSignup,omitempty"`
|
||||
AnonymousUsersEnabled *bool `json:"anonymousUsersEnabled,omitempty"`
|
||||
Providers *AuthProviders `json:"providers,omitempty"`
|
||||
WorkloadTemplate *WorkloadSpec `json:"workloadTemplate,omitempty"`
|
||||
EmailSignupDisabled *bool `json:"emailSignupDisabled,omitempty"`
|
||||
}
|
||||
|
||||
// CoreSpec defines the desired state of Core.
|
||||
|
@ -387,20 +389,89 @@ type CoreSpec struct {
|
|||
Auth *AuthSpec `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type MigrationStatus map[string]metav1.Time
|
||||
type MigrationConditionStatus string
|
||||
|
||||
func (s MigrationStatus) IsApplied(name string) bool {
|
||||
_, ok := s[name]
|
||||
return ok
|
||||
}
|
||||
const (
|
||||
MigrationConditionStatusApplied MigrationConditionStatus = "Applied"
|
||||
MigrationConditionStatusFailed MigrationConditionStatus = "Failed"
|
||||
)
|
||||
|
||||
func (s MigrationStatus) Record(name string) {
|
||||
s[name] = metav1.Now()
|
||||
type MigrationScriptCondition struct {
|
||||
// Name - file name of the migration script
|
||||
Name string `json:"name"`
|
||||
// Hash - SHA256 hash of the script when it was last successfully applied
|
||||
Hash []byte `json:"hash"`
|
||||
// Status - whether the migration was applied or not
|
||||
// +kubebuilder:validation:Enum=Applied;Failed
|
||||
Status MigrationConditionStatus `json:"status"`
|
||||
// LastProbeTime - last time the operator tried to execute the migration script
|
||||
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
|
||||
// LastTransitionTime - last time the condition transitioned from one status to another
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
|
||||
// Reason - one-word, CamcelCase reason for the condition's last transition
|
||||
Reason string `json:"reason,omitempty"`
|
||||
// Message - human-readable message indicating details about the last transition
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type DatabaseStatus struct {
|
||||
AppliedMigrations MigrationStatus `json:"appliedMigrations,omitempty"`
|
||||
Roles map[string][]byte `json:"roles,omitempty"`
|
||||
MigrationConditions []MigrationScriptCondition `json:"migrationConditions,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
Roles map[string][]byte `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
func (s DatabaseStatus) IsMigrationUpToDate(name string, hash []byte) (found bool, upToDate bool) {
|
||||
for _, cond := range s.MigrationConditions {
|
||||
if cond.Name == name {
|
||||
return true, bytes.Equal(cond.Hash, hash)
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
||||
func (s *DatabaseStatus) RecordMigrationCondition(name string, hash []byte, err error) error {
|
||||
var (
|
||||
now = time.Now()
|
||||
newStatus = MigrationConditionStatusApplied
|
||||
lastProbeTime = metav1.NewTime(now)
|
||||
lastTransitionTime = metav1.NewTime(now)
|
||||
message string
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
newStatus = MigrationConditionStatusFailed
|
||||
message = err.Error()
|
||||
}
|
||||
|
||||
for idx, cond := range s.MigrationConditions {
|
||||
if cond.Name == name {
|
||||
lastTransitionTime = cond.LastTransitionTime
|
||||
if cond.Status != newStatus {
|
||||
lastTransitionTime = metav1.NewTime(now)
|
||||
}
|
||||
|
||||
cond.Hash = hash
|
||||
cond.Status = newStatus
|
||||
cond.LastProbeTime = lastProbeTime
|
||||
cond.LastTransitionTime = lastTransitionTime
|
||||
cond.Reason = "Outdated"
|
||||
cond.Message = message
|
||||
|
||||
s.MigrationConditions[idx] = cond
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.MigrationConditions = append(s.MigrationConditions, MigrationScriptCondition{
|
||||
Name: name,
|
||||
Hash: hash,
|
||||
Status: newStatus,
|
||||
LastProbeTime: lastProbeTime,
|
||||
LastTransitionTime: lastTransitionTime,
|
||||
Message: message,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type CoreConditionType string
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
type StudioSpec struct {
|
||||
JWT *JwtSpec `json:"jwt,omitempty"`
|
||||
// WorkloadTemplate - customize the studio deployment
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
// GatewayServiceSelector - selector to find the service for the API gateway
|
||||
// Required to configure the API URL in the studio deployment
|
||||
// If you don't run multiple APIGateway instances in the same namespaces, the default will be fine
|
||||
|
@ -37,7 +37,7 @@ type StudioSpec struct {
|
|||
|
||||
type PGMetaSpec struct {
|
||||
// WorkloadTemplate - customize the pg-meta deployment
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
}
|
||||
|
||||
type DbCredentialsReference struct {
|
||||
|
|
|
@ -191,7 +191,7 @@ type StorageApiSpec struct {
|
|||
// UploadTemp - configure the emptyDir for storing intermediate files during uploads
|
||||
UploadTemp *UploadTempSpec `json:"uploadTemp,omitempty"`
|
||||
// WorkloadTemplate - customize the Storage API workload
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
}
|
||||
|
||||
type ImageProxySpec struct {
|
||||
|
@ -199,7 +199,7 @@ type ImageProxySpec struct {
|
|||
Enable bool `json:"enable,omitempty"`
|
||||
EnabledWebPDetection bool `json:"enableWebPDetection,omitempty"`
|
||||
// WorkloadTemplate - customize the image proxy workload
|
||||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
WorkloadSpec *WorkloadSpec `json:"workloadSpec,omitempty"`
|
||||
}
|
||||
|
||||
// StorageSpec defines the desired state of Storage.
|
||||
|
|
|
@ -21,7 +21,7 @@ limitations under the License.
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
@ -252,7 +252,7 @@ func (in *AuthSpec) DeepCopyInto(out *AuthSpec) {
|
|||
}
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.EmailSignupDisabled != nil {
|
||||
|
@ -506,7 +506,7 @@ func (in *DashboardAuthSpec) DeepCopyInto(out *DashboardAuthSpec) {
|
|||
if in.Basic != nil {
|
||||
in, out := &in.Basic, &out.Basic
|
||||
*out = new(DashboardBasicAuthSpec)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,6 +523,11 @@ func (in *DashboardAuthSpec) DeepCopy() *DashboardAuthSpec {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DashboardBasicAuthSpec) DeepCopyInto(out *DashboardBasicAuthSpec) {
|
||||
*out = *in
|
||||
if in.UsersInline != nil {
|
||||
in, out := &in.UsersInline, &out.UsersInline
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardBasicAuthSpec.
|
||||
|
@ -747,11 +752,11 @@ func (in *DatabaseRolesSecrets) DeepCopy() *DatabaseRolesSecrets {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DatabaseStatus) DeepCopyInto(out *DatabaseStatus) {
|
||||
*out = *in
|
||||
if in.AppliedMigrations != nil {
|
||||
in, out := &in.AppliedMigrations, &out.AppliedMigrations
|
||||
*out = make(MigrationStatus, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
if in.MigrationConditions != nil {
|
||||
in, out := &in.MigrationConditions, &out.MigrationConditions
|
||||
*out = make([]MigrationScriptCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Roles != nil {
|
||||
|
@ -916,9 +921,9 @@ func (in *EnvoySpec) DeepCopyInto(out *EnvoySpec) {
|
|||
*out = new(ControlPlaneSpec)
|
||||
**out = **in
|
||||
}
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Debugging != nil {
|
||||
|
@ -993,9 +998,9 @@ func (in *GithubAuthProvider) DeepCopy() *GithubAuthProvider {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImageProxySpec) DeepCopyInto(out *ImageProxySpec) {
|
||||
*out = *in
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
@ -1041,24 +1046,25 @@ func (in *JwtSpec) DeepCopy() *JwtSpec {
|
|||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in MigrationStatus) DeepCopyInto(out *MigrationStatus) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(MigrationStatus, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
func (in *MigrationScriptCondition) DeepCopyInto(out *MigrationScriptCondition) {
|
||||
*out = *in
|
||||
if in.Hash != nil {
|
||||
in, out := &in.Hash, &out.Hash
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MigrationStatus.
|
||||
func (in MigrationStatus) DeepCopy() MigrationStatus {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MigrationScriptCondition.
|
||||
func (in *MigrationScriptCondition) DeepCopy() *MigrationScriptCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MigrationStatus)
|
||||
out := new(MigrationScriptCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
|
@ -1084,9 +1090,9 @@ func (in *OAuthProvider) DeepCopy() *OAuthProvider {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PGMetaSpec) DeepCopyInto(out *PGMetaSpec) {
|
||||
*out = *in
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
@ -1130,9 +1136,9 @@ func (in *PostgrestSpec) DeepCopyInto(out *PostgrestSpec) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
@ -1289,9 +1295,9 @@ func (in *StorageApiSpec) DeepCopyInto(out *StorageApiSpec) {
|
|||
*out = new(UploadTempSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
@ -1382,9 +1388,9 @@ func (in *StudioSpec) DeepCopyInto(out *StudioSpec) {
|
|||
*out = new(JwtSpec)
|
||||
**out = **in
|
||||
}
|
||||
if in.WorkloadTemplate != nil {
|
||||
in, out := &in.WorkloadTemplate, &out.WorkloadTemplate
|
||||
*out = new(WorkloadTemplate)
|
||||
if in.WorkloadSpec != nil {
|
||||
in, out := &in.WorkloadSpec, &out.WorkloadSpec
|
||||
*out = new(WorkloadSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.GatewayServiceMatchLabels != nil {
|
||||
|
@ -1442,7 +1448,7 @@ func (in *UploadTempSpec) DeepCopy() *UploadTempSpec {
|
|||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
|
||||
func (in *WorkloadSpec) DeepCopyInto(out *WorkloadSpec) {
|
||||
*out = *in
|
||||
if in.Replicas != nil {
|
||||
in, out := &in.Replicas, &out.Replicas
|
||||
|
@ -1461,8 +1467,8 @@ func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
|
|||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Workload != nil {
|
||||
in, out := &in.Workload, &out.Workload
|
||||
if in.ContainerSpec != nil {
|
||||
in, out := &in.ContainerSpec, &out.ContainerSpec
|
||||
*out = new(ContainerTemplate)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
|
@ -1475,12 +1481,12 @@ func (in *WorkloadTemplate) DeepCopyInto(out *WorkloadTemplate) {
|
|||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadTemplate.
|
||||
func (in *WorkloadTemplate) DeepCopy() *WorkloadTemplate {
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadSpec.
|
||||
func (in *WorkloadSpec) DeepCopy() *WorkloadSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WorkloadTemplate)
|
||||
out := new(WorkloadSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
|
@ -32,6 +33,7 @@ var migrationsFS embed.FS
|
|||
type Script struct {
|
||||
FileName string
|
||||
Content string
|
||||
Hash []byte
|
||||
}
|
||||
|
||||
func InitScripts() iter.Seq2[Script, error] {
|
||||
|
@ -49,10 +51,18 @@ func RoleCreationScript(roleName string) (Script, error) {
|
|||
return Script{}, err
|
||||
}
|
||||
|
||||
return Script{fileName, string(content)}, nil
|
||||
hash := sha256.New()
|
||||
_, _ = hash.Write(content)
|
||||
|
||||
return Script{
|
||||
FileName: fileName,
|
||||
Content: string(content),
|
||||
Hash: hash.Sum(nil),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readScripts(dir string) iter.Seq2[Script, error] {
|
||||
hash := sha256.New()
|
||||
return func(yield func(Script, error) bool) {
|
||||
files, err := migrationsFS.ReadDir(dir)
|
||||
if err != nil {
|
||||
|
@ -76,11 +86,16 @@ func readScripts(dir string) iter.Seq2[Script, error] {
|
|||
}
|
||||
}
|
||||
|
||||
_, _ = hash.Write(content)
|
||||
|
||||
s := Script{
|
||||
FileName: file.Name(),
|
||||
Content: string(content),
|
||||
Hash: hash.Sum(nil),
|
||||
}
|
||||
|
||||
hash.Reset()
|
||||
|
||||
if !yield(s, nil) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
-- migrate:up
|
||||
|
||||
-- demote postgres user
|
||||
GRANT ALL ON DATABASE postgres TO postgres;
|
||||
GRANT ALL ON SCHEMA auth TO postgres;
|
||||
GRANT ALL ON SCHEMA extensions TO postgres;
|
||||
GRANT ALL ON SCHEMA storage TO postgres;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA auth TO postgres;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA storage TO postgres;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA extensions TO postgres;
|
||||
GRANT ALL ON ALL SEQUENCES IN SCHEMA auth TO postgres;
|
||||
GRANT ALL ON ALL SEQUENCES IN SCHEMA storage TO postgres;
|
||||
GRANT ALL ON ALL SEQUENCES IN SCHEMA extensions TO postgres;
|
||||
GRANT ALL ON ALL ROUTINES IN SCHEMA auth TO postgres;
|
||||
GRANT ALL ON ALL ROUTINES IN SCHEMA storage TO postgres;
|
||||
GRANT ALL ON ALL ROUTINES IN SCHEMA extensions TO postgres;
|
||||
ALTER ROLE postgres NOSUPERUSER CREATEDB CREATEROLE LOGIN REPLICATION BYPASSRLS;
|
||||
|
||||
-- migrate:down
|
|
@ -5,34 +5,44 @@ DECLARE
|
|||
pgsodium_exists boolean;
|
||||
vault_exists boolean;
|
||||
BEGIN
|
||||
pgsodium_exists = (
|
||||
select count(*) = 1
|
||||
from pg_available_extensions
|
||||
where name = 'pgsodium'
|
||||
and default_version in ('3.1.6', '3.1.7', '3.1.8', '3.1.9')
|
||||
);
|
||||
|
||||
vault_exists = (
|
||||
IF EXISTS (SELECT FROM pg_available_extensions WHERE name = 'supabase_vault' AND default_version != '0.2.8') THEN
|
||||
CREATE EXTENSION IF NOT EXISTS supabase_vault;
|
||||
|
||||
-- for some reason extension custom scripts aren't run during AMI build, so
|
||||
-- we manually run it here
|
||||
GRANT USAGE ON SCHEMA vault TO postgres WITH GRANT OPTION;
|
||||
GRANT SELECT, DELETE ON vault.secrets, vault.decrypted_secrets TO postgres WITH GRANT OPTION;
|
||||
GRANT EXECUTE ON FUNCTION vault.create_secret, vault.update_secret, vault._crypto_aead_det_decrypt TO postgres WITH GRANT OPTION;
|
||||
ELSE
|
||||
pgsodium_exists = (
|
||||
select count(*) = 1
|
||||
from pg_available_extensions
|
||||
where name = 'supabase_vault'
|
||||
);
|
||||
|
||||
IF pgsodium_exists
|
||||
THEN
|
||||
create extension if not exists pgsodium;
|
||||
|
||||
grant pgsodium_keyiduser to postgres with admin option;
|
||||
grant pgsodium_keyholder to postgres with admin option;
|
||||
grant pgsodium_keymaker to postgres with admin option;
|
||||
|
||||
grant execute on function pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) to service_role;
|
||||
grant execute on function pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) to service_role;
|
||||
grant execute on function pgsodium.crypto_aead_det_keygen to service_role;
|
||||
|
||||
IF vault_exists
|
||||
where name = 'pgsodium'
|
||||
and default_version in ('3.1.6', '3.1.7', '3.1.8', '3.1.9')
|
||||
);
|
||||
|
||||
vault_exists = (
|
||||
select count(*) = 1
|
||||
from pg_available_extensions
|
||||
where name = 'supabase_vault'
|
||||
);
|
||||
|
||||
IF pgsodium_exists
|
||||
THEN
|
||||
create extension if not exists supabase_vault;
|
||||
create extension if not exists pgsodium;
|
||||
|
||||
grant pgsodium_keyiduser to postgres with admin option;
|
||||
grant pgsodium_keyholder to postgres with admin option;
|
||||
grant pgsodium_keymaker to postgres with admin option;
|
||||
|
||||
grant execute on function pgsodium.crypto_aead_det_decrypt(bytea, bytea, uuid, bytea) to service_role;
|
||||
grant execute on function pgsodium.crypto_aead_det_encrypt(bytea, bytea, uuid, bytea) to service_role;
|
||||
grant execute on function pgsodium.crypto_aead_det_keygen to service_role;
|
||||
|
||||
IF vault_exists
|
||||
THEN
|
||||
create extension if not exists supabase_vault;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
|
|
|
@ -4,5 +4,12 @@ ALTER ROLE authenticated inherit;
|
|||
ALTER ROLE anon inherit;
|
||||
ALTER ROLE service_role inherit;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgsodium_keyholder') THEN
|
||||
GRANT pgsodium_keyholder to service_role;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- migrate:down
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
-- migrate:up
|
||||
alter role supabase_admin set log_statement = none;
|
||||
alter role supabase_auth_admin set log_statement = none;
|
||||
alter role supabase_storage_admin set log_statement = none;
|
||||
|
||||
-- migrate:down
|
3
assets/migrations/setup/realtime.sql
Normal file
3
assets/migrations/setup/realtime.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
create schema if not exists _realtime;
|
||||
|
||||
alter schema _realtime owner to supabase_admin;
|
|
@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.17.1
|
||||
controller-gen.kubebuilder.io/version: v0.17.2
|
||||
name: apigateways.supabase.k8s.icb4dc0.de
|
||||
spec:
|
||||
group: supabase.k8s.icb4dc0.de
|
||||
|
@ -121,8 +121,28 @@ spec:
|
|||
endpoint
|
||||
properties:
|
||||
basic:
|
||||
description: |-
|
||||
Basic - HTTP basic auth configuration, this should only be used in exceptions
|
||||
e.g. during evaluations or for local development
|
||||
only used if no other authentication is configured
|
||||
properties:
|
||||
plaintextUsersSecretRef:
|
||||
description: |-
|
||||
PlaintextUsersSecretRef - name of a secret that contains plaintext credentials in key-value form
|
||||
if not empty, credentials will be merged with inline users
|
||||
type: string
|
||||
usersInline:
|
||||
description: UsersInline - [htpasswd format](https://httpd.apache.org/docs/2.4/programs/htpasswd.html)
|
||||
items:
|
||||
pattern: ^[\w_.]+:\{SHA\}[A-z0-9]+=*$
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
oauth2:
|
||||
description: |-
|
||||
OAuth2 - configure oauth2 authentication for the dashhboard listener
|
||||
if configured, will be preferred over Basic authentication configuration
|
||||
effectively disabling basic auth
|
||||
properties:
|
||||
authorizationEndpoint:
|
||||
description: AuthorizationEndpoint - endpoint where the
|
||||
|
@ -157,6 +177,11 @@ spec:
|
|||
- key
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
openIdIssuer:
|
||||
description: |-
|
||||
OpenIDIssuer - if set the defaulter will fetch the discovery document and fill
|
||||
TokenEndpoint and AuthorizationEndpoint based on the discovery document
|
||||
type: string
|
||||
resources:
|
||||
description: Resources - resources to request from the
|
||||
OAuth2 provider (e.g. "user", "email", ...) - optional
|
||||
|
@ -174,10 +199,8 @@ spec:
|
|||
retrieve the OAuth2 access and identity token from
|
||||
type: string
|
||||
required:
|
||||
- authorizationEndpoint
|
||||
- clientId
|
||||
- clientSecretRef
|
||||
- tokenEndpoint
|
||||
type: object
|
||||
type: object
|
||||
tls:
|
||||
|
@ -272,7 +295,7 @@ spec:
|
|||
if not set, the name of the APIGateway resource will be used
|
||||
The primary use case is to make the assignment of multiple supabase instances in a single namespace explicit.
|
||||
type: string
|
||||
workloadTemplate:
|
||||
workloadSpec:
|
||||
description: WorkloadTemplate - customize the Envoy deployment
|
||||
properties:
|
||||
additionalLabels:
|
||||
|
@ -2079,248 +2102,9 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
type: array
|
||||
replicas:
|
||||
format: int32
|
||||
type: integer
|
||||
securityContext:
|
||||
description: |-
|
||||
PodSecurityContext holds pod-level security attributes and common container settings.
|
||||
Some fields are also present in container.securityContext. Field values of
|
||||
container.securityContext take precedence over field values of PodSecurityContext.
|
||||
properties:
|
||||
appArmorProfile:
|
||||
description: |-
|
||||
appArmorProfile is the AppArmor options to use by the containers in this pod.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
localhostProfile:
|
||||
description: |-
|
||||
localhostProfile indicates a profile loaded on the node that should be used.
|
||||
The profile must be preconfigured on the node to work.
|
||||
Must match the loaded name of the profile.
|
||||
Must be set if and only if type is "Localhost".
|
||||
type: string
|
||||
type:
|
||||
description: |-
|
||||
type indicates which kind of AppArmor profile will be applied.
|
||||
Valid options are:
|
||||
Localhost - a profile pre-loaded on the node.
|
||||
RuntimeDefault - the container runtime's default profile.
|
||||
Unconfined - no AppArmor enforcement.
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
fsGroup:
|
||||
description: |-
|
||||
A special supplemental group that applies to all containers in a pod.
|
||||
Some volume types allow the Kubelet to change the ownership of that volume
|
||||
to be owned by the pod:
|
||||
|
||||
1. The owning GID will be the FSGroup
|
||||
2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
|
||||
3. The permission bits are OR'd with rw-rw----
|
||||
|
||||
If unset, the Kubelet will not modify the ownership and permissions of any volume.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
fsGroupChangePolicy:
|
||||
description: |-
|
||||
fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
|
||||
before being exposed inside Pod. This field will only apply to
|
||||
volume types which support fsGroup based ownership(and permissions).
|
||||
It will have no effect on ephemeral volume types such as: secret, configmaps
|
||||
and emptydir.
|
||||
Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
runAsGroup:
|
||||
description: |-
|
||||
The GID to run the entrypoint of the container process.
|
||||
Uses runtime default if unset.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence
|
||||
for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
runAsNonRoot:
|
||||
description: |-
|
||||
Indicates that the container must run as a non-root user.
|
||||
If true, the Kubelet will validate the image at runtime to ensure that it
|
||||
does not run as UID 0 (root) and fail to start the container if it does.
|
||||
If unset or false, no such validation will be performed.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
type: boolean
|
||||
runAsUser:
|
||||
description: |-
|
||||
The UID to run the entrypoint of the container process.
|
||||
Defaults to user specified in image metadata if unspecified.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence
|
||||
for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
seLinuxChangePolicy:
|
||||
description: |-
|
||||
seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
|
||||
It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
|
||||
Valid values are "MountOption" and "Recursive".
|
||||
|
||||
"Recursive" means relabeling of all files on all Pod volumes by the container runtime.
|
||||
This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
|
||||
|
||||
"MountOption" mounts all eligible Pod volumes with `-o context` mount option.
|
||||
This requires all Pods that share the same volume to use the same SELinux label.
|
||||
It is not possible to share the same volume among privileged and unprivileged Pods.
|
||||
Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
|
||||
whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
|
||||
CSIDriver instance. Other volumes are always re-labelled recursively.
|
||||
"MountOption" value is allowed only when SELinuxMount feature gate is enabled.
|
||||
|
||||
If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
|
||||
If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
|
||||
and "Recursive" for all other volumes.
|
||||
|
||||
This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
|
||||
|
||||
All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
seLinuxOptions:
|
||||
description: |-
|
||||
The SELinux context to be applied to all containers.
|
||||
If unspecified, the container runtime will allocate a random SELinux context for each
|
||||
container. May also be set in SecurityContext. If set in
|
||||
both SecurityContext and PodSecurityContext, the value specified in SecurityContext
|
||||
takes precedence for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
level:
|
||||
description: Level is SELinux level label that applies
|
||||
to the container.
|
||||
type: string
|
||||
role:
|
||||
description: Role is a SELinux role label that applies
|
||||
to the container.
|
||||
type: string
|
||||
type:
|
||||
description: Type is a SELinux type label that applies
|
||||
to the container.
|
||||
type: string
|
||||
user:
|
||||
description: User is a SELinux user label that applies
|
||||
to the container.
|
||||
type: string
|
||||
type: object
|
||||
seccompProfile:
|
||||
description: |-
|
||||
The seccomp options to use by the containers in this pod.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
localhostProfile:
|
||||
description: |-
|
||||
localhostProfile indicates a profile defined in a file on the node should be used.
|
||||
The profile must be preconfigured on the node to work.
|
||||
Must be a descending path, relative to the kubelet's configured seccomp profile location.
|
||||
Must be set if type is "Localhost". Must NOT be set for any other type.
|
||||
type: string
|
||||
type:
|
||||
description: |-
|
||||
type indicates which kind of seccomp profile will be applied.
|
||||
Valid options are:
|
||||
|
||||
Localhost - a profile defined in a file on the node should be used.
|
||||
RuntimeDefault - the container runtime default profile should be used.
|
||||
Unconfined - no profile should be applied.
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
supplementalGroups:
|
||||
description: |-
|
||||
A list of groups applied to the first process run in each container, in
|
||||
addition to the container's primary GID and fsGroup (if specified). If
|
||||
the SupplementalGroupsPolicy feature is enabled, the
|
||||
supplementalGroupsPolicy field determines whether these are in addition
|
||||
to or instead of any group memberships defined in the container image.
|
||||
If unspecified, no additional groups are added, though group memberships
|
||||
defined in the container image may still be used, depending on the
|
||||
supplementalGroupsPolicy field.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
items:
|
||||
format: int64
|
||||
type: integer
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
supplementalGroupsPolicy:
|
||||
description: |-
|
||||
Defines how supplemental groups of the first container processes are calculated.
|
||||
Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
|
||||
(Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
|
||||
and the container runtime must implement support for this feature.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
sysctls:
|
||||
description: |-
|
||||
Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
|
||||
sysctls (by the container runtime) might fail to launch.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
items:
|
||||
description: Sysctl defines a kernel parameter to be
|
||||
set
|
||||
properties:
|
||||
name:
|
||||
description: Name of a property to set
|
||||
type: string
|
||||
value:
|
||||
description: Value of a property to set
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
windowsOptions:
|
||||
description: |-
|
||||
The Windows specific settings applied to all containers.
|
||||
If unspecified, the options within a container's SecurityContext will be used.
|
||||
If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
Note that this field cannot be set when spec.os.name is linux.
|
||||
properties:
|
||||
gmsaCredentialSpec:
|
||||
description: |-
|
||||
GMSACredentialSpec is where the GMSA admission webhook
|
||||
(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
|
||||
GMSA credential spec named by the GMSACredentialSpecName field.
|
||||
type: string
|
||||
gmsaCredentialSpecName:
|
||||
description: GMSACredentialSpecName is the name of
|
||||
the GMSA credential spec to use.
|
||||
type: string
|
||||
hostProcess:
|
||||
description: |-
|
||||
HostProcess determines if a container should be run as a 'Host Process' container.
|
||||
All of a Pod's containers must have the same effective HostProcess value
|
||||
(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
|
||||
In addition, if HostProcess is true then HostNetwork must also be set to true.
|
||||
type: boolean
|
||||
runAsUserName:
|
||||
description: |-
|
||||
The UserName in Windows to run the entrypoint of the container process.
|
||||
Defaults to the user specified in image metadata if unspecified.
|
||||
May also be set in PodSecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
workload:
|
||||
description: Workload - customize the container template of
|
||||
the workload
|
||||
container:
|
||||
description: ContainerSpec - customize the container template
|
||||
of the workload
|
||||
properties:
|
||||
additionalEnv:
|
||||
items:
|
||||
|
@ -2785,6 +2569,245 @@ spec:
|
|||
type: object
|
||||
type: array
|
||||
type: object
|
||||
replicas:
|
||||
format: int32
|
||||
type: integer
|
||||
securityContext:
|
||||
description: |-
|
||||
PodSecurityContext holds pod-level security attributes and common container settings.
|
||||
Some fields are also present in container.securityContext. Field values of
|
||||
container.securityContext take precedence over field values of PodSecurityContext.
|
||||
properties:
|
||||
appArmorProfile:
|
||||
description: |-
|
||||
appArmorProfile is the AppArmor options to use by the containers in this pod.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
localhostProfile:
|
||||
description: |-
|
||||
localhostProfile indicates a profile loaded on the node that should be used.
|
||||
The profile must be preconfigured on the node to work.
|
||||
Must match the loaded name of the profile.
|
||||
Must be set if and only if type is "Localhost".
|
||||
type: string
|
||||
type:
|
||||
description: |-
|
||||
type indicates which kind of AppArmor profile will be applied.
|
||||
Valid options are:
|
||||
Localhost - a profile pre-loaded on the node.
|
||||
RuntimeDefault - the container runtime's default profile.
|
||||
Unconfined - no AppArmor enforcement.
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
fsGroup:
|
||||
description: |-
|
||||
A special supplemental group that applies to all containers in a pod.
|
||||
Some volume types allow the Kubelet to change the ownership of that volume
|
||||
to be owned by the pod:
|
||||
|
||||
1. The owning GID will be the FSGroup
|
||||
2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
|
||||
3. The permission bits are OR'd with rw-rw----
|
||||
|
||||
If unset, the Kubelet will not modify the ownership and permissions of any volume.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
fsGroupChangePolicy:
|
||||
description: |-
|
||||
fsGroupChangePolicy defines behavior of changing ownership and permission of the volume
|
||||
before being exposed inside Pod. This field will only apply to
|
||||
volume types which support fsGroup based ownership(and permissions).
|
||||
It will have no effect on ephemeral volume types such as: secret, configmaps
|
||||
and emptydir.
|
||||
Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
runAsGroup:
|
||||
description: |-
|
||||
The GID to run the entrypoint of the container process.
|
||||
Uses runtime default if unset.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence
|
||||
for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
runAsNonRoot:
|
||||
description: |-
|
||||
Indicates that the container must run as a non-root user.
|
||||
If true, the Kubelet will validate the image at runtime to ensure that it
|
||||
does not run as UID 0 (root) and fail to start the container if it does.
|
||||
If unset or false, no such validation will be performed.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
type: boolean
|
||||
runAsUser:
|
||||
description: |-
|
||||
The UID to run the entrypoint of the container process.
|
||||
Defaults to user specified in image metadata if unspecified.
|
||||
May also be set in SecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence
|
||||
for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
format: int64
|
||||
type: integer
|
||||
seLinuxChangePolicy:
|
||||
description: |-
|
||||
seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
|
||||
It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
|
||||
Valid values are "MountOption" and "Recursive".
|
||||
|
||||
"Recursive" means relabeling of all files on all Pod volumes by the container runtime.
|
||||
This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
|
||||
|
||||
"MountOption" mounts all eligible Pod volumes with `-o context` mount option.
|
||||
This requires all Pods that share the same volume to use the same SELinux label.
|
||||
It is not possible to share the same volume among privileged and unprivileged Pods.
|
||||
Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
|
||||
whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
|
||||
CSIDriver instance. Other volumes are always re-labelled recursively.
|
||||
"MountOption" value is allowed only when SELinuxMount feature gate is enabled.
|
||||
|
||||
If not specified and SELinuxMount feature gate is enabled, "MountOption" is used.
|
||||
If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes
|
||||
and "Recursive" for all other volumes.
|
||||
|
||||
This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
|
||||
|
||||
All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
seLinuxOptions:
|
||||
description: |-
|
||||
The SELinux context to be applied to all containers.
|
||||
If unspecified, the container runtime will allocate a random SELinux context for each
|
||||
container. May also be set in SecurityContext. If set in
|
||||
both SecurityContext and PodSecurityContext, the value specified in SecurityContext
|
||||
takes precedence for that container.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
level:
|
||||
description: Level is SELinux level label that applies
|
||||
to the container.
|
||||
type: string
|
||||
role:
|
||||
description: Role is a SELinux role label that applies
|
||||
to the container.
|
||||
type: string
|
||||
type:
|
||||
description: Type is a SELinux type label that applies
|
||||
to the container.
|
||||
type: string
|
||||
user:
|
||||
description: User is a SELinux user label that applies
|
||||
to the container.
|
||||
type: string
|
||||
type: object
|
||||
seccompProfile:
|
||||
description: |-
|
||||
The seccomp options to use by the containers in this pod.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
properties:
|
||||
localhostProfile:
|
||||
description: |-
|
||||
localhostProfile indicates a profile defined in a file on the node should be used.
|
||||
The profile must be preconfigured on the node to work.
|
||||
Must be a descending path, relative to the kubelet's configured seccomp profile location.
|
||||
Must be set if type is "Localhost". Must NOT be set for any other type.
|
||||
type: string
|
||||
type:
|
||||
description: |-
|
||||
type indicates which kind of seccomp profile will be applied.
|
||||
Valid options are:
|
||||
|
||||
Localhost - a profile defined in a file on the node should be used.
|
||||
RuntimeDefault - the container runtime default profile should be used.
|
||||
Unconfined - no profile should be applied.
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
supplementalGroups:
|
||||
description: |-
|
||||
A list of groups applied to the first process run in each container, in
|
||||
addition to the container's primary GID and fsGroup (if specified). If
|
||||
the SupplementalGroupsPolicy feature is enabled, the
|
||||
supplementalGroupsPolicy field determines whether these are in addition
|
||||
to or instead of any group memberships defined in the container image.
|
||||
If unspecified, no additional groups are added, though group memberships
|
||||
defined in the container image may still be used, depending on the
|
||||
supplementalGroupsPolicy field.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
items:
|
||||
format: int64
|
||||
type: integer
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
supplementalGroupsPolicy:
|
||||
description: |-
|
||||
Defines how supplemental groups of the first container processes are calculated.
|
||||
Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
|
||||
(Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
|
||||
and the container runtime must implement support for this feature.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
type: string
|
||||
sysctls:
|
||||
description: |-
|
||||
Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
|
||||
sysctls (by the container runtime) might fail to launch.
|
||||
Note that this field cannot be set when spec.os.name is windows.
|
||||
items:
|
||||
description: Sysctl defines a kernel parameter to be
|
||||
set
|
||||
properties:
|
||||
name:
|
||||
description: Name of a property to set
|
||||
type: string
|
||||
value:
|
||||
description: Value of a property to set
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
windowsOptions:
|
||||
description: |-
|
||||
The Windows specific settings applied to all containers.
|
||||
If unspecified, the options within a container's SecurityContext will be used.
|
||||
If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
Note that this field cannot be set when spec.os.name is linux.
|
||||
properties:
|
||||
gmsaCredentialSpec:
|
||||
description: |-
|
||||
GMSACredentialSpec is where the GMSA admission webhook
|
||||
(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the
|
||||
GMSA credential spec named by the GMSACredentialSpecName field.
|
||||
type: string
|
||||
gmsaCredentialSpecName:
|
||||
description: GMSACredentialSpecName is the name of
|
||||
the GMSA credential spec to use.
|
||||
type: string
|
||||
hostProcess:
|
||||
description: |-
|
||||
HostProcess determines if a container should be run as a 'Host Process' container.
|
||||
All of a Pod's containers must have the same effective HostProcess value
|
||||
(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).
|
||||
In addition, if HostProcess is true then HostNetwork must also be set to true.
|
||||
type: boolean
|
||||
runAsUserName:
|
||||
description: |-
|
||||
The UserName in Windows to run the entrypoint of the container process.
|
||||
Defaults to the user specified in image metadata if unspecified.
|
||||
May also be set in PodSecurityContext. If set in both SecurityContext and
|
||||
PodSecurityContext, the value specified in SecurityContext takes precedence.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- controlPlane
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -9,19 +9,20 @@ metadata:
|
|||
namespace: supabase-demo
|
||||
spec:
|
||||
envoy:
|
||||
debugging:
|
||||
componentLogLevels:
|
||||
- component: oauth2
|
||||
level: debug
|
||||
disableIPv6: true
|
||||
workloadSpec:
|
||||
replicas: 2
|
||||
apiEndpoint:
|
||||
jwks:
|
||||
name: core-sample-jwt
|
||||
key: jwks.json
|
||||
dashboardEndpoint:
|
||||
tls:
|
||||
cert:
|
||||
secretName: dashboard-tls-cert
|
||||
auth:
|
||||
oauth2:
|
||||
tokenEndpoint: "https://login.microsoftonline.com/f4e80111-1571-477a-b56d-c5fe517676b7/oauth2/token"
|
||||
authorizationEndpoint: "https://login.microsoftonline.com/f4e80111-1571-477a-b56d-c5fe517676b7/oauth2/authorize"
|
||||
openIdIssuer: "https://login.microsoftonline.com/f4e80111-1571-477a-b56d-c5fe517676b7/"
|
||||
clientId: 3528016b-f6e3-49be-8fb3-f9a9a2ab6c3f
|
||||
scopes:
|
||||
- openid
|
||||
|
@ -49,6 +50,6 @@ spec:
|
|||
- gateway-sample-envoy.supabase-demo.svc.cluster.local
|
||||
- localhost:3000
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: selfsigned-issuer
|
||||
kind: ClusterIssuer
|
||||
name: cluster-pki
|
||||
secretName: dashboard-tls-cert
|
||||
|
|
36
config/dev/ca.yaml
Normal file
36
config/dev/ca.yaml
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: supabase-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: cluster-pki-bootstrapper
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: cluster-pki-ca
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
commonName: cluster-pki
|
||||
isCA: true
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: cluster-pki-bootstrapper
|
||||
secretName: cluster-pki-ca-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: supabase-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: cluster-pki
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
ca:
|
||||
secretName: cluster-pki-ca-cert
|
|
@ -44,14 +44,15 @@ metadata:
|
|||
namespace: supabase-demo
|
||||
spec:
|
||||
instances: 1
|
||||
imageName: ghcr.io/supabase/postgres:15.8.1.021
|
||||
postgresUID: 105
|
||||
postgresGID: 106
|
||||
imageName: code.icb4dc0.de/prskr/supabase-operator/postgres:17.2
|
||||
imagePullPolicy: Always
|
||||
postgresUID: 26
|
||||
postgresGID: 102
|
||||
|
||||
bootstrap:
|
||||
initdb:
|
||||
database: app
|
||||
owner: setup
|
||||
owner: supabase_admin
|
||||
postInitSQL:
|
||||
- drop publication if exists supabase_realtime;
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
|
@ -25,6 +26,8 @@ spec:
|
|||
# will be used by Supabase Auth to redirect users after login
|
||||
siteUrl: http://localhost:3000/
|
||||
database:
|
||||
# this field is write-only, it can be used to configure the DSN without having to create the secret manually
|
||||
# dsn: postgresql://supabase_admin:1n1t-R00t!@cluster-example-rw.supabase-demo:5432/app
|
||||
dsnSecretRef:
|
||||
name: supabase-demo-credentials
|
||||
key: url
|
||||
|
|
|
@ -2,12 +2,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- https://github.com/cert-manager/cert-manager/releases/download/v1.16.3/cert-manager.yaml
|
||||
- https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yaml
|
||||
- https://github.com/cloudnative-pg/cloudnative-pg/releases/download/v1.25.0/cnpg-1.25.0.yaml
|
||||
- ca.yaml
|
||||
- namespace.yaml
|
||||
- cnpg-cluster.yaml
|
||||
- minio.yaml
|
||||
- ../default
|
||||
- studio-plaintext-users.yaml
|
||||
- studio-credentials-secret.yaml
|
||||
- core.yaml
|
||||
- apigateway.yaml
|
||||
|
@ -23,3 +25,6 @@ patches:
|
|||
target:
|
||||
kind: Deployment
|
||||
labelSelector: app.kubernetes.io/name=control-plane
|
||||
|
||||
configurations:
|
||||
- kustomizeconfig/cnpg-cluster.yaml
|
||||
|
|
4
config/dev/kustomizeconfig/cnpg-cluster.yaml
Normal file
4
config/dev/kustomizeconfig/cnpg-cluster.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
images:
|
||||
- kind: Cluster
|
||||
group: postgresql.cnpg.io
|
||||
path: spec/imageName
|
|
@ -25,7 +25,7 @@ spec:
|
|||
bucket: test
|
||||
credentialsSecretRef:
|
||||
secretName: storage-s3-credentials
|
||||
s3Protocol: {}
|
||||
s3: {}
|
||||
db:
|
||||
host: cluster-example-rw.supabase-demo.svc
|
||||
dbName: app
|
||||
|
|
8
config/dev/studio-plaintext-users.yaml
Normal file
8
config/dev/studio-plaintext-users.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: studio-sample-basic-auth
|
||||
namespace: supabase-demo
|
||||
stringData:
|
||||
ted: not_admin
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
apiVersion: supabase.k8s.icb4dc0.de/v1alpha1
|
||||
kind: APIGateway
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: supabase-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: gateway-sample
|
||||
spec:
|
||||
apiEndpoint:
|
||||
jwks:
|
||||
# will be created by Core resource operator if not present
|
||||
# just make sure the secret name is either based on the name of the core resource or explicitly set
|
||||
name: core-sample-jwt
|
||||
key: jwks.json
|
||||
dashboardEndpoint:
|
||||
auth:
|
||||
basic:
|
||||
usersInline:
|
||||
# admin:admin
|
||||
- admin:{SHA}0DPiKuNIrrVmD8IUCuw1hQxNqZc=
|
||||
plaintextUsersSecretRef: studio-sample-basic-auth
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: studio-sample-basic-auth
|
||||
namespace: supabase-demo
|
||||
stringData:
|
||||
ted: not_admin
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
apiVersion: supabase.k8s.icb4dc0.de/v1alpha1
|
||||
kind: APIGateway
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: supabase-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: gateway-sample
|
||||
spec:
|
||||
apiEndpoint:
|
||||
jwks:
|
||||
# will be created by Core resource operator if not present
|
||||
# just make sure the secret name is either based on the name of the core resource or explicitly set
|
||||
name: core-sample-jwt
|
||||
key: jwks.json
|
||||
dashboardEndpoint:
|
||||
auth:
|
||||
oauth2:
|
||||
openIdIssuer: "https://idp.your-domain.com/"
|
||||
clientId: "<your-client-id>"
|
||||
# if not set, 'user' will be used
|
||||
scopes:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
clientSecretRef:
|
||||
name: studio-sample-oauth2
|
||||
key: clientSecret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: studio-sample-oauth2
|
||||
namespace: supabase-demo
|
||||
stringData:
|
||||
clientSecret: "<your-client-secret>"
|
|
@ -15,7 +15,7 @@ spec:
|
|||
bucket: test
|
||||
credentialsSecretRef:
|
||||
secretName: storage-s3-credentials
|
||||
s3Protocol: {}
|
||||
s3: {}
|
||||
db:
|
||||
host: cluster-example-rw.supabase-demo.svc
|
||||
dbName: app
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
apiVersion: ctlptl.dev/v1alpha1
|
||||
kind: Registry
|
||||
name: ctlptl-registry
|
||||
name: supabase-operator-registry
|
||||
port: 5005
|
||||
---
|
||||
apiVersion: ctlptl.dev/v1alpha1
|
||||
kind: Cluster
|
||||
product: kind
|
||||
registry: ctlptl-registry
|
||||
registry: supabase-operator-registry
|
||||
kindV1Alpha4Cluster:
|
||||
name: supabase-operator-debug
|
||||
networking:
|
||||
ipFamily: dual
|
||||
|
|
|
@ -151,7 +151,7 @@ _Appears in:_
|
|||
| `disableSignup` _boolean_ | | | |
|
||||
| `anonymousUsersEnabled` _boolean_ | | | |
|
||||
| `providers` _[AuthProviders](#authproviders)_ | | | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | | | |
|
||||
| `workloadTemplate` _[WorkloadSpec](#workloadspec)_ | | | |
|
||||
| `emailSignupDisabled` _boolean_ | | | |
|
||||
|
||||
|
||||
|
@ -185,7 +185,7 @@ _Appears in:_
|
|||
|
||||
|
||||
_Appears in:_
|
||||
- [WorkloadTemplate](#workloadtemplate)
|
||||
- [WorkloadSpec](#workloadspec)
|
||||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -331,8 +331,8 @@ _Appears in:_
|
|||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `oauth2` _[DashboardOAuth2Spec](#dashboardoauth2spec)_ | | | |
|
||||
| `basic` _[DashboardBasicAuthSpec](#dashboardbasicauthspec)_ | | | |
|
||||
| `oauth2` _[DashboardOAuth2Spec](#dashboardoauth2spec)_ | OAuth2 - configure oauth2 authentication for the dashhboard listener<br />if configured, will be preferred over Basic authentication configuration<br />effectively disabling basic auth | | |
|
||||
| `basic` _[DashboardBasicAuthSpec](#dashboardbasicauthspec)_ | Basic - HTTP basic auth configuration, this should only be used in exceptions<br />e.g. during evaluations or for local development<br />only used if no other authentication is configured | | |
|
||||
|
||||
|
||||
|
||||
|
@ -348,6 +348,10 @@ _Appears in:_
|
|||
_Appears in:_
|
||||
- [DashboardAuthSpec](#dashboardauthspec)
|
||||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `usersInline` _string array_ | UsersInline - [htpasswd format](https://httpd.apache.org/docs/2.4/programs/htpasswd.html) | | items:Pattern: ^[\w_.]+:\\{SHA\\}[A-z0-9]+=*$ <br /> |
|
||||
| `plaintextUsersSecretRef` _string_ | PlaintextUsersSecretRef - name of a secret that contains plaintext credentials in key-value form<br />if not empty, credentials will be merged with inline users | | |
|
||||
|
||||
|
||||
#### DashboardDbSpec
|
||||
|
@ -417,6 +421,7 @@ _Appears in:_
|
|||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `openIdIssuer` _string_ | OpenIDIssuer - if set the defaulter will fetch the discovery document and fill<br />TokenEndpoint and AuthorizationEndpoint based on the discovery document | | |
|
||||
| `tokenEndpoint` _string_ | TokenEndpoint - endpoint where Envoy will retrieve the OAuth2 access and identity token from | | |
|
||||
| `authorizationEndpoint` _string_ | AuthorizationEndpoint - endpoint where the user will be redirected to authenticate | | |
|
||||
| `clientId` _string_ | ClientID - client ID to authenticate with the OAuth2 provider | | |
|
||||
|
@ -513,7 +518,7 @@ _Appears in:_
|
|||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `appliedMigrations` _[MigrationStatus](#migrationstatus)_ | | | |
|
||||
| `migrationConditions` _[MigrationScriptCondition](#migrationscriptcondition) array_ | | | |
|
||||
| `roles` _object (keys:string, values:integer array)_ | | | |
|
||||
|
||||
|
||||
|
@ -655,7 +660,7 @@ _Appears in:_
|
|||
| --- | --- | --- | --- |
|
||||
| `nodeName` _string_ | NodeName - identifies the Envoy cluster within the current namespace<br />if not set, the name of the APIGateway resource will be used<br />The primary use case is to make the assignment of multiple supabase instances in a single namespace explicit. | | |
|
||||
| `controlPlane` _[ControlPlaneSpec](#controlplanespec)_ | ControlPlane - configure the control plane where Envoy will retrieve its configuration from | | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the Envoy deployment | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the Envoy deployment | | |
|
||||
| `disableIPv6` _boolean_ | DisableIPv6 - disable IPv6 for the Envoy instance<br />this will force Envoy to use IPv4 for upstream hosts (mostly for the OAuth2 token endpoint) | | |
|
||||
| `debugging` _[EnvoyDebuggingOptions](#envoydebuggingoptions)_ | | | |
|
||||
|
||||
|
@ -726,7 +731,7 @@ _Appears in:_
|
|||
| --- | --- | --- | --- |
|
||||
| `enable` _boolean_ | Enable - whether to deploy the image proxy or not | | |
|
||||
| `enableWebPDetection` _boolean_ | | | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the image proxy workload | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the image proxy workload | | |
|
||||
|
||||
|
||||
#### ImageSpec
|
||||
|
@ -768,9 +773,11 @@ _Appears in:_
|
|||
| `serviceKey` _string_ | ServiceKey - key in secret where to read the service JWT from | service_key | |
|
||||
|
||||
|
||||
#### MigrationStatus
|
||||
|
||||
_Underlying type:_ _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_
|
||||
|
||||
#### MigrationScriptCondition
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -779,6 +786,14 @@ _Underlying type:_ _[Time](https://kubernetes.io/docs/reference/generated/kubern
|
|||
_Appears in:_
|
||||
- [DatabaseStatus](#databasestatus)
|
||||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` _string_ | Name - file name of the migration script | | |
|
||||
| `hash` _integer array_ | Hash - SHA256 hash of the script when it was last successfully applied | | |
|
||||
| `lastProbeTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_ | LastProbeTime - last time the operator tried to execute the migration script | | |
|
||||
| `lastTransitionTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_ | LastTransitionTime - last time the condition transitioned from one status to another | | |
|
||||
| `reason` _string_ | Reason - one-word, CamcelCase reason for the condition's last transition | | |
|
||||
| `message` _string_ | Message - human-readable message indicating details about the last transition | | |
|
||||
|
||||
|
||||
#### OAuthProvider
|
||||
|
@ -813,7 +828,7 @@ _Appears in:_
|
|||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the pg-meta deployment | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the pg-meta deployment | | |
|
||||
|
||||
|
||||
#### PhoneAuthProvider
|
||||
|
@ -849,7 +864,7 @@ _Appears in:_
|
|||
| `extraSearchPath` _string array_ | ExtraSearchPath - Extra schemas to add to the search_path of every request.<br />These schemas tables, views and functions don’t get API endpoints, they can only be referred from the database objects inside your db-schemas. | [public extensions] | |
|
||||
| `anonRole` _string_ | AnonRole - name of the anon role | anon | |
|
||||
| `maxRows` _integer_ | MaxRows - maximum number of rows PostgREST will load at a time | 1000 | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the PostgREST workload | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadSpec - customize the PostgREST workload | | |
|
||||
|
||||
|
||||
#### S3BackendSpec
|
||||
|
@ -984,7 +999,7 @@ _Appears in:_
|
|||
| `db` _[StorageApiDbSpec](#storageapidbspec)_ | DBSpec - Configure access to the Postgres database<br />In most cases this will reference the supabase-storage-admin credentials secret provided by the Core resource | | |
|
||||
| `s3` _[S3ProtocolSpec](#s3protocolspec)_ | S3Protocol - Configure S3 access to the Storage API allowing clients to use any S3 client | | |
|
||||
| `uploadTemp` _[UploadTempSpec](#uploadtempspec)_ | UploadTemp - configure the emptyDir for storing intermediate files during uploads | | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the Storage API workload | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the Storage API workload | | |
|
||||
|
||||
|
||||
#### StorageList
|
||||
|
@ -1038,7 +1053,7 @@ _Appears in:_
|
|||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `jwt` _[JwtSpec](#jwtspec)_ | | | |
|
||||
| `workloadTemplate` _[WorkloadTemplate](#workloadtemplate)_ | WorkloadTemplate - customize the studio deployment | | |
|
||||
| `workloadSpec` _[WorkloadSpec](#workloadspec)_ | WorkloadTemplate - customize the studio deployment | | |
|
||||
| `gatewayServiceSelector` _object (keys:string, values:string)_ | GatewayServiceSelector - selector to find the service for the API gateway<br />Required to configure the API URL in the studio deployment<br />If you don't run multiple APIGateway instances in the same namespaces, the default will be fine | \{ app.kubernetes.io/component:api-gateway app.kubernetes.io/name:envoy \} | |
|
||||
| `externalUrl` _string_ | APIExternalURL is referring to the URL where Supabase API will be available<br />Typically this is the ingress of the API gateway | | |
|
||||
|
||||
|
@ -1079,7 +1094,7 @@ _Appears in:_
|
|||
| `sizeLimit` _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#quantity-resource-api)_ | | | |
|
||||
|
||||
|
||||
#### WorkloadTemplate
|
||||
#### WorkloadSpec
|
||||
|
||||
|
||||
|
||||
|
@ -1101,7 +1116,7 @@ _Appears in:_
|
|||
| `replicas` _integer_ | | | |
|
||||
| `securityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ | | | |
|
||||
| `additionalLabels` _object (keys:string, values:string)_ | | | |
|
||||
| `workload` _[ContainerTemplate](#containertemplate)_ | Workload - customize the container template of the workload | | |
|
||||
| `container` _[ContainerTemplate](#containertemplate)_ | ContainerSpec - customize the container template of the workload | | |
|
||||
| `additionalVolumes` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volume-v1-core) array_ | | | |
|
||||
|
||||
|
||||
|
|
239
go.mod
239
go.mod
|
@ -1,6 +1,8 @@
|
|||
module code.icb4dc0.de/prskr/supabase-operator
|
||||
|
||||
go 1.23.5
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
github.com/alecthomas/kong v1.7.0
|
||||
|
@ -12,10 +14,11 @@ require (
|
|||
github.com/magefile/mage v1.15.0
|
||||
github.com/onsi/ginkgo/v2 v2.22.2
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
|
||||
google.golang.org/grpc v1.70.0
|
||||
google.golang.org/protobuf v1.36.4
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.32.1
|
||||
k8s.io/apimachinery v0.32.1
|
||||
|
@ -23,67 +26,254 @@ require (
|
|||
sigs.k8s.io/controller-runtime v0.20.1
|
||||
)
|
||||
|
||||
tool (
|
||||
github.com/elastic/crd-ref-docs
|
||||
github.com/golangci/golangci-lint/v2/cmd/golangci-lint
|
||||
gotest.tools/gotestsum
|
||||
mvdan.cc/gofumpt
|
||||
sigs.k8s.io/controller-runtime/tools/setup-envtest
|
||||
sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
sigs.k8s.io/kustomize/kustomize/v5
|
||||
)
|
||||
|
||||
require (
|
||||
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
|
||||
4d63.com/gochecknoglobals v0.2.2 // indirect
|
||||
cel.dev/expr v0.19.2 // indirect
|
||||
github.com/4meepo/tagalign v1.4.2 // indirect
|
||||
github.com/Abirdcfly/dupword v0.1.3 // indirect
|
||||
github.com/Antonboom/errname v1.1.0 // indirect
|
||||
github.com/Antonboom/nilnil v1.1.0 // indirect
|
||||
github.com/Antonboom/testifylint v1.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/Crocmagnon/fatcontext v0.7.1 // indirect
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
|
||||
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
|
||||
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
|
||||
github.com/alexkohler/prealloc v1.0.0 // indirect
|
||||
github.com/alingse/asasalint v0.0.11 // indirect
|
||||
github.com/alingse/nilnesserr v0.1.2 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/ashanbrown/forbidigo v1.6.0 // indirect
|
||||
github.com/ashanbrown/makezero v1.2.0 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bitfield/gotestdox v0.2.2 // indirect
|
||||
github.com/bkielbasa/cyclop v1.2.3 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
||||
github.com/bombsimon/wsl/v4 v4.6.0 // indirect
|
||||
github.com/breml/bidichk v0.3.3 // indirect
|
||||
github.com/breml/errchkjson v0.4.1 // indirect
|
||||
github.com/butuzov/ireturn v0.3.1 // indirect
|
||||
github.com/butuzov/mirror v1.3.0 // indirect
|
||||
github.com/catenacyber/perfsprint v0.9.1 // indirect
|
||||
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charithe/durationcheck v0.0.10 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/ckaznocha/intrange v0.3.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
||||
github.com/daixiang0/gci v0.13.6 // indirect
|
||||
github.com/dave/dst v0.27.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
||||
github.com/dnephin/pflag v1.0.7 // indirect
|
||||
github.com/elastic/crd-ref-docs v0.1.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/ettle/strcase v0.2.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/firefart/nonamedreturns v1.0.5 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||
github.com/ghostiam/protogetter v0.3.12 // indirect
|
||||
github.com/go-critic/go-critic v0.13.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/go-toolsmith/astcast v1.1.0 // indirect
|
||||
github.com/go-toolsmith/astcopy v1.1.0 // indirect
|
||||
github.com/go-toolsmith/astequal v1.2.0 // indirect
|
||||
github.com/go-toolsmith/astfmt v1.1.0 // indirect
|
||||
github.com/go-toolsmith/astp v1.1.0 // indirect
|
||||
github.com/go-toolsmith/strparse v1.1.0 // indirect
|
||||
github.com/go-toolsmith/typep v1.1.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
|
||||
github.com/gobuffalo/flect v1.0.3 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.11.3 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
|
||||
github.com/golangci/go-printf-func-name v0.1.0 // indirect
|
||||
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
|
||||
github.com/golangci/golangci-lint/v2 v2.0.1 // indirect
|
||||
github.com/golangci/golines v0.0.0-20250217232252-b35a6149b587 // indirect
|
||||
github.com/golangci/misspell v0.6.0 // indirect
|
||||
github.com/golangci/plugin-module-register v0.1.1 // indirect
|
||||
github.com/golangci/revgrep v0.8.0 // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/cel-go v0.22.0 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
||||
github.com/gostaticanalysis/comment v1.5.0 // indirect
|
||||
github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect
|
||||
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jgautheron/goconst v1.7.1 // indirect
|
||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||
github.com/jjti/go-spancheck v0.6.4 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/julz/importas v0.2.0 // indirect
|
||||
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
|
||||
github.com/kisielk/errcheck v1.9.0 // indirect
|
||||
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/kulti/thelper v0.6.3 // indirect
|
||||
github.com/kunwardeep/paralleltest v1.0.12 // indirect
|
||||
github.com/lasiar/canonicalheader v1.1.2 // indirect
|
||||
github.com/ldez/exptostd v0.4.2 // indirect
|
||||
github.com/ldez/gomoddirectives v0.6.1 // indirect
|
||||
github.com/ldez/grignotin v0.9.0 // indirect
|
||||
github.com/ldez/tagliatelle v0.7.1 // indirect
|
||||
github.com/ldez/usetesting v0.4.2 // indirect
|
||||
github.com/leonklingele/grouper v1.1.2 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httprc v1.0.6 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/macabu/inamedparam v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/maratori/testableexamples v1.0.0 // indirect
|
||||
github.com/maratori/testpackage v1.1.1 // indirect
|
||||
github.com/matoous/godox v1.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mgechev/revive v1.7.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/moricho/tparallel v0.3.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nakabonne/nestif v0.3.1 // indirect
|
||||
github.com/nishanths/exhaustive v0.12.0 // indirect
|
||||
github.com/nishanths/predeclared v0.2.2 // indirect
|
||||
github.com/nunnatsa/ginkgolinter v0.19 |