diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49cfd96..19eff4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,7 @@ jobs: name: run tests uses: okdp/gh-workflows/.github/workflows/makefile-run-template.yml@v1 with: - go_version: "1.23" + go_version: "1.24" command: "make test" docker_test: diff --git a/.gitignore b/.gitignore index fc1f73b..38a5fe6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ tmp/ .go-cache/ .bin/ package-lock.json +*.tgz diff --git a/.local/application-local.yaml b/.local/application-local.yaml index 627a196..0e35c2a 100644 --- a/.local/application-local.yaml +++ b/.local/application-local.yaml @@ -82,25 +82,75 @@ swagger: security: - oauth2: [openid, email, profile, roles] -kad: - - id: sandbox - name: Sandbox de idir - apiUrl: https://host.docker.internal:6553 - authBearer: 4Ys3brdqnD5LVjf6hLcQsSQbHWLh5asJ - insecureSkipVerify: true - - id: sandbox2 - name: Sandbox2 de idir - apiUrl: https://host.docker.internal:6553 - authBearer: 4Ys3brdqnD5LVjf6hLcQsSQbHWLh5asJ - insecureSkipVerify: true - - id: sandbox3 - name: Sandbox3 de idir - apiUrl: https://host.docker.internal:6553 - authBearer: 4Ys3brdqnD5LVjf6hLcQsSQbHWLh5asJ - insecureSkipVerify: true - - id: sandbox4 - name: Sandbox4 de idir - apiUrl: https://host.docker.internal:6553 - authBearer: 4Ys3brdqnD5LVjf6hLcQsSQbHWLh5asJ - insecureSkipVerify: true + +# packages: +# - repo: quay.io/kubocd/packages +# name: redis +# versions: [""] +# - repo: quay.io/kubocd/packages +# name: minio +# versions: [""] +# - repo: quay.io/kubocd/packages +# name: cnpg +# versions: [""] + +catalog: + - id: storage + name: Storage catalog + description: My Storage packages + repoUrl: quay.io/kubocd/packages + ### public registry, no credentials needed + #credentials: + # robotAccountName: $(OCI_USERNAME) + # robotAccountToken: $(OCI_PASSWORD) + # dockerconfigjson: $(DOCKER_CONFIG_JSON) + packages: + - name: redis + - name: minio + - name: cnpg + + - id: auth + name: Auth catalog + description: My Auth packages + repoUrl: quay.io/kubocd/packages + packages: + - name: openldap + + - id: infra + name: Infra catalog + description: My Infra packages + repoUrl: quay.io/kubocd/packages + packages: + - name: cert-manager + - name: ingress-nginx + - name: metallb + + - id: stack + name: Stack catalog + description: My Stack packages + repoUrl: quay.io/kubocd/packages + packages: + - name: podinfo + +clusters: + - id: kubo2 + name: My k8s cluster 1 + env: dev + auth: + # inCluster: true + kubeconfig: + apiServer: https://host.docker.internal:56660 + path: /tmp/.kube/config + # When not provided, use current context + # context: kind-kind-okdp-sandbox + insecureSkipTlsVerify: true + # certificate: + # apiServer: https://k8s-api-server-url:6443 + # clientKey: /path/to/client-key.pem + # clientCert: /path/to/client-cert.pem + # caCert: /path/to/ca-cert.pem + # bearer: + # apiServer: https://k8s-api-server-url:6443 + # bearerToken: $(BEARER_TOKEN) + diff --git a/.local/authz-policy.csv b/.local/authz-policy.csv index 1efc35a..d93e87b 100644 --- a/.local/authz-policy.csv +++ b/.local/authz-policy.csv @@ -1,14 +1,10 @@ p, role:viewers, /api/v1/users/myprofile, * -p, role:viewers, /api/v1/kad, * -p, role:viewers, /api/v1/kad/*/services, * -p, role:viewers, /api/v1/kad/*/catalog, * -p, role:viewers, /api/v1/kad/*/catalog/*, * -p, role:viewers, /api/v1/kad/*/componentreleases, * -p, role:viewers, /api/v1/kad/*/componentreleases/*, * -p, role:viewers, /api/v1/kad/*/templatereleases, * -p, role:viewers, /api/v1/kad/*/templatereleases/*, * -p, role:viewers, /api/v1/kad/*/components, * -p, role:viewers, /api/v1/kad/*/components/*, * +p, role:viewers, /api/v1/catalogs, * +p, role:viewers, /api/v1/catalogs/*, * + +p, role:viewers, /api/v1/clusters, * +p, role:viewers, /api/v1/clusters/*/gitrepos, * +p, role:viewers, /api/v1/clusters/*/gitrepos/*, * g, role:admins, role:developers g, role:developers, role:viewers diff --git a/.local/keycloak.sh b/.local/keycloak.sh index 42265b2..5289caa 100644 --- a/.local/keycloak.sh +++ b/.local/keycloak.sh @@ -1,5 +1,28 @@ #!/bin/bash +CONFIDENTIAL_CLIENT='confidential-oidc-client' +PUBLIC_CLIENT='public-oidc-client' +WEB_ORIGINS='["*"]' +REDIRECT_URIS='[ + "http://localhost:8090/oauth2/callback", + "http://localhost:8092/oauth2-redirect.html", + "http://localhost:4200/index.html", + "http://localhost:4200/silent-refresh.html", + "http://localhost:4200/home", + "http://okdp-ui.okdp.sandbox/index.html", + "https://okdp-ui.okdp.sandbox/index.html", + "http://okdp-server.okdp.sandbox/swagger/oauth2-redirect.html", + "https://okdp-server.okdp.sandbox/swagger/oauth2-redirect.html" +]' + +get_client_id() { + local client_name=$1 + /opt/keycloak/bin/kcadm.sh get clients -r master --fields id,clientId \ + | grep -B1 "\"clientId\" : \"${client_name}\"" \ + | grep '"id"' \ + | sed -E 's/.*"id" : "([^"]+)".*/\1/' +} + echo "Creating users, roles and clients ..." # Connect to kecloak @@ -35,16 +58,26 @@ echo "Creating users, roles and clients ..." /opt/keycloak/bin/kcadm.sh add-roles -r master --uusername adm1 --rolename admins # Create OAuth2 clients -/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=public-oidc-client -s name=public-oidc-client -s publicClient=true \ - -s 'redirectUris=["http://localhost:8090/oauth2/callback", "http://localhost:8092/oauth2-redirect.html", "http://localhost:4200/index.html", "http://localhost:4200/silent-refresh.html", "http://localhost:4200/home"]' \ - -s 'webOrigins=["http://localhost:8090", "http://localhost:8092", "http://localhost:4200"]' -/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=confidential-oidc-client -s name=confidential-oidc-client -s 'secret=secret1' \ - -s 'redirectUris=["http://localhost:8090/oauth2/callback", "http://localhost:8092/oauth2-redirect.html", "http://localhost:4200/index.html", "http://localhost:4200/silent-refresh.html", "http://localhost:4200/home"]' \ - -s 'webOrigins=["http://localhost:8090", "http://localhost:8092", "http://localhost:4200"]' +/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=$PUBLIC_CLIENT -s name=$PUBLIC_CLIENT -s publicClient=true \ + -s "redirectUris=${REDIRECT_URIS}" \ + -s "webOrigins=${WEB_ORIGINS}" +/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=$CONFIDENTIAL_CLIENT -s name=$CONFIDENTIAL_CLIENT -s 'secret=secret1' \ + -s "redirectUris=${REDIRECT_URIS}" \ + -s "webOrigins=${WEB_ORIGINS}" + +CONF_CLIENT_ID=$(get_client_id "$CONFIDENTIAL_CLIENT") +/opt/keycloak/bin/kcadm.sh update clients/$CONF_CLIENT_ID -r master \ + -s "redirectUris=${REDIRECT_URIS}" \ + -s "webOrigins=${WEB_ORIGINS}" + +PUB_CLIENT_ID=$(get_client_id "$PUBLIC_CLIENT") +/opt/keycloak/bin/kcadm.sh update clients/$PUB_CLIENT_ID -r master \ + -s "redirectUris=${REDIRECT_URIS}" \ + -s "webOrigins=${WEB_ORIGINS}" # Update access token lifetime -echo "Update access token lifetime to 1H" -/opt/keycloak/bin/kcadm.sh update realms/master -s accessTokenLifespan=3600 +echo "Update access token lifetime to 8H" +/opt/keycloak/bin/kcadm.sh update realms/master -s accessTokenLifespan=28800 echo "Users, roles and clients created successfuly" exit 0 diff --git a/Dockerfile b/Dockerfile index 670f224..9719b05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG GO_VERSION=1.23 +ARG GO_VERSION=1.24 FROM golang:${GO_VERSION} AS go-build @@ -24,7 +24,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ LDFLAGS=${LDFLAGS##-X localbuild=true} GIT_COMMIT=$GIT_COMMIT \ CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -a -o okdp-server main.go -FROM alpine:3.20.3 +FROM alpine:3.21.3 RUN apk --no-cache add ca-certificates && update-ca-certificates diff --git a/Makefile b/Makefile index e558c13..5193316 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,13 @@ test: compile gotest build: test gobuild run: test gorun rundev: generate gocompile gotest gobuild gorun -update: build goupdate +update: build goupdate build .PHONY: tools tools: go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.4.1 go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 - go install golang.org/x/tools/cmd/goimports@v0.28.0 + go install golang.org/x/tools/cmd/goimports@v0.33.0 .PHONY: gogenerate gogenerate: @@ -81,6 +81,6 @@ gorun: .PHONY: goupdate goupdate: - go get -u all + go get -u ./... go mod tidy diff --git a/README.md b/README.md index 0e84d1d..0714060 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,9 @@ Manually add the following entry in /etc/hosts 127.0.0.1 keycloak ``` -Forward kad webserver to localhost: - -```shell -kubectl port-forward svc/kad-webserver 6553:6553 -``` - ### Start +Start docker compose using your robot account token to access private registries: ```shell docker-compose rm -f docker-compose up --build @@ -39,61 +34,6 @@ adm1/user view1/user -```shell - -kadcli git remove projectA-1.yaml -m "Test remove" -n "idir" --insecureSkipVerify -kadcli git add -m "test add" -n"idir" projectA-1.yaml --insecureSkipVerify - -curl -H "Authorization: Bearer HEDG296X4XjnjETBJ1HGEUEqQbn3pNaD" -X PUT 'https://kad.ingress.kind.local/api/git/v1/mycluster/deployments/minio3.yaml' -F kadfile=@.tmp/z.tmp/curl/minio3.yaml -F commit-message='A commit Message' -F committer-name='Serge' -F committer-email='serge@example.com' -k - - -kadcli kad componentReleases apply --insecureSkipVerify minio1 -kadcli kad componentReleases apply --insecureSkipVerify _all_ - -``` - - -http://localhost:8092/#/componentreleases/CreateOrUpdateComponentRelease -``` -{ - "comment": "Create minio deployment example", - "gitRepoFolder": "deployments", - "componentReleases": [ - { - "name": "minio3", - "component": { - "name": "minio", - "version": "1.0.0", - "protected": true, - "config": { - "install": { - "createNamespace": true - } - }, - "parameters": { - "ingressName": "minio3", - "ldap": "openldap" - }, - "parameterFiles": [ - { - "document": "minio-flavor-small" - }, - { - "document": "data1-minio-parameters", - "unwrap": "minio" - } - ] - }, - "namespace": "minio3", - "dependsOn": [ - "ldapLocalServer" - ] - } - ] -} -``` - - # Helm ``` @@ -101,12 +41,15 @@ docker build -t quay.io/okdp/okdp-server:0.1.0-snapshot . docker push quay.io/okdp/okdp-server:0.1.0-snapshot helm package ./helm/okdp-server -helm push okdp-server-0.1.0-snapshot.tgz oci://quay.io/okdp/charts +helm push okdp-server-0.2.0-snapshot.tgz oci://quay.io/okdp/charts -helm pull oci://quay.io/okdp/charts/swagger-ui --version 0.1.0 --destination helm/okdp-server/charts +helm pull oci://quay.io/okdp/charts/swagger-ui --version 0.2.0 --destination helm/okdp-server/charts helm upgrade --install okdp-server \ --namespace okdp-server \ --create-namespace helm/okdp-server \ --values helm/okdp-server/values.keycloak.yaml ``` + +Swagger UI: https://okdp-server.okdp.sandbox/swagger/ + diff --git a/api/openapi/v3/_api/kad/kad-server.go b/api/openapi/v3/_api/admin/admin-server.go similarity index 56% rename from api/openapi/v3/_api/kad/kad-server.go rename to api/openapi/v3/_api/admin/admin-server.go index fccb608..e2b0779 100644 --- a/api/openapi/v3/_api/kad/kad-server.go +++ b/api/openapi/v3/_api/admin/admin-server.go @@ -1,7 +1,7 @@ -// Package _kad provides primitives to interact with the openapi HTTP API. +// Package _admin provides primitives to interact with the openapi HTTP API. // // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. -package _kad +package _admin import ( "fmt" @@ -13,12 +13,9 @@ import ( // ServerInterface represents all server handlers. type ServerInterface interface { - // List all KAD configured instances - // (GET /kad) - ListKadInstances(c *gin.Context) - // Get KAD instance by name - // (GET /kad/{kadInstanceId}) - GetKadInstance(c *gin.Context, kadInstanceId string) + // Get the list of the deployed releases on all namespaces + // (GET /admin/clusters/{clusterId}/releases) + AdminListK8sReleases(c *gin.Context, clusterId string) } // ServerInterfaceWrapper converts contexts to parameters. @@ -30,30 +27,17 @@ type ServerInterfaceWrapper struct { type MiddlewareFunc func(c *gin.Context) -// ListKadInstances operation middleware -func (siw *ServerInterfaceWrapper) ListKadInstances(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.ListKadInstances(c) -} - -// GetKadInstance operation middleware -func (siw *ServerInterfaceWrapper) GetKadInstance(c *gin.Context) { +// AdminListK8sReleases operation middleware +func (siw *ServerInterfaceWrapper) AdminListK8sReleases(c *gin.Context) { var err error - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string + // ------------- Path parameter "clusterId" ------------- + var clusterId string - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) return } @@ -64,7 +48,7 @@ func (siw *ServerInterfaceWrapper) GetKadInstance(c *gin.Context) { } } - siw.Handler.GetKadInstance(c, kadInstanceId) + siw.Handler.AdminListK8sReleases(c, clusterId) } // GinServerOptions provides options for the Gin server. @@ -94,6 +78,5 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options ErrorHandler: errorHandler, } - router.GET(options.BaseURL+"/kad", wrapper.ListKadInstances) - router.GET(options.BaseURL+"/kad/:kadInstanceId", wrapper.GetKadInstance) + router.GET(options.BaseURL+"/admin/clusters/:clusterId/releases", wrapper.AdminListK8sReleases) } diff --git a/api/openapi/v3/_api/catalogs/catalogs-server.go b/api/openapi/v3/_api/catalogs/catalogs-server.go index 3bab79d..4453c75 100644 --- a/api/openapi/v3/_api/catalogs/catalogs-server.go +++ b/api/openapi/v3/_api/catalogs/catalogs-server.go @@ -14,11 +14,26 @@ import ( // ServerInterface represents all server handlers. type ServerInterface interface { // List all catalogs - // (GET /kad/{kadInstanceId}/catalogs) - ListCatalogs(c *gin.Context, kadInstanceId string) - // Get a catalog info by name - // (GET /kad/{kadInstanceId}/catalogs/{name}) - GetCatalog(c *gin.Context, kadInstanceId string, name string) + // (GET /catalogs) + ListCatalogs(c *gin.Context) + // Get a catalog by id + // (GET /catalogs/{catalogId}) + GetCatalog(c *gin.Context, catalogId string) + // Get a list of packages by catalog id + // (GET /catalogs/{catalogId}/packages) + ListPackages(c *gin.Context, catalogId string) + // Get package by catalog id and package name + // (GET /catalogs/{catalogId}/packages/{name}) + GetPackage(c *gin.Context, catalogId string, name string) + // List versions for a specific package + // (GET /catalogs/{catalogId}/packages/{name}/versions) + GetPackageVersions(c *gin.Context, catalogId string, name string) + // Get package definition + // (GET /catalogs/{catalogId}/packages/{name}/versions/{version}) + GetPackageDefinition(c *gin.Context, catalogId string, name string, version string) + // Get package schema (parameters, context, etc) + // (GET /catalogs/{catalogId}/packages/{name}/versions/{version}/schema) + GetPackageSchema(c *gin.Context, catalogId string, name string, version string) } // ServerInterfaceWrapper converts contexts to parameters. @@ -33,14 +48,27 @@ type MiddlewareFunc func(c *gin.Context) // ListCatalogs operation middleware func (siw *ServerInterfaceWrapper) ListCatalogs(c *gin.Context) { + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListCatalogs(c) +} + +// GetCatalog operation middleware +func (siw *ServerInterfaceWrapper) GetCatalog(c *gin.Context) { + var err error - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string + // ------------- Path parameter "catalogId" ------------- + var catalogId string - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) return } @@ -51,20 +79,77 @@ func (siw *ServerInterfaceWrapper) ListCatalogs(c *gin.Context) { } } - siw.Handler.ListCatalogs(c, kadInstanceId) + siw.Handler.GetCatalog(c, catalogId) } -// GetCatalog operation middleware -func (siw *ServerInterfaceWrapper) GetCatalog(c *gin.Context) { +// ListPackages operation middleware +func (siw *ServerInterfaceWrapper) ListPackages(c *gin.Context) { + + var err error + + // ------------- Path parameter "catalogId" ------------- + var catalogId string + + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListPackages(c, catalogId) +} + +// GetPackage operation middleware +func (siw *ServerInterfaceWrapper) GetPackage(c *gin.Context) { + + var err error + + // ------------- Path parameter "catalogId" ------------- + var catalogId string + + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "name" ------------- + var name string + + err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetPackage(c, catalogId, name) +} + +// GetPackageVersions operation middleware +func (siw *ServerInterfaceWrapper) GetPackageVersions(c *gin.Context) { var err error - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string + // ------------- Path parameter "catalogId" ------------- + var catalogId string - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) return } @@ -84,7 +169,91 @@ func (siw *ServerInterfaceWrapper) GetCatalog(c *gin.Context) { } } - siw.Handler.GetCatalog(c, kadInstanceId, name) + siw.Handler.GetPackageVersions(c, catalogId, name) +} + +// GetPackageDefinition operation middleware +func (siw *ServerInterfaceWrapper) GetPackageDefinition(c *gin.Context) { + + var err error + + // ------------- Path parameter "catalogId" ------------- + var catalogId string + + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "name" ------------- + var name string + + err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "version" ------------- + var version string + + err = runtime.BindStyledParameterWithOptions("simple", "version", c.Param("version"), &version, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter version: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetPackageDefinition(c, catalogId, name, version) +} + +// GetPackageSchema operation middleware +func (siw *ServerInterfaceWrapper) GetPackageSchema(c *gin.Context) { + + var err error + + // ------------- Path parameter "catalogId" ------------- + var catalogId string + + err = runtime.BindStyledParameterWithOptions("simple", "catalogId", c.Param("catalogId"), &catalogId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalogId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "name" ------------- + var name string + + err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "version" ------------- + var version string + + err = runtime.BindStyledParameterWithOptions("simple", "version", c.Param("version"), &version, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter version: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetPackageSchema(c, catalogId, name, version) } // GinServerOptions provides options for the Gin server. @@ -114,6 +283,11 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options ErrorHandler: errorHandler, } - router.GET(options.BaseURL+"/kad/:kadInstanceId/catalogs", wrapper.ListCatalogs) - router.GET(options.BaseURL+"/kad/:kadInstanceId/catalogs/:name", wrapper.GetCatalog) + router.GET(options.BaseURL+"/catalogs", wrapper.ListCatalogs) + router.GET(options.BaseURL+"/catalogs/:catalogId", wrapper.GetCatalog) + router.GET(options.BaseURL+"/catalogs/:catalogId/packages", wrapper.ListPackages) + router.GET(options.BaseURL+"/catalogs/:catalogId/packages/:name", wrapper.GetPackage) + router.GET(options.BaseURL+"/catalogs/:catalogId/packages/:name/versions", wrapper.GetPackageVersions) + router.GET(options.BaseURL+"/catalogs/:catalogId/packages/:name/versions/:version", wrapper.GetPackageDefinition) + router.GET(options.BaseURL+"/catalogs/:catalogId/packages/:name/versions/:version/schema", wrapper.GetPackageSchema) } diff --git a/api/openapi/v3/_api/clusters/clusters-server.go b/api/openapi/v3/_api/clusters/clusters-server.go new file mode 100644 index 0000000..fff3bad --- /dev/null +++ b/api/openapi/v3/_api/clusters/clusters-server.go @@ -0,0 +1,164 @@ +// Package _clusters provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package _clusters + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/oapi-codegen/runtime" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // List all kubernetes clusters + // (GET /clusters) + ListClusters(c *gin.Context) + // Get a kubernetes cluster by id + // (GET /clusters/{clusterId}) + GetCluster(c *gin.Context, clusterId string) + // List all kubernetes namespaces + // (GET /clusters/{clusterId}/namespaces) + ListNamespaces(c *gin.Context, clusterId string) + // Get a kubernetes namespace by name + // (GET /clusters/{clusterId}/namespaces/{namespace}) + GetNamespace(c *gin.Context, clusterId string, namespace string) +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +type MiddlewareFunc func(c *gin.Context) + +// ListClusters operation middleware +func (siw *ServerInterfaceWrapper) ListClusters(c *gin.Context) { + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListClusters(c) +} + +// GetCluster operation middleware +func (siw *ServerInterfaceWrapper) GetCluster(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetCluster(c, clusterId) +} + +// ListNamespaces operation middleware +func (siw *ServerInterfaceWrapper) ListNamespaces(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListNamespaces(c, clusterId) +} + +// GetNamespace operation middleware +func (siw *ServerInterfaceWrapper) GetNamespace(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetNamespace(c, clusterId, namespace) +} + +// GinServerOptions provides options for the Gin server. +type GinServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { + errorHandler := options.ErrorHandler + if errorHandler == nil { + errorHandler = func(c *gin.Context, err error, statusCode int) { + c.JSON(statusCode, gin.H{"msg": err.Error()}) + } + } + + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandler: errorHandler, + } + + router.GET(options.BaseURL+"/clusters", wrapper.ListClusters) + router.GET(options.BaseURL+"/clusters/:clusterId", wrapper.GetCluster) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces", wrapper.ListNamespaces) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace", wrapper.GetNamespace) +} diff --git a/api/openapi/v3/_api/componentreleases/componentreleases-server.go b/api/openapi/v3/_api/componentreleases/componentreleases-server.go deleted file mode 100644 index cb3a87f..0000000 --- a/api/openapi/v3/_api/componentreleases/componentreleases-server.go +++ /dev/null @@ -1,229 +0,0 @@ -// Package _componentreleases provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. -package _componentreleases - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/oapi-codegen/runtime" -) - -// ListComponentReleasesParams defines parameters for ListComponentReleases. -type ListComponentReleasesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// GetComponentReleaseParams defines parameters for GetComponentRelease. -type GetComponentReleaseParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// CreateOrUpdateComponentReleaseJSONBody defines parameters for CreateOrUpdateComponentRelease. -type CreateOrUpdateComponentReleaseJSONBody struct { - Comment string `json:"comment"` - ComponentReleases []struct { - Component struct { - // Config Additional configuration - Config *map[string]interface{} `json:"config,omitempty"` - Name string `json:"name"` - ParameterFiles *[]struct { - Document *string `json:"document,omitempty"` - File *string `json:"file,omitempty"` - Unwrap *string `json:"unwrap,omitempty"` - Wrap *string `json:"wrap,omitempty"` - } `json:"parameterFiles,omitempty"` - - // Parameters List of paramters as key/value pairs - Parameters *map[string]interface{} `json:"parameters,omitempty"` - Protected *bool `json:"protected,omitempty"` - Source *struct { - Version string `json:"version"` - } `json:"source,omitempty"` - Suspended *bool `json:"suspended,omitempty"` - - // Values List of values as key/value pairs - Values *map[string]interface{} `json:"values,omitempty"` - Version string `json:"version"` - } `json:"component"` - DependsOn *[]string `json:"dependsOn,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Name string `json:"name"` - Namespace *string `json:"namespace,omitempty"` - Roles *[]string `json:"roles,omitempty"` - } `json:"componentReleases"` - GitRepoFolder string `json:"gitRepoFolder"` -} - -// CreateOrUpdateComponentReleaseJSONRequestBody defines body for CreateOrUpdateComponentRelease for application/json ContentType. -type CreateOrUpdateComponentReleaseJSONRequestBody CreateOrUpdateComponentReleaseJSONBody - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // List all component releases - // (GET /kad/{kadInstanceId}/componentreleases) - ListComponentReleases(c *gin.Context, kadInstanceId string, params ListComponentReleasesParams) - // Get a component release by name - // (GET /kad/{kadInstanceId}/componentreleases/{name}) - GetComponentRelease(c *gin.Context, kadInstanceId string, name string, params GetComponentReleaseParams) - // Create or update a component release - // (PUT /kad/{kadInstanceId}/componentreleases/{name}) - CreateOrUpdateComponentRelease(c *gin.Context, kadInstanceId string, name string) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// ListComponentReleases operation middleware -func (siw *ServerInterfaceWrapper) ListComponentReleases(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params ListComponentReleasesParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.ListComponentReleases(c, kadInstanceId, params) -} - -// GetComponentRelease operation middleware -func (siw *ServerInterfaceWrapper) GetComponentRelease(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // ------------- Path parameter "name" ------------- - var name string - - err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params GetComponentReleaseParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.GetComponentRelease(c, kadInstanceId, name, params) -} - -// CreateOrUpdateComponentRelease operation middleware -func (siw *ServerInterfaceWrapper) CreateOrUpdateComponentRelease(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // ------------- Path parameter "name" ------------- - var name string - - err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.CreateOrUpdateComponentRelease(c, kadInstanceId, name) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.GET(options.BaseURL+"/kad/:kadInstanceId/componentreleases", wrapper.ListComponentReleases) - router.GET(options.BaseURL+"/kad/:kadInstanceId/componentreleases/:name", wrapper.GetComponentRelease) - router.PUT(options.BaseURL+"/kad/:kadInstanceId/componentreleases/:name", wrapper.CreateOrUpdateComponentRelease) -} diff --git a/api/openapi/v3/_api/components/components-server.go b/api/openapi/v3/_api/components/components-server.go deleted file mode 100644 index 29acf8e..0000000 --- a/api/openapi/v3/_api/components/components-server.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package _components provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. -package _components - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/oapi-codegen/runtime" -) - -// ListComponentsParams defines parameters for ListComponents. -type ListComponentsParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// GetComponentsByNameParams defines parameters for GetComponentsByName. -type GetComponentsByNameParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // List all components - // (GET /kad/{kadInstanceId}/components) - ListComponents(c *gin.Context, kadInstanceId string, params ListComponentsParams) - // Get a components by name - // (GET /kad/{kadInstanceId}/components/{name}) - GetComponentsByName(c *gin.Context, kadInstanceId string, name string, params GetComponentsByNameParams) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// ListComponents operation middleware -func (siw *ServerInterfaceWrapper) ListComponents(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params ListComponentsParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.ListComponents(c, kadInstanceId, params) -} - -// GetComponentsByName operation middleware -func (siw *ServerInterfaceWrapper) GetComponentsByName(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // ------------- Path parameter "name" ------------- - var name string - - err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params GetComponentsByNameParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.GetComponentsByName(c, kadInstanceId, name, params) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.GET(options.BaseURL+"/kad/:kadInstanceId/components", wrapper.ListComponents) - router.GET(options.BaseURL+"/kad/:kadInstanceId/components/:name", wrapper.GetComponentsByName) -} diff --git a/api/openapi/v3/_api/k8s/k8s-server.go b/api/openapi/v3/_api/k8s/k8s-server.go new file mode 100644 index 0000000..b736b66 --- /dev/null +++ b/api/openapi/v3/_api/k8s/k8s-server.go @@ -0,0 +1,964 @@ +// Package _k8s provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package _k8s + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/oapi-codegen/runtime" +) + +// Defines values for CreateK8sReleaseJSONBodySpecPackageProvider. +const ( + CreateK8sReleaseJSONBodySpecPackageProviderAws CreateK8sReleaseJSONBodySpecPackageProvider = "aws" + CreateK8sReleaseJSONBodySpecPackageProviderAzure CreateK8sReleaseJSONBodySpecPackageProvider = "azure" + CreateK8sReleaseJSONBodySpecPackageProviderGcp CreateK8sReleaseJSONBodySpecPackageProvider = "gcp" + CreateK8sReleaseJSONBodySpecPackageProviderGeneric CreateK8sReleaseJSONBodySpecPackageProvider = "generic" +) + +// Defines values for CreateK8sReleaseJSONBodySpecPackageVerifyProvider. +const ( + CreateK8sReleaseJSONBodySpecPackageVerifyProviderCosign CreateK8sReleaseJSONBodySpecPackageVerifyProvider = "cosign" + CreateK8sReleaseJSONBodySpecPackageVerifyProviderNotation CreateK8sReleaseJSONBodySpecPackageVerifyProvider = "notation" +) + +// Defines values for UpdateK8sReleaseJSONBodySpecPackageProvider. +const ( + UpdateK8sReleaseJSONBodySpecPackageProviderAws UpdateK8sReleaseJSONBodySpecPackageProvider = "aws" + UpdateK8sReleaseJSONBodySpecPackageProviderAzure UpdateK8sReleaseJSONBodySpecPackageProvider = "azure" + UpdateK8sReleaseJSONBodySpecPackageProviderGcp UpdateK8sReleaseJSONBodySpecPackageProvider = "gcp" + UpdateK8sReleaseJSONBodySpecPackageProviderGeneric UpdateK8sReleaseJSONBodySpecPackageProvider = "generic" +) + +// Defines values for UpdateK8sReleaseJSONBodySpecPackageVerifyProvider. +const ( + UpdateK8sReleaseJSONBodySpecPackageVerifyProviderCosign UpdateK8sReleaseJSONBodySpecPackageVerifyProvider = "cosign" + UpdateK8sReleaseJSONBodySpecPackageVerifyProviderNotation UpdateK8sReleaseJSONBodySpecPackageVerifyProvider = "notation" +) + +// CreateK8sReleaseJSONBody defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *CreateK8sReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider CreateK8sReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` +} + +// CreateK8sReleaseParams defines parameters for CreateK8sRelease. +type CreateK8sReleaseParams struct { + // DryRun If true, performs a server-side dry run without persisting the resource + DryRun *bool `form:"dryRun,omitempty" json:"dryRun,omitempty"` +} + +// CreateK8sReleaseJSONBodySpecPackageProvider defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBodySpecPackageProvider string + +// CreateK8sReleaseJSONBodySpecPackageVerifyProvider defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBodySpecPackageVerifyProvider string + +// UpdateK8sReleaseJSONBody defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *UpdateK8sReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider UpdateK8sReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` +} + +// UpdateK8sReleaseParams defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseParams struct { + // DryRun If true, performs a server-side dry run without persisting the resource + DryRun *bool `form:"dryRun,omitempty" json:"dryRun,omitempty"` +} + +// UpdateK8sReleaseJSONBodySpecPackageProvider defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBodySpecPackageProvider string + +// UpdateK8sReleaseJSONBodySpecPackageVerifyProvider defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBodySpecPackageVerifyProvider string + +// CreateK8sReleaseJSONRequestBody defines body for CreateK8sRelease for application/json ContentType. +type CreateK8sReleaseJSONRequestBody CreateK8sReleaseJSONBody + +// UpdateK8sReleaseJSONRequestBody defines body for UpdateK8sRelease for application/json ContentType. +type UpdateK8sReleaseJSONRequestBody UpdateK8sReleaseJSONBody + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Get the list of the deployed releases + // (GET /clusters/{clusterId}/namespaces/{namespace}/releases) + ListK8sReleases(c *gin.Context, clusterId string, namespace string) + // Create KuboCD release in Kubernetes + // (POST /clusters/{clusterId}/namespaces/{namespace}/releases) + CreateK8sRelease(c *gin.Context, clusterId string, namespace string, params CreateK8sReleaseParams) + // Update KuboCD release in Kubernetes + // (PUT /clusters/{clusterId}/namespaces/{namespace}/releases) + UpdateK8sRelease(c *gin.Context, clusterId string, namespace string, params UpdateK8sReleaseParams) + // Delete the KuboCD release in kubernetes + // (DELETE /clusters/{clusterId}/namespaces/{namespace}/releases/{releaseName}) + DeleteK8sRelease(c *gin.Context, clusterId string, namespace string, releaseName string) + // Get the deployed release by name + // (GET /clusters/{clusterId}/namespaces/{namespace}/releases/{releaseName}) + GetK8sRelease(c *gin.Context, clusterId string, namespace string, releaseName string) + // Get the release status + // (GET /clusters/{clusterId}/namespaces/{namespace}/releases/{releaseName}/status) + GetK8sReleaseStatus(c *gin.Context, clusterId string, namespace string, releaseName string) +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +type MiddlewareFunc func(c *gin.Context) + +// ListK8sReleases operation middleware +func (siw *ServerInterfaceWrapper) ListK8sReleases(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListK8sReleases(c, clusterId, namespace) +} + +// CreateK8sRelease operation middleware +func (siw *ServerInterfaceWrapper) CreateK8sRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params CreateK8sReleaseParams + + // ------------- Optional query parameter "dryRun" ------------- + + err = runtime.BindQueryParameter("form", true, false, "dryRun", c.Request.URL.Query(), ¶ms.DryRun) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter dryRun: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.CreateK8sRelease(c, clusterId, namespace, params) +} + +// UpdateK8sRelease operation middleware +func (siw *ServerInterfaceWrapper) UpdateK8sRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params UpdateK8sReleaseParams + + // ------------- Optional query parameter "dryRun" ------------- + + err = runtime.BindQueryParameter("form", true, false, "dryRun", c.Request.URL.Query(), ¶ms.DryRun) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter dryRun: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.UpdateK8sRelease(c, clusterId, namespace, params) +} + +// DeleteK8sRelease operation middleware +func (siw *ServerInterfaceWrapper) DeleteK8sRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "releaseName" ------------- + var releaseName string + + err = runtime.BindStyledParameterWithOptions("simple", "releaseName", c.Param("releaseName"), &releaseName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter releaseName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.DeleteK8sRelease(c, clusterId, namespace, releaseName) +} + +// GetK8sRelease operation middleware +func (siw *ServerInterfaceWrapper) GetK8sRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "releaseName" ------------- + var releaseName string + + err = runtime.BindStyledParameterWithOptions("simple", "releaseName", c.Param("releaseName"), &releaseName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter releaseName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetK8sRelease(c, clusterId, namespace, releaseName) +} + +// GetK8sReleaseStatus operation middleware +func (siw *ServerInterfaceWrapper) GetK8sReleaseStatus(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "releaseName" ------------- + var releaseName string + + err = runtime.BindStyledParameterWithOptions("simple", "releaseName", c.Param("releaseName"), &releaseName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter releaseName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetK8sReleaseStatus(c, clusterId, namespace, releaseName) +} + +// GinServerOptions provides options for the Gin server. +type GinServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { + errorHandler := options.ErrorHandler + if errorHandler == nil { + errorHandler = func(c *gin.Context, err error, statusCode int) { + c.JSON(statusCode, gin.H{"msg": err.Error()}) + } + } + + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandler: errorHandler, + } + + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases", wrapper.ListK8sReleases) + router.POST(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases", wrapper.CreateK8sRelease) + router.PUT(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases", wrapper.UpdateK8sRelease) + router.DELETE(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases/:releaseName", wrapper.DeleteK8sRelease) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases/:releaseName", wrapper.GetK8sRelease) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/releases/:releaseName/status", wrapper.GetK8sReleaseStatus) +} diff --git a/api/openapi/v3/_api/repositories/repositories-server.go b/api/openapi/v3/_api/repositories/repositories-server.go new file mode 100644 index 0000000..2515668 --- /dev/null +++ b/api/openapi/v3/_api/repositories/repositories-server.go @@ -0,0 +1,1012 @@ +// Package _repositories provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package _repositories + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/oapi-codegen/runtime" +) + +// Defines values for CreateGitReleaseJSONBodySpecPackageProvider. +const ( + CreateGitReleaseJSONBodySpecPackageProviderAws CreateGitReleaseJSONBodySpecPackageProvider = "aws" + CreateGitReleaseJSONBodySpecPackageProviderAzure CreateGitReleaseJSONBodySpecPackageProvider = "azure" + CreateGitReleaseJSONBodySpecPackageProviderGcp CreateGitReleaseJSONBodySpecPackageProvider = "gcp" + CreateGitReleaseJSONBodySpecPackageProviderGeneric CreateGitReleaseJSONBodySpecPackageProvider = "generic" +) + +// Defines values for CreateGitReleaseJSONBodySpecPackageVerifyProvider. +const ( + CreateGitReleaseJSONBodySpecPackageVerifyProviderCosign CreateGitReleaseJSONBodySpecPackageVerifyProvider = "cosign" + CreateGitReleaseJSONBodySpecPackageVerifyProviderNotation CreateGitReleaseJSONBodySpecPackageVerifyProvider = "notation" +) + +// Defines values for UpdateGitReleaseJSONBodySpecPackageProvider. +const ( + UpdateGitReleaseJSONBodySpecPackageProviderAws UpdateGitReleaseJSONBodySpecPackageProvider = "aws" + UpdateGitReleaseJSONBodySpecPackageProviderAzure UpdateGitReleaseJSONBodySpecPackageProvider = "azure" + UpdateGitReleaseJSONBodySpecPackageProviderGcp UpdateGitReleaseJSONBodySpecPackageProvider = "gcp" + UpdateGitReleaseJSONBodySpecPackageProviderGeneric UpdateGitReleaseJSONBodySpecPackageProvider = "generic" +) + +// Defines values for UpdateGitReleaseJSONBodySpecPackageVerifyProvider. +const ( + UpdateGitReleaseJSONBodySpecPackageVerifyProviderCosign UpdateGitReleaseJSONBodySpecPackageVerifyProvider = "cosign" + UpdateGitReleaseJSONBodySpecPackageVerifyProviderNotation UpdateGitReleaseJSONBodySpecPackageVerifyProvider = "notation" +) + +// CreateGitReleaseJSONBody defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *CreateGitReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider CreateGitReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` +} + +// CreateGitReleaseJSONBodySpecPackageProvider defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBodySpecPackageProvider string + +// CreateGitReleaseJSONBodySpecPackageVerifyProvider defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBodySpecPackageVerifyProvider string + +// UpdateGitReleaseJSONBody defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *UpdateGitReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider UpdateGitReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` +} + +// UpdateGitReleaseJSONBodySpecPackageProvider defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBodySpecPackageProvider string + +// UpdateGitReleaseJSONBodySpecPackageVerifyProvider defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBodySpecPackageVerifyProvider string + +// CreateGitReleaseJSONRequestBody defines body for CreateGitRelease for application/json ContentType. +type CreateGitReleaseJSONRequestBody CreateGitReleaseJSONBody + +// UpdateGitReleaseJSONRequestBody defines body for UpdateGitRelease for application/json ContentType. +type UpdateGitReleaseJSONRequestBody UpdateGitReleaseJSONBody + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // List all configured git repositories + // (GET /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations) + ListGitRepos(c *gin.Context, clusterId string, namespace string) + // Return a git repo details + // (GET /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}) + GetGitRepo(c *gin.Context, clusterId string, namespace string, kustomizationName string) + // Return list of releases in the git repo + // (GET /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases) + ListGitReleases(c *gin.Context, clusterId string, namespace string, kustomizationName string) + // Create a new KuboCD release in the git repo + // (POST /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases) + CreateGitRelease(c *gin.Context, clusterId string, namespace string, kustomizationName string) + // Update an existing KuboCD release in the git repo + // (PUT /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases) + UpdateGitRelease(c *gin.Context, clusterId string, namespace string, kustomizationName string) + // Delete KuboCD release by name in the git repo + // (DELETE /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases/{releaseName}) + DeleteGitRelease(c *gin.Context, clusterId string, namespace string, kustomizationName string, releaseName string) + // Return KuboCD release by name in the git repo + // (GET /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases/{releaseName}) + GetGitRelease(c *gin.Context, clusterId string, namespace string, kustomizationName string, releaseName string) +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +type MiddlewareFunc func(c *gin.Context) + +// ListGitRepos operation middleware +func (siw *ServerInterfaceWrapper) ListGitRepos(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListGitRepos(c, clusterId, namespace) +} + +// GetGitRepo operation middleware +func (siw *ServerInterfaceWrapper) GetGitRepo(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetGitRepo(c, clusterId, namespace, kustomizationName) +} + +// ListGitReleases operation middleware +func (siw *ServerInterfaceWrapper) ListGitReleases(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.ListGitReleases(c, clusterId, namespace, kustomizationName) +} + +// CreateGitRelease operation middleware +func (siw *ServerInterfaceWrapper) CreateGitRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.CreateGitRelease(c, clusterId, namespace, kustomizationName) +} + +// UpdateGitRelease operation middleware +func (siw *ServerInterfaceWrapper) UpdateGitRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.UpdateGitRelease(c, clusterId, namespace, kustomizationName) +} + +// DeleteGitRelease operation middleware +func (siw *ServerInterfaceWrapper) DeleteGitRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "releaseName" ------------- + var releaseName string + + err = runtime.BindStyledParameterWithOptions("simple", "releaseName", c.Param("releaseName"), &releaseName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter releaseName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.DeleteGitRelease(c, clusterId, namespace, kustomizationName, releaseName) +} + +// GetGitRelease operation middleware +func (siw *ServerInterfaceWrapper) GetGitRelease(c *gin.Context) { + + var err error + + // ------------- Path parameter "clusterId" ------------- + var clusterId string + + err = runtime.BindStyledParameterWithOptions("simple", "clusterId", c.Param("clusterId"), &clusterId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter clusterId: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "namespace" ------------- + var namespace string + + err = runtime.BindStyledParameterWithOptions("simple", "namespace", c.Param("namespace"), &namespace, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter namespace: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "kustomizationName" ------------- + var kustomizationName string + + err = runtime.BindStyledParameterWithOptions("simple", "kustomizationName", c.Param("kustomizationName"), &kustomizationName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kustomizationName: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "releaseName" ------------- + var releaseName string + + err = runtime.BindStyledParameterWithOptions("simple", "releaseName", c.Param("releaseName"), &releaseName, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter releaseName: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetGitRelease(c, clusterId, namespace, kustomizationName, releaseName) +} + +// GinServerOptions provides options for the Gin server. +type GinServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router gin.IRouter, si ServerInterface) { + RegisterHandlersWithOptions(router, si, GinServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { + errorHandler := options.ErrorHandler + if errorHandler == nil { + errorHandler = func(c *gin.Context, err error, statusCode int) { + c.JSON(statusCode, gin.H{"msg": err.Error()}) + } + } + + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandler: errorHandler, + } + + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations", wrapper.ListGitRepos) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName", wrapper.GetGitRepo) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName/releases", wrapper.ListGitReleases) + router.POST(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName/releases", wrapper.CreateGitRelease) + router.PUT(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName/releases", wrapper.UpdateGitRelease) + router.DELETE(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName/releases/:releaseName", wrapper.DeleteGitRelease) + router.GET(options.BaseURL+"/clusters/:clusterId/namespaces/:namespace/gitkustomizations/:kustomizationName/releases/:releaseName", wrapper.GetGitRelease) +} diff --git a/api/openapi/v3/_api/services/services-server.go b/api/openapi/v3/_api/services/services-server.go deleted file mode 100644 index fc99f50..0000000 --- a/api/openapi/v3/_api/services/services-server.go +++ /dev/null @@ -1,99 +0,0 @@ -// Package _services provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. -package _services - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/oapi-codegen/runtime" -) - -// ListServicesParams defines parameters for ListServices. -type ListServicesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // List all services - // (GET /kad/{kadInstanceId}/services) - ListServices(c *gin.Context, kadInstanceId string, params ListServicesParams) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// ListServices operation middleware -func (siw *ServerInterfaceWrapper) ListServices(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params ListServicesParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.ListServices(c, kadInstanceId, params) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.GET(options.BaseURL+"/kad/:kadInstanceId/services", wrapper.ListServices) -} diff --git a/api/openapi/v3/_api/spec.go b/api/openapi/v3/_api/spec.go index 6d304e1..bc43527 100644 --- a/api/openapi/v3/_api/spec.go +++ b/api/openapi/v3/_api/spec.go @@ -18,51 +18,109 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xcWXPUOvb/Ki7//w8zVU06cOcpT8MlQGXYUgnh1hSTohT7dLdubMtIcqCH6u8+JVmy", - "ZS1eupvQufBCBVs6m87yO/JJvsUJyUtSQMFZfPItZskKciR/TGGBC8wxKT49QxxlZCmelpSUQDkGuaa7", - "GXPI5Q98XUJ8EjNOcbGMNzP9AFGK1uL/BcrBvxDyMkMcJtHbzGIKnytMIY1PPtbEZ6ZsJt3rZje5+RMS", - "Hs/ir3kmuNRCxYlSVpA1baDJuVa4xUXqFZOVkLjLUZaRL88oIA5vUQ6sRIlpjBtCMkCF2C9XfkBZBcy/", - "QMk60foJKRbYc5q4YBxlmeeYxwhLIYcUI2Esl4J+Ca8R4y8QzioaJMMp7uhbVPkNUOeYvSTb/c452/tt", - "pboauNtnMcc5kIp7bVyVS4pSCGv+UMzSbwRrsfaY1jatJXwWTEjB4Su/lFnGNccLnPnTwr9YbT3rhSWN", - "3K4Wz+J/ozzzCpFCCUXK3hV7ylkloigHDrSO7jSVCQNl54ZunFYgOLOE4rL2hfg1Zjwii0juF9sjxKJb", - "WM/vRMRHJcJUpi5b/pbfj7VjSQmHhEMa8FiSwcTExEhFEwhkTEg/AGWYFBOJprBAVcbVZu+WJeYXUBKG", - "OaFrl33w5AtPRjT9gq/8uaLIUYGWfsP5i5mkZe40mfsOZwVZ3qdTApRfQkKBX8DCK2WyQtSf63DBgd6h", - "zF/zeolWNBv2P7FI8ze4mbRnlgI+E5AE72YBXDBIghn5fqzQyLC1ISyydiw5AWKHg21Ix7d8tmcVE0k2", - "lBsqhpbSrKSAd4v45KNrpP5MajG83sziuwYn7ZNoMGv44/SuMWIDzbS2De4yrWNm0Sb/dUqKJ9/bdbTR", - "vYsYZ36kqTOzWQi9R8gRr5gbN0ApoV63XoTKjq9iecpaIF1SyACxqbWEY+6Vxjq3RV3rVH6tdfOavJFC", - "kx6MNNkWqCagMedw+9H0GaEG5KKW5BytM4LSnqbM90oj//Ew5WmzMqq3V7RGhx6fGcZIAlt0T7IrYUqS", - "Kleyj3ewqvhCUel9FXix8eF7y4XuHdj1A6oQOhqdo/TCLRJ2m1ynm6HeO9IG2ybc6+2BPRToJgspviX2", - "mwx+B+4wAo1MMDlcwOcKmDcD5MHwSiwiXQX+nwo0E//fvL1YmavrovmINOUxvMIZL0iWAh0+8e7yWaOK", - "T/DJ5mIlKRjsfLfTk3sVGOw+fBtyrw9j4+Bt7SkfemL78nsmju9dUkZXjtO+yhHsiK/CleOPv07lOIjk", - "bjlV3b2EoPBlPxSuncGA1EqHPd739JaFugWSuUME4KdPwRrx44qHVsAsIyZrnxa7NgfbXUjXvKBI8FSU", - "v1Mzcg9wJnwHpDvg3dqT2DKe0Wzqk9hTn9ItoC8yxHu+iGz7XUIRDFZFu9APL+y79uuN8BIlt2gZ5qDe", - "99HfLSvrT1Zvh76VDdlCr+sTtXFHdRkUn8StOwd807SQYw/7ND1HYqnoCho4b7/mZr4LFRXnTmawG190", - "/NzqyF9i8S7HAZhdP+8mkfcriFaIrUQi4SuI1LqZ14NzzN8Aa0+mA6HU1kivCJLgQJ/nCGcuDfm4KwmX", - "yDpMSTtZl5B4OorOgigg2rjZAmXMSbV/rICvgEacRHKHYyYzTBBdAj9XedaytnwXiSQaiRTalTHChfzf", - "EvOImvebIwCf4QWvUHpWMI4K75eLEl/5Lntn8ddHS/JIednT87Ori9fyi2/FV78DouAvajgdInV2at5c", - "X97i8gNQvFh3jN657hxudu2PfvrrQzzT+nUE97IfjLRbw4xWnF0CvQP6XJf6roXzNkLcHq1BKeoVLjgs", - "gbbFZ0jXvIkuRUttHFSHGTJ71ME+Z+kkm62a725Ztkus8BRCZa/9D+EkTC5lWH+btoPSchBj+29BZzEW", - "PQ7g0i7fma32KNNi10ved4vCzq38dtdCujQdUv9/v92ot83r6+IGAWrRrfpGqf/+rUmywllKoTj4tmT6", - "FMF370wa232/rsTODRYytHPEFQN6Tok+BCvgNUpy5wMoqcqJjpORJS6m3QpsMzFR3QwhAlb5DSy2ajGb", - "el7boNFYyzRo98ow7GYjWMFXDrRA2SlJmIvM3r06PY/0tx599yc/i8crzkt2Mp+T27Q8wmRe45kFUd+v", - "OEq4cVoxTjE9wv/FnFQFFPDP2+qGcJQdYaK1UtwE6KsKzNe9nGy4jlmEWYSii+eX76On52cRhQVQKBIQ", - "0FTiR0m9xijCoDgBdZOs0V2JkhVET46OHc5fvnw5QvL1EaHLudrL5q/Pnj1/e/n80ZOj46MVzzPjg2Zs", - "sFNSldj4EHISPz46PjqWAxAlFKjE8Un8m3xUR6s8jflt/eVwCZ4mRaYUlGXRq6enzQUtpBFW+Ez4hQgc", - "eW5nqdph4GDpOOpKXbJ7cnysj0/dF6CyzHAiKcz/VFNJLDDO1PLdAhKZ8Hzo4qxl5ElPm1DmFVZqd7YT", - "R5M0HqnNZQdWOiIpt4AGdrIqzxFdjzxUjkR5/CiweHwttgs3mX8zoPlZugm6zUvgHVtEN+tIpZWut7wE", - "01m6VePko022Q/LsVLYX8YkuPG73cJbG5qnWNZPZcwdNVbv+GVy1Y8PuJ5dD9dcebxrlpnMT7/WnOb3y", - "P4U3sT1rb43+Oo7qRcNjP/HqCfkBH+0De8FsKu9n9MaDT6bGjaL2ylbrQdecfxNe0Z9RkeYRCRCko8Dj", - "qi9Be+oPdtSZzU+JpcPXw0y9ub9gmOrprnc8M06F5oefS/1+NNFvtXzmSJ7XczlJSSidOsMaB+auL3DG", - "gQoLaZNEfxPNA4oYCEE5pH/XQnyuQF4ZW787dI953Hcku87sNOMwgxne4T451WsKUUPi8JO+K7MRRq5J", - "xsfTyIJg8x+oCtbpHlx5cNTZY6F4aNG9c8R6KpVj3wdUs0KuPhBxs7isPPFTz8JHhEZVmYqfPBw8QVRv", - "e0ev5KafOp6u68XA+O8kXd+Pa9ejrKM8u1TTprZKm/sJy3YiwC9tjrnyvDRiVZIAY4sqy+RV7pPjxz9K", - "pPpXYV2RDjIxjInhXevxmEuDZu0Qzv0FcPcCcHdDtuOh7A4Y9iFhVy9mHRccE1EqGwlP2e/rZpbsIMvp", - "TwxLH1RMup73UFAu64O3fcGpZmJG1C29MlC1LjWhXzVr+/gwT2NqdOjpsKHYaHhMrVbNxoOvVaz1RR0M", - "rdbBUNAjIIN3lA0fvaO5zgnEhjVh9itGdokR3zFNjRV75G8oZhyek2LH9pLDDyBX5DaSXFuMjqhx+M9m", - "3o8C7aM8sNB6byvz64pycnC6PuxY9eFcTIa8ezjCKgaUzfN12c4hBqMoX0dieaTW+kPnzVpP3u01QQvG", - "Ewx61ZkAtP6UjSA1Jte+6ep70D5gnY1x8PKExWnLPwQkiNQprJ79m6MSz+8exyIO1Q776K+6dO1Ryu4M", - "4RLzVXVzlJBcDjLKfx7VbNtpUyWTm2teIWMEzPlt7H1wvpW//P/NY1yF7fbBxAC1gemDfXEyZlOGisS+", - "WDqJZMSd/97Uda5Pe5jvnSmLN9eb/wUAAP//ngezcqRUAAA=", + "H4sIAAAAAAAC/+w9a3Mct5F/BbVJFcnKPpTkLuVj6iqnkLbCkiWxSDp3Ka/Ows707iKLAcYAhuSa4X+/", + "ajzmidmHRMmkjl/s5eDV6Hc3GtDdIJFZLgUIowfHdwOdLCGj9mcKcyaYYVL8dEIN5XKBX3Mlc1CGge2T", + "KEhBGEa57jamMlmBSqSYs8U/tRT4zaxzGBwPtFFMLAb3w4GSM2leJokshHlLM9ja6UquIDbV/TB8kbN/", + "QmJwXAo6USzHPUTnZWn383BwO1rIkbCwDM5OsZ/oAyynyYou3HaZgSyChZ6xuCv4uWAK0sHxj67X+8gW", + "/AeqFF1bVEAuf1AcZ5xLlVEzOB4Uig2GG7dhR11831mWpQO/uyayqnVqe+yANxzcZrza4yCwyb1FfcU9", + "vNAGVBc1tDBL/L8U8G4+OP7xrgmbCAPf3w+bTatiBo6vum0Jzj9nCTXQbZwBVXbC98MWLL6lC2POLkFd", + "u6Y9MP7y/MyPux/6yTdwbh3GasXmwBh31Df7eUBP6Akos01MTl7aXtifMxAmPqZsfg3r/fBQDWusUIIX", + "w03FP9VSMyk5UIHNNR76TJiTwsBtHA1MaEgKBZcrll9x/XdQbL6Ow5lTJyS7I8uOqNbvW62Ls5gKBXH9", + "OVTnBj2EKw4Hq292UTiewC2F84qZC8ilZkaq9Z5GS0OiwFzAfDvQVdcY+/XaDGzQOU36LEqU3LjyvOf7", + "QxqESu3jeiVNKpgr9qphcSuhmhRpkevcGZh+09kw44OrJRBsIXJOzBKIt0+dDTdx053jh4vvcYp3JxdE", + "wYJpo9a7Im04uAalmRS6O/VLwpk2OHPoQ+ZStSAtfYUOyE17H/MSaotXO9xKgYDkFu4vgAPVESz7BsK0", + "Bf3S+oXlTpRr1eTl+dl4MOyqz787ECPoOT/zbcSCAW5+vyVIifNAHXGZJgpyBRqEoTgBfqaCuD2Op8Lp", + "PE30UhY8JYkU16AMUZDIhWC/lNNpYqRdh1MD2hAmDChBObmmvIAhoSKdioyuiQKcmRSiNoXto8dT8UYq", + "IEzM5TFZGpPr48lkwcx49Y0eMzlJZJYVgpn1BDWvYrPCSKUnKVwDn2i2GFGVLJmBxBQKJjRnIwuuwH3p", + "cZb+RoGWhUpAx1h5xUTaxeZrJlIkESWup4O1Qhp+wm1ffHt5RcL8DrEOh1VXXUMnYoKJOSjXda5kZqcB", + "keaSCWP/cHaY6GKWMYOE+rkAbRDT46k4oUJIQ2ZAijylBtLxVJwJckIz4CdUw+fHJmJQjxBtUXxmYGhK", + "De3i9NJQkVKVBgyFnhE+xz1avnR/pqkVKsrPG906a7ckQs2YUVStGyt1XT0FdqkrloE2NMu7kJ/4LsSE", + "PjhTaRWQDiNsiuEjBQ449pWiCZyDYjK9RP8ojag430Ao5/IGUqsVFjhuXnBiQGVMWDgaqzNh/vRv1coo", + "gQvnKIWlN+zs1Hf5mJ3NmaCc/QIqspPvvaqu+oz30M7DwQIEKGrgbdRSnSuYs1uHHtcR5ZGSQrCfC2fE", + "xjGIQ+eY/rxEMRMJEFFkM1BNUa8G4qZS0Gg4iDbUwI604HQG/FO4+TWsR04J5ZQpq3cxOllIxX6BUgXp", + "KItnVNAFpN8x4DG2e+Oaydy2E6NossJdow4hh4nMcg63XmqPogvEHYq3NWciABilS8Nz685hm3aaSN4I", + "UBcwB4Wk1DHrG9oQgfJG4D4byOvJNjRNb68ViW4t2lDEHP1opNDNVDhwe12Bi2CPvPG3gpJIkRQK974m", + "VvNLHkWhBj7/nolVTFfkCpDnUoKdRpyJFTp70Wn89poz/ODk8+yUUK3ZAr2S2Zq8LmagBJgG825CiM4h", + "6XWsLnNIGh5QQ1qRi3zHrtnxgV2Eba4kyZW8ZikQ36mwPo5idMZBT4XlK2SpE9dc+QS1iSwdtMyAwG3O", + "qdPlU+GHaEIVkAwUiiITFva5REuAPCpVCup4KkYEXewFlzPKcZu04IZIAeTQ7dkOPbHh91HoXYpXAJ4c", + "vix/3jCzRDcnh4TNWWI7D0ltMhfLD4lXhwE076lWk/vl0ANCWCG1/vpUnDogj8mP7/vF66OCuo9N9VmL", + "D2/7lc7ZnBhl3dc0JeSOMKEN5fyY3JHW2GPbkdyTe6uQLapIRnN0wwpt/TQNZkioJoV2+MxkWnAYX4BI", + "QR0e1RA0p1zXLG0tV5HCrFh04XylZJEj8cAa25wqmoFBR7PQ1mdAhrNjF8hDIfSgIiXnZcjUyi0XWX5S", + "JVhaGqBqtDhRRWJw35peA6GRkMK6s27AVHjGuTTUFHrsWAUBLDTUoPxLHAFFlp+X24tDVrXvDlyFsk+B", + "L54iz5HCImExO4RiqSQHTW5QRWBXIsWYHNLcDktDXIWi7WEtkGH4GinpA96jXuna6mC1MvgtX2gplWlo", + "ripqdLqTXDKx4EA4Q/gEX8dsQF7lH7q79424zxRyLtdddQzKXNazRi2nvN5MEipQ2BbsGhwZQyaDEtfJ", + "8iFlaPCnAphZgiJSkZk0SyLnU4Hai5Lzb9+MQCQSKeDjsFoqmBx+MFyPE2U+HFkpyhW7pgamYgVr37iC", + "9YejP3dnO3nZmimhbiJcGue6WbJkCdegrB3QRZ5zBumQ3DDObbynfUSQSCEgcSGoZZKpCHmWsdX3NcAt", + "lAgczumVApuTtSzwy1TQwizRx02cC+2NQQ3QP1tkeuAxIi4nmQo/Cym0c7+tV+DturYRb30mB5snRlag", + "aZg53l7nQD68y+nPBXxAmnxYVR4BkxPD9YcxYumtNHBMLos8R/YMKZMPCf2OcfgwJB9wNfvbbvvDCtbu", + "rxWsNVnSa8AlQSDDeU+m6wTs4spaH9LEvZWdLBJbCKlihsd+J/IalGKpd2C8dofbhBfISTk1BpTQwRKP", + "nafh5iQuFpmKQ8tPIc2kEX6qyXjBjOt4NCZncyKkCZ5NOiS09CjqTDecikQKjZ+tPyWTIiv1KFJhLQtV", + "+ppGYtCXElkYcrOkOEaizVFxjz2k0CO48C0uGtYttqdESDG6+v6S/O3q6jwIt43bvChE7YjNT11Tn7m0", + "ex0cD/49Gww7q7uOhBonmXbv707OqnSrTXQyTZIlJCsvmy4po8dTYc1HWM6mkvJcyVuWofQje2Z0bd2D", + "wmVDjCT/ZEhY/AVCFyieMJ+zxApzoS3/NUIVzwiD48H/Hv74YvQf7393OJ2O3a+jvxxm+l/6X9m/lkdH", + "v/ttVD07uqu4fvbua2CEJRUpd/46JcmS8ZTMeXF7ckreJayGkwDg0GMtjHd+kx3vsmQ5BtRSTcVLzmt+", + "ro9BwzAFOWcu5rDcXubXEMEQWFdVyrGu0KQYBrtwQG/0wZAc0F8KBfhjkeQHqGsObGjPkoPxVPz3EoSV", + "CO8Mo0h4JrHhYr3vCHXUrGAc3XLf6fg/fQd72FJkqAKqL/RG438RgMFwsEjymmZoEOV2vcHqnTfaS0h9", + "Mrlt6ZyPg0O8b1ooH3QYaVnqZsk4umg2J1g3AsFz6wrVr6AuVePQqYUQqow7bjgjheJEJux4MpkWL178", + "ManG2b/h2H02dOH+jse/vbiveRsOM0E/W6xbh6OF+oA3wuWCiamone0gQ6Gw8GsgLENPqMxSOt7WlaUk", + "NUPZtI3tUpBfiUBo7VkCrXKTNvbafYJxqh86VckA0hzgRBw1fyXhMBU4xqEvL7j1bRxJ7FBC/dgl1YQa", + "Q5Ml2k/s6LCrx+Q7qUgWMuZoOpkUx1MRMucddOuJoXqlJ0GeYJTLdFSKSu27B2LkgZj8hqbpyMKKEHgA", + "RkaOaLtrlC8LjZFBTFljnMLpghjgXJeSqyTnzpr4oZ7YiRQJ44w2/PpOTq1mMw1dfH6xMywDWZimXf7T", + "C90xzCgavrNV+AoyaaxlJjUz5MyLPSTkbOWYg4lFU5//6cXuZrTPiF6XFQZNMF0twM6KwqhCG8ubM84S", + "67BOReB4t4abgi0ENdYrEmlN+ztjW5pDr92NdM7JVNwswUY8iCYnLuiRBEnqao2MmmT57uz05MzqK7OO", + "ZY1bXVrGiIXPdi7caKKYAcWoBw+hQuvjtmdDCGEBpBgz0CQ4XjdUEx9VuEjjROKfiCQOWk8F/sXEwgUY", + "YfCBriBgmqQAmcPmzK/I0KeYEyrWXvdMRWn3HczuxM4kS0IXSETT2FcjWdxETR0rFk011MjclGfX1c6t", + "0NbCw7DIcCrYGMZuYa0LjA69JAfHMaRZapFWh5xuaMTHdlM2CadgAbchykCMtXAQGNIpX9xrAM0HJN8V", + "PGGyG/uFKYNJo1NxTTlLySs0hYuCU0XgNlegtT/kimhBZ3O61sVj41O2UvJLQO0e+7HBLCX77addrOOo", + "VO1yl2Rm04sPmjOxItJRnudBQTTRZCBZCsnlYl1aWSthPuQhL71MjWuObblCOKqNurM7eVNNYBoeQMSf", + "nYqIsvxV/J5Wr5ISW3uWUWjDtXWWNkbzfEPmExkxJHYbPn51PGGrbSpHZmQToeoaRoVYCXkjRnN/MGhU", + "AY6lDCQG0g2ZcUTgDcyWUq5csJYruMZANRw675TXtinQ/tNjlyGdF3zOOK8Fj2UW8oulS/WK5X5sb3b8", + "bE7WoIf+0MnlUXzy+1Af1dLhc7Zwhz0Yaxq6AoGaxvt+UzHcAXEoMueoy/66fmPPEzadLO9F/FYNBcbl", + "iNzcKk7cwN+AZ+EIDcGwlgxosvQnG7HzYe+BbuSo2rw+jYJ2uxxJqEHVIE9OCYdr4FNx6FIsmrx9d2Uh", + "W7YgGwfHF73jkJAIaRcwyE7upIzkVJndTmIMVQswG86OmgduZXabMDEmh2/omlCurRNC7aqMcucQ2uQF", + "yQpu2Kgcr2us+1YaEpSIPVBiJmQ3NJgiJ1RI6+Pd0PXQnynYk0NRr5GbisPSoQgpeBsdkTm7hbQCfUik", + "IhquQVGOYqWPxjUEBTSXMWu9kHGzMg2nAtE40p69IFJ/a8syB7+ZVNcoJr7kbNIts3NnNrHi3XBI7o/o", + "a/VJ/hx5a4FfqOSLF/idibmM3NDYcj9iwUx3UG+FauEqLTdVUMZKTn09aRGrYvyUOtqeotJmkqarUV0U", + "uZk3drCG8crNqgIUUbsrTS3x4nS9LDkxXmVgmxt1BnJm9Wqk0GAqXtpzvhsqjD9e9IEI3OacJcwQOsN4", + "NmTi67mIoT0hlOLA5YAPZIZWKzfrAzQazHggLPDjqTj89jaB3IXGB976HFh1UeYEfBLXnmha1XjUVwkR", + "OXQLp7/Bv9aosDC2cw1DDKl8xaLL2bplfNSzryeywyGqhaBVskwQQzwk2kOlgq2e2svq1wwKkg021m81", + "Yftba6g/TZ1BD6+EpHptXIcqCmgaF65Kb26TL5zh/bYbXXtD34FdI4952eyWozGNcfxpIO66R9H0O731", + "o/42J9aqIGzpxYMyZL70Rd2RxD0TwTeMQVxvLit+6hXGRvoC90IFaRoTNPo2OmMJ5dyFZ0MyK1yldfB8", + "Z0BSpnNO15BOBdXEApNIXmQifvLDhDndVAFw3uoxFScyX1eRk5Oo2hh0FyyurW6yvQ6DFKZHpWBKAb0A", + "nfeHHeeNdoe2xANUfh6G4+t/TITVa2NyJcuTc6S8w1HPWVj/2mHZStc0vMxybPD6HVH8llt9puKs1J6u", + "nDMcH87W9aAqHi6h+AYJi9mmWnObt/zmyf9M/lF3lImd83MxWk9899kVd6G9i/KRxbY/aJ8iddyOkaR1", + "pR2w53XK2qV+XMH6/Zi8ZD7HGIoFbelQzZiPp+I1rEliL1UcLE3GD4bkwNtoWxnIqVgUdvF0SMAk43Gk", + "4PZ+R/+m5hbXPBx3GeECdC6FU2bNL1d26s79EkFAFFmzLjplc5dDCfUeys9hz6p0LV0kV2n+kw436Wr3", + "ghbM/IRun7ua9lMSrqbGhbSeogate6uLSjh8r+qqRQnDBiPanc8WGbgOJJEpRGu8TRRx9sBinZd5iRam", + "HhRHLXMfUFTuzQ/Y6h+3WKTFQD9oUOdKzhmPhAGQUcbjQY+SRd680b1VkO256X6F1aXO2SO7U8y2BVgh", + "Jdu5q1jMBgHM6qalxUG54wDTVrTXEXt/j0vBrbtPdSqT2DnD69PzZj2Oj/eOB+H8EnlqzOTEFb+4WNXm", + "U10S3VNrwFKmxuwXZmQhQMB/rYqZNJSPmQy78quV14c2rhQ5obTmyF6Xenl+FnKvCZRlXHb28qotZwl4", + "5RSuAOc0WQL5w/hFZ+Wbm5sxtc1jqRYTP1ZPvj87+fbt5bejP4xfjFHXunNGw8vNuOU8VDmrbgAOjge/", + "H78Yv7B3CnIQNGeD48Ef7Sd3UdNSY5K4i/n2jwWYnkwm5ZyEnlMkUXk6eZb6PidhIlveb6XOTvqHFy/K", + "eEwYdxHBVcQwKSbh8QeXGGnw/I75k/Jlgc4FyQ4VQ1LWJjEDuE4xuEOHPcDcEbqOGuoA5SkISkl3W1kX", + "WUbVOoZ6l1LQ9vAifHqPY0oyTu78r7P0vpekr8Cg9+k6otfG0ghRX0Gg6aAZyvzYCan9TGen9kb54Dgk", + "bjzjlyAN6prH5kxrGG0bgvefyEj78k+XNGFfNffnMbNLhKz7Mcyk/mZJvzKwdfquI64SFowyEQ44D7M+", + "STbaVx+Vt6m366OAmKfFYHwjD3wkx03ukMibVVaIsBrruSJ234JzxDVZ7bLIl2fB4V2c8CG9FFnItzw6", + "bVm9FfBVcPNuLPVpPD2pPwjRr1UbT0LUbrOVp14b2Prv1asPz+z9edm7pNOjdxy3MNQDMfXkzv/aTXdX", + "O9zI0Kdlt6+XpXvXuC4PfCPLVI1fTnjiKUi3ajuv1ys3FeWfilFI60z4sLIyqXa1VWT8qzeHlRgMq7NK", + "MMnRRklyr/M8S9FXIkV+uiciQVtZd4NguQzxDnmp6uyThEF9Kaow55dOUYW36PZMUQVwn0KKKkKFOnHD", + "pyZxJ3f+1/ZsVXf+jYkrj/Ftas/P1Kv2AnSPMnFVvnDYTVz5fT2pvEIfhfdjo0lVebiX6qiG9SiPt9W8", + "T5Krdn5XcKNOqmH3iWklUaffxzGU8+fs7z3UVVVK6wuK4irrbeMdzS/OXh0/6nVkB/0+W2j+cvzcnq/D", + "H9W7W09VDXY450E4d7JgZlVoIzP2S/VC4Zazv3AlNCULZl+GdEWurFddhmddt3Hz667W/3KMPefFbVJt", + "qcHocEuz3B60Yq+RXmsD2WMSgH290NZDu/vp/TbVn8axaT/X1iSp8fkBpGly1/j77cZzjQswhRKEVjyY", + "gqGM67iR8DR8FqqHAqwBUy5TW2AShadD1McYE7Qf0+6Izauw+SdiE3vl4wsL8ETValY3SXI4HS2fwfY3", + "cAP8m8ylX+FZuD+HcAeCbITr1xXyfS164w7Qdnse6qWRRZ+AzG+TpH4NMBzkUpueR7CBUCLgJtzEDBXa", + "28XUja4E9VlOn7Sc2vs0f5XuOtJD839147JXCmX5aFr1tlhnF/cdjfL7z6pR2nK7u1IJr6PpIklA63nB", + "+foxK5k9dMFGRVNE9MwP7u43FQRumbbXDPbWNm6OZ23zrG0eXtv4f3djB23z4pFqG7+DJ6Nt9tYIv1Z4", + "M7nzv8q0hX0NBXr+3Q1ob8MnKndQcG78s4J7+gouBl+dJ/bLs9T47zFmWLarAb/7i/KGMfL501FVe8n1", + "JtdoU5bko7VGyIE+q4xnlfFUVMYG96ylK5jP5DzyzMyn6oZ9XZituddX4B625LUTK/doFZR38PsOKl9/", + "o59E5vVRHsJ/ZMbya8pW7sR7NVmw/3rtthRlNzioOKE3NVlx8v8/Rh72PsqXg5pLldmnRCwVR5qlQFK1", + "JqoQ9sEV+3AVKO0js/q/0RZg/LkA+46BBzJV64sC6dCBqPoXdZ6zjM9Zxh3EOaYaNiQV99QMbtSzZnjW", + "DM8ZwceYEdxLM3ys37x3Us8/Yt2CbLVJ0biRz4pma0z7nPJ6rCmvbVwfsdQbo9F2FLC5/vtZdL5C0fl6", + "Uj/bmPozGatJ9aTdRlkL0Lju2yTsMrwl9yxnX5Wcla9Ffi3S1mTrqIwVGgUsW+fVc4a9kpKt3Xuevm9c", + "TN6swwN+n0i75quKuPAe6Gs+JNh8sdBO9X6HW9Nvmvt97BRvkadGbktkJLj/l+qCwnKvCE5ozibXvx+g", + "tPkRnexBc972o4zN1wgXzCyL2TiRmX0S0f5n5F/1LN+t9DB1dUrtIcCHWKb2UN8GdVm72v0gi1ZXr3tU", + "5itmSO3c4CEWbd2v6Vn49TeXD70wKpMvuR5NMyYG9+/v/y8AAP//fn3AcWOUAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/openapi/v3/_api/templatereleases/templatereleases-server.go b/api/openapi/v3/_api/templatereleases/templatereleases-server.go deleted file mode 100644 index 80593cf..0000000 --- a/api/openapi/v3/_api/templatereleases/templatereleases-server.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package _templatereleases provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. -package _templatereleases - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/oapi-codegen/runtime" -) - -// ListTemplateReleasesParams defines parameters for ListTemplateReleases. -type ListTemplateReleasesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// GetTemplateReleaseParams defines parameters for GetTemplateRelease. -type GetTemplateReleaseParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // List all template releases - // (GET /kad/{kadInstanceId}/templatereleases) - ListTemplateReleases(c *gin.Context, kadInstanceId string, params ListTemplateReleasesParams) - // Get a template release by name - // (GET /kad/{kadInstanceId}/templatereleases/{name}) - GetTemplateRelease(c *gin.Context, kadInstanceId string, name string, params GetTemplateReleaseParams) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -type MiddlewareFunc func(c *gin.Context) - -// ListTemplateReleases operation middleware -func (siw *ServerInterfaceWrapper) ListTemplateReleases(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params ListTemplateReleasesParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.ListTemplateReleases(c, kadInstanceId, params) -} - -// GetTemplateRelease operation middleware -func (siw *ServerInterfaceWrapper) GetTemplateRelease(c *gin.Context) { - - var err error - - // ------------- Path parameter "kadInstanceId" ------------- - var kadInstanceId string - - err = runtime.BindStyledParameterWithOptions("simple", "kadInstanceId", c.Param("kadInstanceId"), &kadInstanceId, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter kadInstanceId: %w", err), http.StatusBadRequest) - return - } - - // ------------- Path parameter "name" ------------- - var name string - - err = runtime.BindStyledParameterWithOptions("simple", "name", c.Param("name"), &name, runtime.BindStyledParameterOptions{Explode: false, Required: true}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter name: %w", err), http.StatusBadRequest) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params GetTemplateReleaseParams - - // ------------- Optional query parameter "catalog" ------------- - - err = runtime.BindQueryParameter("form", true, false, "catalog", c.Request.URL.Query(), ¶ms.Catalog) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter catalog: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.GetTemplateRelease(c, kadInstanceId, name, params) -} - -// GinServerOptions provides options for the Gin server. -type GinServerOptions struct { - BaseURL string - Middlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. -func RegisterHandlers(router gin.IRouter, si ServerInterface) { - RegisterHandlersWithOptions(router, si, GinServerOptions{}) -} - -// RegisterHandlersWithOptions creates http.Handler with additional options -func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) { - errorHandler := options.ErrorHandler - if errorHandler == nil { - errorHandler = func(c *gin.Context, err error, statusCode int) { - c.JSON(statusCode, gin.H{"msg": err.Error()}) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandler: errorHandler, - } - - router.GET(options.BaseURL+"/kad/:kadInstanceId/templatereleases", wrapper.ListTemplateReleases) - router.GET(options.BaseURL+"/kad/:kadInstanceId/templatereleases/:name", wrapper.GetTemplateRelease) -} diff --git a/api/openapi/v3/_api/types.go b/api/openapi/v3/_api/types.go index d8368aa..bcdca96 100644 --- a/api/openapi/v3/_api/types.go +++ b/api/openapi/v3/_api/types.go @@ -5,249 +5,146 @@ package _api import ( "encoding/json" + "fmt" + "time" "github.com/oapi-codegen/runtime" ) -// Catalog defines model for Catalog. -type Catalog struct { - Components []string `json:"components"` - Name string `json:"name"` - Templates []string `json:"templates"` -} +// Defines values for ReleaseSpecPackageProvider. +const ( + ReleaseSpecPackageProviderAws ReleaseSpecPackageProvider = "aws" + ReleaseSpecPackageProviderAzure ReleaseSpecPackageProvider = "azure" + ReleaseSpecPackageProviderGcp ReleaseSpecPackageProvider = "gcp" + ReleaseSpecPackageProviderGeneric ReleaseSpecPackageProvider = "generic" +) -// Component defines model for Component. -type Component struct { - Kind string `json:"kind"` - Spec struct { - AllowCreateNamespace bool `json:"allowCreateNamespace"` - AllowValues bool `json:"allowValues"` - Catalogs []string `json:"catalogs"` - Config struct { - Install struct { - CreateNamespace bool `json:"createNamespace"` - Remediation struct { - RemediateLastFailure bool `json:"remediateLastFailure"` - Retries float32 `json:"retries"` - } `json:"remediation"` - } `json:"install"` - Timeout string `json:"timeout"` - Upgrade struct { - Remediation struct { - RemediateLastFailure bool `json:"remediateLastFailure"` - Retries float32 `json:"retries"` - } `json:"remediation"` - } `json:"upgrade"` - } `json:"config"` - ContextSchema struct { - File string `json:"File"` - Json string `json:"Json"` - } `json:"contextSchema"` - DependsOn []string `json:"dependsOn"` - Name string `json:"name"` - - // Parameters List of paramters as key/value pairs - Parameters map[string]interface{} `json:"parameters"` - ParametersSchema struct { - File string `json:"File"` - Json string `json:"Json"` - } `json:"parametersSchema"` - Protected bool `json:"protected"` - Roles []string `json:"roles"` - Source struct { - AllowedVersions []string `json:"allowedVersions"` - DefaultVersion string `json:"defaultVersion"` - GitRepository struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - Path string `json:"path"` - Unmanaged bool `json:"unmanaged"` - } `json:"gitRepository"` - HelmRepository struct { - CertSecretRef string `json:"certSecretRef"` - Chart string `json:"chart"` - Interval string `json:"interval"` - SecretRef string `json:"secretRef"` - Url string `json:"url"` - } `json:"helmRepository"` - OciRepository struct { - CertSecretRef string `json:"certSecretRef"` - Insecure bool `json:"insecure"` - Interval string `json:"interval"` - SecretRef string `json:"secretRef"` - Url string `json:"url"` - } `json:"ociRepository"` - } `json:"source"` - Suspended bool `json:"suspended"` - Usage Component_Spec_Usage `json:"usage"` - Values Component_Spec_Values `json:"values"` - Version string `json:"version"` - } `json:"spec"` - Status struct { - Error string `json:"error"` - File string `json:"file"` - ParametersSchema map[string]interface{} `json:"parametersSchema"` - Path string `json:"path"` - Releases []string `json:"releases"` - Title string `json:"title"` - } `json:"status"` -} +// Defines values for ReleaseSpecPackageVerifyProvider. +const ( + ReleaseSpecPackageVerifyProviderCosign ReleaseSpecPackageVerifyProvider = "cosign" + ReleaseSpecPackageVerifyProviderNotation ReleaseSpecPackageVerifyProvider = "notation" +) -// ComponentSpecUsage0 defines model for . -type ComponentSpecUsage0 = string +// Defines values for ServerResponseType. +const ( + GitRepo ServerResponseType = "git_repo" + K8sCluster ServerResponseType = "k8s_cluster" + OkdpServer ServerResponseType = "okdp_server" + Registry ServerResponseType = "registry" +) -// ComponentSpecUsage1 defines model for . -type ComponentSpecUsage1 map[string]interface{} +// Defines values for CreateGitReleaseJSONBodySpecPackageProvider. +const ( + CreateGitReleaseJSONBodySpecPackageProviderAws CreateGitReleaseJSONBodySpecPackageProvider = "aws" + CreateGitReleaseJSONBodySpecPackageProviderAzure CreateGitReleaseJSONBodySpecPackageProvider = "azure" + CreateGitReleaseJSONBodySpecPackageProviderGcp CreateGitReleaseJSONBodySpecPackageProvider = "gcp" + CreateGitReleaseJSONBodySpecPackageProviderGeneric CreateGitReleaseJSONBodySpecPackageProvider = "generic" +) -// Component_Spec_Usage defines model for Component.Spec.Usage. -type Component_Spec_Usage struct { - union json.RawMessage -} +// Defines values for CreateGitReleaseJSONBodySpecPackageVerifyProvider. +const ( + CreateGitReleaseJSONBodySpecPackageVerifyProviderCosign CreateGitReleaseJSONBodySpecPackageVerifyProvider = "cosign" + CreateGitReleaseJSONBodySpecPackageVerifyProviderNotation CreateGitReleaseJSONBodySpecPackageVerifyProvider = "notation" +) -// ComponentSpecValues0 defines model for . -type ComponentSpecValues0 = string +// Defines values for UpdateGitReleaseJSONBodySpecPackageProvider. +const ( + UpdateGitReleaseJSONBodySpecPackageProviderAws UpdateGitReleaseJSONBodySpecPackageProvider = "aws" + UpdateGitReleaseJSONBodySpecPackageProviderAzure UpdateGitReleaseJSONBodySpecPackageProvider = "azure" + UpdateGitReleaseJSONBodySpecPackageProviderGcp UpdateGitReleaseJSONBodySpecPackageProvider = "gcp" + UpdateGitReleaseJSONBodySpecPackageProviderGeneric UpdateGitReleaseJSONBodySpecPackageProvider = "generic" +) -// ComponentSpecValues1 defines model for . -type ComponentSpecValues1 map[string]interface{} +// Defines values for UpdateGitReleaseJSONBodySpecPackageVerifyProvider. +const ( + UpdateGitReleaseJSONBodySpecPackageVerifyProviderCosign UpdateGitReleaseJSONBodySpecPackageVerifyProvider = "cosign" + UpdateGitReleaseJSONBodySpecPackageVerifyProviderNotation UpdateGitReleaseJSONBodySpecPackageVerifyProvider = "notation" +) -// Component_Spec_Values defines model for Component.Spec.Values. -type Component_Spec_Values struct { - union json.RawMessage -} +// Defines values for CreateK8sReleaseJSONBodySpecPackageProvider. +const ( + CreateK8sReleaseJSONBodySpecPackageProviderAws CreateK8sReleaseJSONBodySpecPackageProvider = "aws" + CreateK8sReleaseJSONBodySpecPackageProviderAzure CreateK8sReleaseJSONBodySpecPackageProvider = "azure" + CreateK8sReleaseJSONBodySpecPackageProviderGcp CreateK8sReleaseJSONBodySpecPackageProvider = "gcp" + CreateK8sReleaseJSONBodySpecPackageProviderGeneric CreateK8sReleaseJSONBodySpecPackageProvider = "generic" +) -// ComponentReleasePayload defines model for ComponentReleasePayload. -type ComponentReleasePayload struct { - Component struct { - // Config Additional configuration - Config *map[string]interface{} `json:"config,omitempty"` - Name string `json:"name"` - ParameterFiles *[]struct { - Document *string `json:"document,omitempty"` - File *string `json:"file,omitempty"` - Unwrap *string `json:"unwrap,omitempty"` - Wrap *string `json:"wrap,omitempty"` - } `json:"parameterFiles,omitempty"` - - // Parameters List of paramters as key/value pairs - Parameters *map[string]interface{} `json:"parameters,omitempty"` - Protected *bool `json:"protected,omitempty"` - Source *struct { - Version string `json:"version"` - } `json:"source,omitempty"` - Suspended *bool `json:"suspended,omitempty"` +// Defines values for CreateK8sReleaseJSONBodySpecPackageVerifyProvider. +const ( + CreateK8sReleaseJSONBodySpecPackageVerifyProviderCosign CreateK8sReleaseJSONBodySpecPackageVerifyProvider = "cosign" + CreateK8sReleaseJSONBodySpecPackageVerifyProviderNotation CreateK8sReleaseJSONBodySpecPackageVerifyProvider = "notation" +) - // Values List of values as key/value pairs - Values *map[string]interface{} `json:"values,omitempty"` - Version string `json:"version"` - } `json:"component"` - DependsOn *[]string `json:"dependsOn,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Name string `json:"name"` - Namespace *string `json:"namespace,omitempty"` - Roles *[]string `json:"roles,omitempty"` -} +// Defines values for UpdateK8sReleaseJSONBodySpecPackageProvider. +const ( + Aws UpdateK8sReleaseJSONBodySpecPackageProvider = "aws" + Azure UpdateK8sReleaseJSONBodySpecPackageProvider = "azure" + Gcp UpdateK8sReleaseJSONBodySpecPackageProvider = "gcp" + Generic UpdateK8sReleaseJSONBodySpecPackageProvider = "generic" +) + +// Defines values for UpdateK8sReleaseJSONBodySpecPackageVerifyProvider. +const ( + Cosign UpdateK8sReleaseJSONBodySpecPackageVerifyProvider = "cosign" + Notation UpdateK8sReleaseJSONBodySpecPackageVerifyProvider = "notation" +) -// ComponentReleaseRequest defines model for ComponentReleaseRequest. -type ComponentReleaseRequest struct { - Comment string `json:"comment"` - ComponentReleases []struct { - Component struct { - // Config Additional configuration - Config *map[string]interface{} `json:"config,omitempty"` - Name string `json:"name"` - ParameterFiles *[]struct { - Document *string `json:"document,omitempty"` - File *string `json:"file,omitempty"` - Unwrap *string `json:"unwrap,omitempty"` - Wrap *string `json:"wrap,omitempty"` - } `json:"parameterFiles,omitempty"` - - // Parameters List of paramters as key/value pairs - Parameters *map[string]interface{} `json:"parameters,omitempty"` - Protected *bool `json:"protected,omitempty"` - Source *struct { - Version string `json:"version"` - } `json:"source,omitempty"` - Suspended *bool `json:"suspended,omitempty"` - - // Values List of values as key/value pairs - Values *map[string]interface{} `json:"values,omitempty"` - Version string `json:"version"` - } `json:"component"` - DependsOn *[]string `json:"dependsOn,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Name string `json:"name"` - Namespace *string `json:"namespace,omitempty"` - Roles *[]string `json:"roles,omitempty"` - } `json:"componentReleases"` - GitRepoFolder string `json:"gitRepoFolder"` +// Catalog defines model for Catalog. +type Catalog struct { + Credentials *struct { + Dockerconfigjson *string `json:"dockerconfigjson,omitempty"` + RobotAccountName *string `json:"robotAccountName,omitempty"` + RobotAccountToken *string `json:"robotAccountToken,omitempty"` + } `json:"credentials,omitempty"` + Description string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + Packages []struct { + Name string `json:"name"` + } `json:"packages"` + RepoURL string `json:"repoUrl"` } -// ComponentReleaseResponse defines model for ComponentReleaseResponse. -type ComponentReleaseResponse struct { - Kind string `json:"kind"` - Spec struct { - Component struct { - Ref struct { - Name string `json:"Name"` - Version string `json:"Version"` - } `json:"Ref"` - Source struct { - Version string `json:"version"` - } `json:"Source"` - - // Config Additional configuration - Config map[string]interface{} `json:"config"` - ParameterFiles []struct { - Document *string `json:"Document,omitempty"` - File *string `json:"File,omitempty"` - Unwrap *string `json:"Unwrap,omitempty"` - Wrap *string `json:"Wrap,omitempty"` - } `json:"parameterFiles"` - - // Parameters List of paramters as key/value pairs - Parameters map[string]interface{} `json:"parameters"` - Protected bool `json:"protected"` - Suspended bool `json:"suspended"` - - // Values List of values as key/value pairs - Values map[string]interface{} `json:"values"` - } `json:"component"` - DependsOn []string `json:"dependsOn"` - Enabled bool `json:"enabled"` - HelmReleaseName string `json:"helmReleaseName__"` - Name string `json:"name"` - Namespace string `json:"namespace"` - Roles []string `json:"roles"` - } `json:"spec"` - Status struct { - Catalogs []string `json:"catalogs"` - Dependencies []string `json:"dependencies"` - Error string `json:"error"` - File string `json:"file"` - - // Parameters List of values as key/value pairs - Parameters map[string]interface{} `json:"parameters"` - Path string `json:"path"` - Usage string `json:"usage"` - } `json:"status"` +// Cluster defines model for Cluster. +type Cluster struct { + Auth *Cluster_Auth `json:"auth,omitempty"` + Env string `json:"env"` + ID string `json:"id"` + Name string `json:"name"` } -// FlatComponent defines model for FlatComponent. -type FlatComponent struct { - Catalogs []string `json:"catalogs"` - ComponentName string `json:"componentName"` - ComponentReleaseName string `json:"componentReleaseName"` - ComponentVersion string `json:"componentVersion"` - Enabled bool `json:"enabled"` - PackageName string `json:"packageName"` - PackageVersion string `json:"packageVersion"` - Protected bool `json:"protected"` - Suspended bool `json:"suspended"` - TemplateName string `json:"templateName"` - TemplateReleaseName string `json:"templateReleaseName"` - TemplateVersion string `json:"templateVersion"` - Usage string `json:"usage"` +// ClusterAuth0 defines model for . +type ClusterAuth0 = interface{} + +// ClusterAuth1 defines model for . +type ClusterAuth1 = interface{} + +// ClusterAuth2 defines model for . +type ClusterAuth2 = interface{} + +// ClusterAuth3 defines model for . +type ClusterAuth3 = interface{} + +// Cluster_Auth defines model for Cluster.Auth. +type Cluster_Auth struct { + Bearer *struct { + APIServer string `json:"apiServer"` + BearerToken string `json:"bearerToken"` + } `json:"bearer,omitempty"` + Certificate *struct { + APIServer string `json:"apiServer"` + CACert string `json:"caCert"` + ClientCert string `json:"clientCert"` + ClientKey string `json:"clientKey"` + } `json:"certificate,omitempty"` + InCluster *bool `json:"inCluster,omitempty"` + Kubeconfig *struct { + APIServer string `json:"apiServer"` + Context string `json:"context"` + InsecureSkipTlsVerify bool `json:"insecureSkipTlsVerify"` + Path string `json:"path"` + } `json:"kubeconfig,omitempty"` + union json.RawMessage } // GitCommit defines model for GitCommit. @@ -271,72 +168,408 @@ type GitCommit struct { TargetPath *string `json:"targetPath,omitempty"` } -// KadInstance defines model for KadInstance. -type KadInstance struct { - APIURL string `json:"apiUrl"` - AuthBearer string `json:"authBearer"` - ID string `json:"id"` - InsecureSkipVerify bool `json:"insecureSkipVerify"` - Name string `json:"name"` +// GitRepository defines model for GitRepository. +type GitRepository struct { + Credentials struct { + SecretRef string `json:"secretRef"` + } `json:"credentials"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Path string `json:"path"` + Ref string `json:"ref"` + RepoURL string `json:"repoUrl"` } -// ServerError defines model for ServerError. -type ServerError struct { - Message string `json:"message"` - Status int `json:"status"` - Type string `json:"type"` -} +// Package defines model for Package. +type Package struct { + // Name The name of the package + Name string `json:"name"` + + // RepoURL The URL of OCR registry + RepoURL string `json:"repoUrl"` -// Service defines model for Service. -type Service struct { - Name string `json:"name"` - IsComposition bool `json:"isComposition"` - FlatComponents []struct { - Catalogs []string `json:"catalogs"` - ComponentName string `json:"componentName"` - ComponentReleaseName string `json:"componentReleaseName"` - ComponentVersion string `json:"componentVersion"` - Enabled bool `json:"enabled"` - PackageName string `json:"packageName"` - PackageVersion string `json:"packageVersion"` - Protected bool `json:"protected"` - Suspended bool `json:"suspended"` - TemplateName string `json:"templateName"` - TemplateReleaseName string `json:"templateReleaseName"` - TemplateVersion string `json:"templateVersion"` - Usage string `json:"usage"` - } `json:"flatComponents"` + // Versions A list of versions for the package + Versions []string `json:"versions"` } -// TemplateRelease defines model for TemplateRelease. -type TemplateRelease struct { +// Release Release is the Schema for the releases API. +type Release struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. Spec struct { - Enabled bool `json:"enabled"` - Name string `json:"name"` - Template struct { - Ref struct { - Name string `json:"Name"` - Version string `json:"Version"` - } `json:"Ref"` - - // Parameters List of paramters as key/value pairs - Parameters map[string]interface{} `json:"parameters"` - } `json:"template"` + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *ReleaseSpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider ReleaseSpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` } `json:"spec"` - Status struct { - Catalogs []string `json:"catalogs"` - Children []string `json:"children"` - Error string `json:"error"` - File string `json:"file"` - - // Parameters List of paramters as key/value pairs - Parameters map[string]interface{} `json:"parameters"` - Path string `json:"path"` - Usage string `json:"usage"` - } `json:"status"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` } +// ReleaseSpecPackageProvider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator +// All following fields will be replicated in this object +// The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. +// When not specified, defaults to 'generic'. +// -kubebuilder:default:=generic +type ReleaseSpecPackageProvider string + +// ReleaseSpecPackageVerifyProvider Provider specifies the technology used to sign the OCI Artifact. +type ReleaseSpecPackageVerifyProvider string + +// ReleaseInfo defines model for ReleaseInfo. +type ReleaseInfo struct { + Description *string `json:"description,omitempty"` + Git struct { + Path string `json:"path"` + URL string `json:"url"` + } `json:"git"` + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + Package struct { + Repository string `json:"repository"` + Tag string `json:"tag"` + } `json:"package"` +} + +// ReleaseStatus ReleaseStatus defines the observed state of Release. +// As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. +// (Except for 'context', as controlled by a debug flag) +type ReleaseStatus struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` +} + +// ServerResponse defines model for ServerResponse. +type ServerResponse struct { + // Message The response message from the server + Message string `json:"message"` + + // Status The HTTP status code + Status int `json:"status"` + + // Type The type of the server response + Type ServerResponseType `json:"type"` +} + +// ServerResponseType The type of the server response +type ServerResponseType string + // UserProfile defines model for UserProfile. type UserProfile struct { Email string `json:"email"` @@ -347,103 +580,1230 @@ type UserProfile struct { Subject string `json:"sub"` } -// ListComponentReleasesParams defines parameters for ListComponentReleases. -type ListComponentReleasesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} +// CreateGitReleaseJSONBody defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` -// GetComponentReleaseParams defines parameters for GetComponentRelease. -type GetComponentReleaseParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` -} + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` -// CreateOrUpdateComponentReleaseJSONBody defines parameters for CreateOrUpdateComponentRelease. -type CreateOrUpdateComponentReleaseJSONBody struct { - Comment string `json:"comment"` - ComponentReleases []struct { - Component struct { - // Config Additional configuration - Config *map[string]interface{} `json:"config,omitempty"` - Name string `json:"name"` - ParameterFiles *[]struct { - Document *string `json:"document,omitempty"` - File *string `json:"file,omitempty"` - Unwrap *string `json:"unwrap,omitempty"` - Wrap *string `json:"wrap,omitempty"` - } `json:"parameterFiles,omitempty"` - - // Parameters List of paramters as key/value pairs - Parameters *map[string]interface{} `json:"parameters,omitempty"` - Protected *bool `json:"protected,omitempty"` - Source *struct { - Version string `json:"version"` - } `json:"source,omitempty"` - Suspended *bool `json:"suspended,omitempty"` - - // Values List of values as key/value pairs - Values *map[string]interface{} `json:"values,omitempty"` - Version string `json:"version"` - } `json:"component"` - DependsOn *[]string `json:"dependsOn,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Name string `json:"name"` - Namespace *string `json:"namespace,omitempty"` - Roles *[]string `json:"roles,omitempty"` - } `json:"componentReleases"` - GitRepoFolder string `json:"gitRepoFolder"` + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *CreateGitReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider CreateGitReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` } -// ListComponentsParams defines parameters for ListComponents. -type ListComponentsParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` +// CreateGitReleaseJSONBodySpecPackageProvider defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBodySpecPackageProvider string + +// CreateGitReleaseJSONBodySpecPackageVerifyProvider defines parameters for CreateGitRelease. +type CreateGitReleaseJSONBodySpecPackageVerifyProvider string + +// UpdateGitReleaseJSONBody defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *UpdateGitReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider UpdateGitReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` } -// GetComponentsByNameParams defines parameters for GetComponentsByName. -type GetComponentsByNameParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` +// UpdateGitReleaseJSONBodySpecPackageProvider defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBodySpecPackageProvider string + +// UpdateGitReleaseJSONBodySpecPackageVerifyProvider defines parameters for UpdateGitRelease. +type UpdateGitReleaseJSONBodySpecPackageVerifyProvider string + +// CreateK8sReleaseJSONBody defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *CreateK8sReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider CreateK8sReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` } -// ListServicesParams defines parameters for ListServices. -type ListServicesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` +// CreateK8sReleaseParams defines parameters for CreateK8sRelease. +type CreateK8sReleaseParams struct { + // DryRun If true, performs a server-side dry run without persisting the resource + DryRun *bool `form:"dryRun,omitempty" json:"dryRun,omitempty"` } -// ListTemplateReleasesParams defines parameters for ListTemplateReleases. -type ListTemplateReleasesParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` +// CreateK8sReleaseJSONBodySpecPackageProvider defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBodySpecPackageProvider string + +// CreateK8sReleaseJSONBodySpecPackageVerifyProvider defines parameters for CreateK8sRelease. +type CreateK8sReleaseJSONBodySpecPackageVerifyProvider string + +// UpdateK8sReleaseJSONBody defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBody struct { + // ApiVersion APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + ApiVersion string `json:"apiVersion"` + + // Kind Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // Metadata Standard object metadata. + Metadata struct { + // Annotations Arbitrary metadata. + Annotations *map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp Creation timestamp. + CreationTimestamp *time.Time `json:"creationTimestamp,omitempty"` + + // DeletionGracePeriodSeconds Seconds allowed for graceful termination. + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp Deletion timestamp. + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + + // Finalizers List of finalizers. + Finalizers *[]string `json:"finalizers,omitempty"` + + // GenerateName Prefix for generating a unique name. + GenerateName *string `json:"generateName,omitempty"` + + // Generation Sequence number representing generation of desired state. + Generation *int64 `json:"generation,omitempty"` + + // Labels Key-value pairs to categorize resources. + Labels *map[string]string `json:"labels,omitempty"` + + // ManagedFields Managed fields tracking info (complex object). + ManagedFields *map[string]interface{} `json:"managedFields,omitempty"` + + // Name Name of the resource. + Name *string `json:"name,omitempty"` + + // Namespace Namespace of the resource. + Namespace *string `json:"namespace,omitempty"` + + // OwnerReferences References to owning resources. + OwnerReferences *[]struct { + ApiVersion *string `json:"apiVersion,omitempty"` + Kind *string `json:"kind,omitempty"` + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + } `json:"ownerReferences,omitempty"` + + // ResourceVersion Resource version for concurrency control. + ResourceVersion *string `json:"resourceVersion,omitempty"` + + // SelfLink Deprecated self-link URL. + SelfLink *string `json:"selfLink,omitempty"` + + // Uid Unique ID assigned by Kubernetes. + Uid *string `json:"uid,omitempty"` + } `json:"metadata"` + + // Spec ReleaseSpec defines the desired state of Release. + Spec struct { + // Contexts To provide contextual variables + // Refer to Context resource description for some explanation + // Contexts are merged in the following order: + // - The global default one (defined in Config) + // - The namespace context (A context with a specific name, defined in config, present in the release namespace) + // - This ordered list + // Default: [] + Contexts *[]struct { + Name string `json:"name"` + Namespace *string `json:"namespace,omitempty"` + } `json:"contexts,omitempty"` + + // CreateNamespace If true, add { install: { createNamespace: true } } to config map. + // Must be set, as used in module.Render() + // Default: false + CreateNamespace *bool `json:"createNamespace,omitempty"` + + // Debug Group a set of parameters useful for debugging Release and Package + Debug *struct { + // DumpContext DumpContext instruct to save a representation of the context + // in the Status. This for user debugging? + DumpContext *bool `json:"dumpContext,omitempty"` + + // DumpParameters DumpParameters instruct to save a representation of the parameters + // in the Status. This for user debugging? + DumpParameters *bool `json:"dumpParameters,omitempty"` + } `json:"debug,omitempty"` + + // Dependencies The roles we depend on. (appended to the one of the underlying package) + // Default: [] + Dependencies *[]string `json:"dependencies,omitempty"` + + // Description Short description of this release. Single line only + Description *string `json:"description,omitempty"` + + // Package The package to deploy + Package struct { + // CertSecretRef CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // + // Note: Support for the `caFile`, `certFile` and `keyFile` keys have + // been deprecated. + CertSecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"certSecretRef,omitempty"` + + // Ignore Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + Ignore *string `json:"ignore,omitempty"` + + // Insecure Insecure allows connecting to a non-TLS HTTP container registry. + Insecure *bool `json:"insecure,omitempty"` + + // Interval Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + Interval string `json:"interval"` + + // Provider The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + // All following fields will be replicated in this object + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // -kubebuilder:default:=generic + Provider *UpdateK8sReleaseJSONBodySpecPackageProvider `json:"provider,omitempty"` + + // ProxySecretRef ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + ProxySecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"proxySecretRef,omitempty"` + + // Repository Part of OCI url oci://: + Repository string `json:"repository"` + + // SecretRef SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + + // ServiceAccountName ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + ServiceAccountName *string `json:"serviceAccountName,omitempty"` + + // Suspend This flag tells the controller to suspend the reconciliation of this source. + Suspend *bool `json:"suspend,omitempty"` + + // Tag Part of OCI url oci://: + Tag string `json:"tag"` + + // Timeout The timeout for remote OCI Repository operations like pulling, defaults to 60s. + Timeout *string `json:"timeout,omitempty"` + + // Verify Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + Verify *struct { + // MatchOIDCIdentity MatchOIDCIdentity specifies the identity matching criteria to use + // while verifying an OCI artifact which was signed using Cosign keyless + // signing. The artifact's identity is deemed to be verified if any of the + // specified matchers match against the identity. + MatchOIDCIdentity *[]struct { + // Issuer Issuer specifies the regex pattern to match against to verify + // the OIDC issuer in the Fulcio certificate. The pattern must be a + // valid Go regular expression. + Issuer string `json:"issuer"` + + // Subject Subject specifies the regex pattern to match against to verify + // the identity subject in the Fulcio certificate. The pattern must + // be a valid Go regular expression. + Subject string `json:"subject"` + } `json:"matchOIDCIdentity,omitempty"` + + // Provider Provider specifies the technology used to sign the OCI Artifact. + Provider UpdateK8sReleaseJSONBodySpecPackageVerifyProvider `json:"provider"` + + // SecretRef SecretRef specifies the Kubernetes Secret containing the + // trusted public keys. + SecretRef *struct { + // Name Name of the referent. + Name string `json:"name"` + } `json:"secretRef,omitempty"` + } `json:"verify,omitempty"` + } `json:"package"` + + // Parameters The Release configuration variables + Parameters *interface{} `json:"parameters,omitempty"` + + // Protected If true, the webhook will prevent deletion + // Default: false + Protected *bool `json:"protected,omitempty"` + + // Roles List of roles fulfilled by this release. (appended to the one of the underlying package) + // Default: [] + Roles *[]string `json:"roles,omitempty"` + + // SkipDefaultContext If yes, the default context(s) of the configs are not taken in account + // ,Default: false + SkipDefaultContext *bool `json:"skipDefaultContext,omitempty"` + + // SpecPatchByModule Allow to patch the HelmRelease.spec for each module + SpecPatchByModule *map[string]interface{} `json:"specPatchByModule,omitempty"` + + // Suspended If true, HelmRelease update is suspended at KuboCD level + // (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + // Default: false + Suspended *bool `json:"suspended,omitempty"` + + // TargetNamespace The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + // Not required, as it can be setup another way, depending on the package + // (i.e. the package has a fixed namespace, or several ones). + // Default: Release.metadata.namespace + TargetNamespace *string `json:"targetNamespace,omitempty"` + } `json:"spec"` + + // Status ReleaseStatus defines the observed state of Release. + // As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + // (Except for 'context', as controlled by a debug flag) + Status *struct { + // Context Context is the resulting context, if requested in debug options + Context *interface{} `json:"context,omitempty"` + + // Dependencies The result of the package template and release value + Dependencies *[]string `json:"dependencies,omitempty"` + + // HelmReleaseStates HelmReleaseState describe the observed state of child HelmReleases by name + HelmReleaseStates *map[string]struct { + Ready string `json:"ready"` + Status *string `json:"status,omitempty"` + } `json:"helmReleaseStates,omitempty"` + MissingDependency *string `json:"missingDependency,omitempty"` + + // Parameters Parameters is the resulting parameters set, if requested in debug options + Parameters *interface{} `json:"parameters,omitempty"` + Phase *string `json:"phase,omitempty"` + + // PrintContexts PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + // as printcolumn + PrintContexts *string `json:"printContexts,omitempty"` + + // PrintDescription PrintDescription + // Copy of the release description, or, if empty the (templated) package one + PrintDescription *string `json:"printDescription,omitempty"` + + // PrintProtected PrintProtected is a copy of Protected, with a Y/n flag. To be used in display + PrintProtected *string `json:"printProtected,omitempty"` + + // Protected Protected result of Release.spec.protected defaulted to package.spec.protected + // It is the value checked by the webhook + Protected *bool `json:"protected,omitempty"` + + // ReadyReleases ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + // as printcolumn + ReadyReleases *string `json:"readyReleases,omitempty"` + + // Roles The result of the package template and release value + Roles *[]string `json:"roles,omitempty"` + + // Usage Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + // Key could 'html', 'text', some language id, etc... + Usage *map[string]string `json:"usage,omitempty"` + } `json:"status,omitempty"` } -// GetTemplateReleaseParams defines parameters for GetTemplateRelease. -type GetTemplateReleaseParams struct { - // Catalog Filter by catalogs (comma separated) - Catalog *string `form:"catalog,omitempty" json:"catalog,omitempty"` +// UpdateK8sReleaseParams defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseParams struct { + // DryRun If true, performs a server-side dry run without persisting the resource + DryRun *bool `form:"dryRun,omitempty" json:"dryRun,omitempty"` } -// CreateOrUpdateComponentReleaseJSONRequestBody defines body for CreateOrUpdateComponentRelease for application/json ContentType. -type CreateOrUpdateComponentReleaseJSONRequestBody CreateOrUpdateComponentReleaseJSONBody +// UpdateK8sReleaseJSONBodySpecPackageProvider defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBodySpecPackageProvider string + +// UpdateK8sReleaseJSONBodySpecPackageVerifyProvider defines parameters for UpdateK8sRelease. +type UpdateK8sReleaseJSONBodySpecPackageVerifyProvider string + +// CreateGitReleaseJSONRequestBody defines body for CreateGitRelease for application/json ContentType. +type CreateGitReleaseJSONRequestBody CreateGitReleaseJSONBody -// AsComponentSpecUsage0 returns the union data inside the Component_Spec_Usage as a ComponentSpecUsage0 -func (t Component_Spec_Usage) AsComponentSpecUsage0() (ComponentSpecUsage0, error) { - var body ComponentSpecUsage0 +// UpdateGitReleaseJSONRequestBody defines body for UpdateGitRelease for application/json ContentType. +type UpdateGitReleaseJSONRequestBody UpdateGitReleaseJSONBody + +// CreateK8sReleaseJSONRequestBody defines body for CreateK8sRelease for application/json ContentType. +type CreateK8sReleaseJSONRequestBody CreateK8sReleaseJSONBody + +// UpdateK8sReleaseJSONRequestBody defines body for UpdateK8sRelease for application/json ContentType. +type UpdateK8sReleaseJSONRequestBody UpdateK8sReleaseJSONBody + +// AsClusterAuth0 returns the union data inside the Cluster_Auth as a ClusterAuth0 +func (t Cluster_Auth) AsClusterAuth0() (ClusterAuth0, error) { + var body ClusterAuth0 err := json.Unmarshal(t.union, &body) return body, err } -// FromComponentSpecUsage0 overwrites any union data inside the Component_Spec_Usage as the provided ComponentSpecUsage0 -func (t *Component_Spec_Usage) FromComponentSpecUsage0(v ComponentSpecUsage0) error { +// FromClusterAuth0 overwrites any union data inside the Cluster_Auth as the provided ClusterAuth0 +func (t *Cluster_Auth) FromClusterAuth0(v ClusterAuth0) error { b, err := json.Marshal(v) t.union = b return err } -// MergeComponentSpecUsage0 performs a merge with any union data inside the Component_Spec_Usage, using the provided ComponentSpecUsage0 -func (t *Component_Spec_Usage) MergeComponentSpecUsage0(v ComponentSpecUsage0) error { +// MergeClusterAuth0 performs a merge with any union data inside the Cluster_Auth, using the provided ClusterAuth0 +func (t *Cluster_Auth) MergeClusterAuth0(v ClusterAuth0) error { b, err := json.Marshal(v) if err != nil { return err @@ -454,22 +1814,22 @@ func (t *Component_Spec_Usage) MergeComponentSpecUsage0(v ComponentSpecUsage0) e return err } -// AsComponentSpecUsage1 returns the union data inside the Component_Spec_Usage as a ComponentSpecUsage1 -func (t Component_Spec_Usage) AsComponentSpecUsage1() (ComponentSpecUsage1, error) { - var body ComponentSpecUsage1 +// AsClusterAuth1 returns the union data inside the Cluster_Auth as a ClusterAuth1 +func (t Cluster_Auth) AsClusterAuth1() (ClusterAuth1, error) { + var body ClusterAuth1 err := json.Unmarshal(t.union, &body) return body, err } -// FromComponentSpecUsage1 overwrites any union data inside the Component_Spec_Usage as the provided ComponentSpecUsage1 -func (t *Component_Spec_Usage) FromComponentSpecUsage1(v ComponentSpecUsage1) error { +// FromClusterAuth1 overwrites any union data inside the Cluster_Auth as the provided ClusterAuth1 +func (t *Cluster_Auth) FromClusterAuth1(v ClusterAuth1) error { b, err := json.Marshal(v) t.union = b return err } -// MergeComponentSpecUsage1 performs a merge with any union data inside the Component_Spec_Usage, using the provided ComponentSpecUsage1 -func (t *Component_Spec_Usage) MergeComponentSpecUsage1(v ComponentSpecUsage1) error { +// MergeClusterAuth1 performs a merge with any union data inside the Cluster_Auth, using the provided ClusterAuth1 +func (t *Cluster_Auth) MergeClusterAuth1(v ClusterAuth1) error { b, err := json.Marshal(v) if err != nil { return err @@ -480,32 +1840,22 @@ func (t *Component_Spec_Usage) MergeComponentSpecUsage1(v ComponentSpecUsage1) e return err } -func (t Component_Spec_Usage) MarshalJSON() ([]byte, error) { - b, err := t.union.MarshalJSON() - return b, err -} - -func (t *Component_Spec_Usage) UnmarshalJSON(b []byte) error { - err := t.union.UnmarshalJSON(b) - return err -} - -// AsComponentSpecValues0 returns the union data inside the Component_Spec_Values as a ComponentSpecValues0 -func (t Component_Spec_Values) AsComponentSpecValues0() (ComponentSpecValues0, error) { - var body ComponentSpecValues0 +// AsClusterAuth2 returns the union data inside the Cluster_Auth as a ClusterAuth2 +func (t Cluster_Auth) AsClusterAuth2() (ClusterAuth2, error) { + var body ClusterAuth2 err := json.Unmarshal(t.union, &body) return body, err } -// FromComponentSpecValues0 overwrites any union data inside the Component_Spec_Values as the provided ComponentSpecValues0 -func (t *Component_Spec_Values) FromComponentSpecValues0(v ComponentSpecValues0) error { +// FromClusterAuth2 overwrites any union data inside the Cluster_Auth as the provided ClusterAuth2 +func (t *Cluster_Auth) FromClusterAuth2(v ClusterAuth2) error { b, err := json.Marshal(v) t.union = b return err } -// MergeComponentSpecValues0 performs a merge with any union data inside the Component_Spec_Values, using the provided ComponentSpecValues0 -func (t *Component_Spec_Values) MergeComponentSpecValues0(v ComponentSpecValues0) error { +// MergeClusterAuth2 performs a merge with any union data inside the Cluster_Auth, using the provided ClusterAuth2 +func (t *Cluster_Auth) MergeClusterAuth2(v ClusterAuth2) error { b, err := json.Marshal(v) if err != nil { return err @@ -516,22 +1866,22 @@ func (t *Component_Spec_Values) MergeComponentSpecValues0(v ComponentSpecValues0 return err } -// AsComponentSpecValues1 returns the union data inside the Component_Spec_Values as a ComponentSpecValues1 -func (t Component_Spec_Values) AsComponentSpecValues1() (ComponentSpecValues1, error) { - var body ComponentSpecValues1 +// AsClusterAuth3 returns the union data inside the Cluster_Auth as a ClusterAuth3 +func (t Cluster_Auth) AsClusterAuth3() (ClusterAuth3, error) { + var body ClusterAuth3 err := json.Unmarshal(t.union, &body) return body, err } -// FromComponentSpecValues1 overwrites any union data inside the Component_Spec_Values as the provided ComponentSpecValues1 -func (t *Component_Spec_Values) FromComponentSpecValues1(v ComponentSpecValues1) error { +// FromClusterAuth3 overwrites any union data inside the Cluster_Auth as the provided ClusterAuth3 +func (t *Cluster_Auth) FromClusterAuth3(v ClusterAuth3) error { b, err := json.Marshal(v) t.union = b return err } -// MergeComponentSpecValues1 performs a merge with any union data inside the Component_Spec_Values, using the provided ComponentSpecValues1 -func (t *Component_Spec_Values) MergeComponentSpecValues1(v ComponentSpecValues1) error { +// MergeClusterAuth3 performs a merge with any union data inside the Cluster_Auth, using the provided ClusterAuth3 +func (t *Cluster_Auth) MergeClusterAuth3(v ClusterAuth3) error { b, err := json.Marshal(v) if err != nil { return err @@ -542,12 +1892,88 @@ func (t *Component_Spec_Values) MergeComponentSpecValues1(v ComponentSpecValues1 return err } -func (t Component_Spec_Values) MarshalJSON() ([]byte, error) { +func (t Cluster_Auth) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() + if err != nil { + return nil, err + } + object := make(map[string]json.RawMessage) + if t.union != nil { + err = json.Unmarshal(b, &object) + if err != nil { + return nil, err + } + } + + if t.Bearer != nil { + object["bearer"], err = json.Marshal(t.Bearer) + if err != nil { + return nil, fmt.Errorf("error marshaling 'bearer': %w", err) + } + } + + if t.Certificate != nil { + object["certificate"], err = json.Marshal(t.Certificate) + if err != nil { + return nil, fmt.Errorf("error marshaling 'certificate': %w", err) + } + } + + if t.InCluster != nil { + object["inCluster"], err = json.Marshal(t.InCluster) + if err != nil { + return nil, fmt.Errorf("error marshaling 'inCluster': %w", err) + } + } + + if t.Kubeconfig != nil { + object["kubeconfig"], err = json.Marshal(t.Kubeconfig) + if err != nil { + return nil, fmt.Errorf("error marshaling 'kubeconfig': %w", err) + } + } + b, err = json.Marshal(object) return b, err } -func (t *Component_Spec_Values) UnmarshalJSON(b []byte) error { +func (t *Cluster_Auth) UnmarshalJSON(b []byte) error { err := t.union.UnmarshalJSON(b) + if err != nil { + return err + } + object := make(map[string]json.RawMessage) + err = json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["bearer"]; found { + err = json.Unmarshal(raw, &t.Bearer) + if err != nil { + return fmt.Errorf("error reading 'bearer': %w", err) + } + } + + if raw, found := object["certificate"]; found { + err = json.Unmarshal(raw, &t.Certificate) + if err != nil { + return fmt.Errorf("error reading 'certificate': %w", err) + } + } + + if raw, found := object["inCluster"]; found { + err = json.Unmarshal(raw, &t.InCluster) + if err != nil { + return fmt.Errorf("error reading 'inCluster': %w", err) + } + } + + if raw, found := object["kubeconfig"]; found { + err = json.Unmarshal(raw, &t.Kubeconfig) + if err != nil { + return fmt.Errorf("error reading 'kubeconfig': %w", err) + } + } + return err } diff --git a/api/openapi/v3/api.yaml b/api/openapi/v3/api.yaml index 3254e9e..6e8af37 100644 --- a/api/openapi/v3/api.yaml +++ b/api/openapi/v3/api.yaml @@ -22,63 +22,75 @@ tags: description: User profile externalDocs: url: https://github.com/okdp/okdp-server - - name: kad - description: Kad instances configuration - externalDocs: - url: https://github.com/okdp/okdp-server - - name: services - description: Services - externalDocs: - url: https://github.com/okdp/okdp-server - name: catalogs description: Catalogs externalDocs: url: https://github.com/okdp/okdp-server - - name: templatereleases - description: Template releases + - name: clusters + description: Kubernetes Clusters externalDocs: url: https://github.com/okdp/okdp-server - - name: componentreleases - description: Component releases + - name: repositories + description: KuboCD Git Releases externalDocs: url: https://github.com/okdp/okdp-server - - name: components - description: Components + - name: k8s + description: KuboCD K8S Releases externalDocs: url: https://github.com/okdp/okdp-server - + - name: admin + description: KuboCD K8S Releases + externalDocs: + url: https://github.com/okdp/okdp-server + paths: ### Users /users/myprofile: $ref: ./paths/users/user-profile.yaml - ### KAD instances - /kad: - $ref: ./paths/kad/kad-instance.yaml - /kad/{kadInstanceId}: - $ref: ./paths/kad/kad-instance-by-name.yaml - ### KAD Catalog API - /kad/{kadInstanceId}/catalogs: - $ref: ./paths/catalogs/catalog.yaml - /kad/{kadInstanceId}/catalogs/{name}: - $ref: ./paths/catalogs/catalog-by-name.yaml - ### Services API - /kad/{kadInstanceId}/services: - $ref: ./paths/services/service.yaml - ### KAD Component Releases API - /kad/{kadInstanceId}/componentreleases: - $ref: ./paths/componentreleases/component-releases.yaml - /kad/{kadInstanceId}/componentreleases/{name}: - $ref: ./paths/componentreleases/component-releases-by-name.yaml - ### KAD Template Releases API - /kad/{kadInstanceId}/templatereleases: - $ref: ./paths/templatereleases/template-releases.yaml - /kad/{kadInstanceId}/templatereleases/{name}: - $ref: ./paths/templatereleases/template-releases-by-name.yaml - ### KAD Components API - /kad/{kadInstanceId}/components: - $ref: ./paths/components/component.yaml - /kad/{kadInstanceId}/components/{name}: - $ref: ./paths/components/component-by-name.yaml + + ### Registry Catalogs + /catalogs: + $ref: ./paths/catalogs/catalog-list.yaml + /catalogs/{catalogId}: + $ref: ./paths/catalogs/catalog-by-id.yaml + /catalogs/{catalogId}/packages: + $ref: ./paths/catalogs/package-list.yaml + /catalogs/{catalogId}/packages/{name}: + $ref: ./paths/catalogs/package-by-name.yaml + /catalogs/{catalogId}/packages/{name}/versions: + $ref: ./paths/catalogs/package-versions-by-name.yaml + /catalogs/{catalogId}/packages/{name}/versions/{version}: + $ref: ./paths/catalogs/package-definition.yaml + /catalogs/{catalogId}/packages/{name}/versions/{version}/schema: + $ref: ./paths/catalogs/package-schema.yaml + + ### Clusters + /clusters: + $ref: ./paths/clusters/cluster-list.yaml + /clusters/{clusterId}: + $ref: ./paths/clusters/cluster-by-id.yaml + /clusters/{clusterId}/namespaces: + $ref: ./paths/clusters/namespace-list.yaml + /clusters/{clusterId}/namespaces/{namespace}: + $ref: ./paths/clusters/namespace-by-name.yaml + + ### Git repositories KuboCD releases + /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations: + $ref: ./paths/repositories/repo-list.yaml + /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}: + $ref: ./paths/repositories/repo-by-name.yaml + /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases: + $ref: ./paths/repositories/releases.yaml + /clusters/{clusterId}/namespaces/{namespace}/gitkustomizations/{kustomizationName}/releases/{releaseName}: + $ref: ./paths/repositories/release-by-name.yaml + + ### k8s + /clusters/{clusterId}/namespaces/{namespace}/releases: + $ref: ./paths/k8s/releases.yaml + /clusters/{clusterId}/namespaces/{namespace}/releases/{releaseName}: + $ref: ./paths/k8s/release-by-name.yaml + /clusters/{clusterId}/namespaces/{namespace}/releases/{releaseName}/status: + $ref: ./paths/k8s/release-status.yaml components: schemas: @@ -86,24 +98,20 @@ components: $ref: './definition/UserProfile.yaml' Catalog: $ref: './definition/Catalog.yaml' - TemplateRelease: - $ref: './definition/TemplateRelease.yaml' - ComponentReleasePayload: - $ref: './definition/ComponentReleasePayload.yaml' - ComponentReleaseRequest: - $ref: './definition/ComponentReleaseRequest.yaml' - ComponentReleaseResponse: - $ref: './definition/ComponentReleaseResponse.yaml' - Component: - $ref: './definition/Component.yaml' - Service: - $ref: './definition/Service.yaml' - FlatComponent: - $ref: './definition/FlatComponent.yaml' - KadInstance: - $ref: './definition/KadInstance.yaml' + Cluster: + $ref: './definition/Cluster.yaml' + Package: + $ref: './definition/Package.yaml' + Release: + $ref: './definition/Release.yaml' + ReleaseInfo: + $ref: './definition/ReleaseInfo.yaml' + ReleaseStatus: + $ref: './definition/ReleaseStatus.yaml' + GitRepository: + $ref: './definition/GitRepository.yaml' GitCommit: $ref: './definition/GitCommit.yaml' - ServerError: - $ref: './definition/ServerError.yaml' + ServerResponse: + $ref: './definition/ServerResponse.yaml' diff --git a/api/openapi/v3/definition/Catalog.yaml b/api/openapi/v3/definition/Catalog.yaml index 74e2275..8ce4f67 100644 --- a/api/openapi/v3/definition/Catalog.yaml +++ b/api/openapi/v3/definition/Catalog.yaml @@ -1,19 +1,40 @@ type: object xml: - name: catalog -required: + name: Catalog +required: +- "id" - "name" -- "components" -- "templates" +- "description" +- "repoUrl" +- "packages" properties: + id: + type: string + x-go-name: ID name: type: string - components: - type: array - items: - type: string - templates: + description: + type: string + repoUrl: + type: string + format: uri + x-go-name: repoURL + credentials: + type: object + properties: + robotAccountName: + type: string + robotAccountToken: + type: string + dockerconfigjson: + type: string + packages: type: array items: - type: string + type: object + required: + - name + properties: + name: + type: string diff --git a/api/openapi/v3/definition/Cluster.yaml b/api/openapi/v3/definition/Cluster.yaml new file mode 100644 index 0000000..b181438 --- /dev/null +++ b/api/openapi/v3/definition/Cluster.yaml @@ -0,0 +1,77 @@ +type: object +xml: + name: Cluster +required: + - id + - name + - env + - k8s +properties: + id: + type: string + x-go-name: ID + name: + type: string + env: + type: string + auth: + type: object + oneOf: + - required: [inCluster] + - required: [kubeconfig] + - required: [certificate] + - required: [bearer] + properties: + inCluster: + type: boolean + kubeconfig: + type: object + required: + - apiServer + - path + - context + - insecureSkipTlsVerify + properties: + apiServer: + type: string + format: uri + x-go-name: APIServer + path: + type: string + context: + type: string + insecureSkipTlsVerify: + type: boolean + certificate: + type: object + required: + - apiServer + - clientKey + - clientCert + - caCert + properties: + apiServer: + type: string + format: uri + x-go-name: APIServer + clientKey: + type: string + clientCert: + type: string + caCert: + type: string + x-go-name: CACert + bearer: + type: object + required: + - apiServer + - bearerToken + properties: + apiServer: + type: string + format: uri + x-go-name: APIServer + bearerToken: + type: string + + diff --git a/api/openapi/v3/definition/Component.yaml b/api/openapi/v3/definition/Component.yaml deleted file mode 100644 index 3e859c0..0000000 --- a/api/openapi/v3/definition/Component.yaml +++ /dev/null @@ -1,226 +0,0 @@ -# https://swagger-toolbox.firebaseapp.com/ -type: object -xml: - name: component -required: -- "kind" -- "spec" -- "status" -properties: - kind: - type: "string" - spec: - required: - - "name" - - "version" - - "catalogs" - - "usage" - - "config" - - "suspended" - - "protected" - - "source" - - "parameters" - - "parametersSchema" - - "contextSchema" - - "values" - - "allowValues" - - "allowCreateNamespace" - - "roles" - - "dependsOn" - properties: - name: - type: "string" - version: - type: "string" - catalogs: - type: "array" - items: - type: "string" - usage: - oneOf: - - type: string - - type: object - additionalProperties: true - config: - required: - - "install" - - "timeout" - - "upgrade" - properties: - install: - required: - - "createNamespace" - - "remediation" - properties: - createNamespace: - type: "boolean" - remediation: - required: - - "remediateLastFailure" - - "retries" - properties: - remediateLastFailure: - type: "boolean" - retries: - type: "number" - type: "object" - type: "object" - timeout: - type: "string" - upgrade: - required: - - "remediation" - properties: - remediation: - required: - - "remediateLastFailure" - - "retries" - properties: - remediateLastFailure: - type: "boolean" - retries: - type: "number" - type: "object" - type: "object" - type: "object" - suspended: - type: "boolean" - protected: - type: "boolean" - source: - required: - - "allowedVersions" - - "defaultVersion" - - "gitRepository" - - "ociRepository" - - "helmRepository" - properties: - allowedVersions: - type: "array" - items: - type: "string" - defaultVersion: - type: "string" - gitRepository: - required: - - "name" - - "path" - - "unmanaged" - - "namespace" - properties: - name: - type: "string" - path: - type: "string" - unmanaged: - type: "boolean" - namespace: - type: "string" - type: "object" - ociRepository: - required: - - "url" - - "insecure" - - "interval" - - "secretRef" - - "certSecretRef" - properties: - url: - type: "string" - insecure: - type: "boolean" - interval: - type: "string" - secretRef: - type: "string" - certSecretRef: - type: "string" - type: "object" - helmRepository: - required: - - "url" - - "chart" - - "interval" - - "secretRef" - - "certSecretRef" - properties: - url: - type: "string" - chart: - type: "string" - interval: - type: "string" - secretRef: - type: "string" - certSecretRef: - type: "string" - type: "object" - type: "object" - parameters: - description: List of paramters as key/value pairs - additionalProperties: true - type: "object" - parametersSchema: - required: - - "File" - - "Json" - - "Yaml" - properties: - File: - type: "string" - Json: - type: "string" - type: "object" - contextSchema: - required: - - "File" - - "Json" - - "Yaml" - properties: - File: - type: "string" - Json: - type: "string" - type: "object" - values: - oneOf: - - type: string - - type: object - additionalProperties: true - allowValues: - type: "boolean" - allowCreateNamespace: - type: "boolean" - roles: - type: "array" - items: - type: "string" - dependsOn: - type: "array" - items: - type: "string" - type: "object" - status: - required: - - "file" - - "path" - - "error" - - "parametersSchema" - - "releases" - - "title" - properties: - file: - type: "string" - path: - type: "string" - error: - type: "string" - parametersSchema: - type: "object" - releases: - type: "array" - items: - type: "string" - title: - type: "string" - type: "object" diff --git a/api/openapi/v3/definition/ComponentReleasePayload.yaml b/api/openapi/v3/definition/ComponentReleasePayload.yaml deleted file mode 100644 index fc80da7..0000000 --- a/api/openapi/v3/definition/ComponentReleasePayload.yaml +++ /dev/null @@ -1,67 +0,0 @@ -type: object -required: - - "name" - - "component" -properties: - name: - type: "string" - enabled: - type: "boolean" - namespace: - type: "string" - roles: - type: array - items: - type: string - dependsOn: - type: array - items: - type: string - component: - required: - - "name" - - "version" - properties: - name: - type: "string" - version: - type: "string" - suspended: - type: "boolean" - protected: - type: "boolean" - source: - required: - - "version" - properties: - version: - type: "string" - type: "object" - parameters: - description: List of paramters as key/value pairs - additionalProperties: true - type: "object" - parameterFiles: - type: "array" - items: - type: "object" - properties: - document: - type: "string" - file: - type: "string" - unwrap: - type: "string" - wrap: - type: "string" - values: - description: List of values as key/value pairs - additionalProperties: true - type: "object" - config: - description: Additional configuration - additionalProperties: true - type: "object" - - - diff --git a/api/openapi/v3/definition/ComponentReleaseRequest.yaml b/api/openapi/v3/definition/ComponentReleaseRequest.yaml deleted file mode 100644 index 7f94626..0000000 --- a/api/openapi/v3/definition/ComponentReleaseRequest.yaml +++ /dev/null @@ -1,17 +0,0 @@ -type: object -required: - - "gitRepoFolder" - - "comment" - - "componentReleases" -properties: - gitRepoFolder: - type: "string" - comment: - type: "string" - componentReleases: - type: "array" - items: - $ref: './ComponentReleasePayload.yaml' - - - diff --git a/api/openapi/v3/definition/ComponentReleaseResponse.yaml b/api/openapi/v3/definition/ComponentReleaseResponse.yaml deleted file mode 100644 index 3561c31..0000000 --- a/api/openapi/v3/definition/ComponentReleaseResponse.yaml +++ /dev/null @@ -1,125 +0,0 @@ -type: object -required: - - "kind" - - "spec" - - "status" -properties: - kind: - type: "string" - spec: - required: - - "name" - - "enabled" - - "component" - - "namespace" - - "helmReleaseName__" - - "roles" - - "dependsOn" - properties: - name: - type: "string" - enabled: - type: "boolean" - component: - required: - - "Ref" - - "suspended" - - "protected" - - "Source" - - "parameters" - - "parameterFiles" - - "config" - - "values" - properties: - Ref: - required: - - "Name" - - "Version" - properties: - Name: - type: "string" - Version: - type: "string" - type: "object" - suspended: - type: "boolean" - protected: - type: "boolean" - Source: - required: - - "version" - properties: - version: - type: "string" - type: "object" - parameters: - description: List of paramters as key/value pairs - additionalProperties: true - type: "object" - parameterFiles: - type: "array" - items: - type: "object" - properties: - Document: - type: "string" - File: - type: "string" - Unwrap: - type: "string" - Wrap: - type: "string" - values: - description: List of values as key/value pairs - additionalProperties: true - type: "object" - config: - description: Additional configuration - additionalProperties: true - type: "object" - type: "object" - namespace: - type: "string" - helmReleaseName__: - type: "string" - roles: - type: "array" - items: - type: "string" - dependsOn: - type: "array" - items: - type: "string" - type: "object" - status: - required: - - "file" - - "path" - - "error" - - "parameters" - - "dependencies" - - "usage" - - "catalogs" - properties: - file: - type: "string" - path: - type: "string" - error: - type: "string" - parameters: - description: List of values as key/value pairs - additionalProperties: true - type: "object" - dependencies: - type: "array" - items: - type: "string" - usage: - type: "string" - catalogs: - type: "array" - items: - type: "string" - type: "object" - diff --git a/api/openapi/v3/definition/FlatComponent.yaml b/api/openapi/v3/definition/FlatComponent.yaml deleted file mode 100644 index 592e6d0..0000000 --- a/api/openapi/v3/definition/FlatComponent.yaml +++ /dev/null @@ -1,47 +0,0 @@ -type: "object" -xml: - name: flatComponent -required: -- "packageName" -- "packageVersion" -- "componentName" -- "componentVersion" -- "templateName" -- "templateVersion" -- "componentReleaseName" -- "templateReleaseName" -- "enabled" -- "suspended" -- "protected" -- "catalogs" -- "usage" -properties: - packageName: - type: string - packageVersion: - type: string - componentName: - type: string - componentVersion: - type: string - templateName: - type: string - templateVersion: - type: string - componentReleaseName: - type: string - templateReleaseName: - type: string - enabled: - type: boolean - suspended: - type: boolean - protected: - type: boolean - catalogs: - type: array - items: - type: string - usage: - type: string - default: "" diff --git a/api/openapi/v3/definition/GitCommit.yaml b/api/openapi/v3/definition/GitCommit.yaml index a0c4b8c..c7b02e7 100644 --- a/api/openapi/v3/definition/GitCommit.yaml +++ b/api/openapi/v3/definition/GitCommit.yaml @@ -1,4 +1,6 @@ type: object +xml: + name: GitCommit properties: committerName: type: string diff --git a/api/openapi/v3/definition/GitRepository.yaml b/api/openapi/v3/definition/GitRepository.yaml new file mode 100644 index 0000000..de3bb1c --- /dev/null +++ b/api/openapi/v3/definition/GitRepository.yaml @@ -0,0 +1,30 @@ +type: object +xml: + name: GitRepository +required: +- "repoUrl" +- "ref" +- "name" +- "namespace" +- "path" +- "credentials" +properties: + repoUrl: + type: string + format: uri + x-go-name: repoURL + ref: + type: string + name: + type: string + namespace: + type: string + path: + type: string + credentials: + type: object + required: + - "secretRef" + properties: + secretRef: + type: string diff --git a/api/openapi/v3/definition/KadInstance.yaml b/api/openapi/v3/definition/KadInstance.yaml deleted file mode 100644 index fc13f9f..0000000 --- a/api/openapi/v3/definition/KadInstance.yaml +++ /dev/null @@ -1,23 +0,0 @@ -type: object -xml: - name: kadInstance -required: -- id -- name -- apiUrl -- authBearer -- insecureSkipVerify -properties: - id: - type: string - x-go-name: ID - name: - type: string - apiUrl: - type: string - x-go-name: APIURL - authBearer: - type: string - insecureSkipVerify: - type: boolean - default: true diff --git a/api/openapi/v3/definition/Package.yaml b/api/openapi/v3/definition/Package.yaml new file mode 100644 index 0000000..a574c72 --- /dev/null +++ b/api/openapi/v3/definition/Package.yaml @@ -0,0 +1,20 @@ +type: object +xml: + name: Package +required: +- "name" +- "versions" +- "repoUrl" +properties: + name: + type: string + description: The name of the package + versions: + type: array + items: + type: string + description: A list of versions for the package + repoUrl: + type: string + description: The URL of OCR registry + x-go-name: repoURL diff --git a/api/openapi/v3/definition/Release.yaml b/api/openapi/v3/definition/Release.yaml new file mode 100644 index 0000000..97df61a --- /dev/null +++ b/api/openapi/v3/definition/Release.yaml @@ -0,0 +1,357 @@ +# controller-gen crd paths=./api/v1alpha1 output:crd:dir=./api/schema +description: Release is the Schema for the releases API. +type: object +xml: + name: Release +required: +- "apiVersion" +- "kind" +- "metadata" +- "spec" +properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + description: Standard object metadata. + properties: + name: + type: string + description: Name of the resource. + namespace: + type: string + description: Namespace of the resource. + labels: + type: object + additionalProperties: + type: string + description: Key-value pairs to categorize resources. + annotations: + type: object + additionalProperties: + type: string + description: Arbitrary metadata. + finalizers: + type: array + items: + type: string + description: List of finalizers. + ownerReferences: + type: array + items: + type: object + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + uid: + type: string + description: References to owning resources. + generation: + type: integer + format: int64 + description: Sequence number representing generation of desired state. + creationTimestamp: + type: string + format: date-time + description: Creation timestamp. + deletionTimestamp: + type: string + format: date-time + description: Deletion timestamp. + uid: + type: string + description: Unique ID assigned by Kubernetes. + generateName: + type: string + description: Prefix for generating a unique name. + selfLink: + type: string + description: Deprecated self-link URL. + resourceVersion: + type: string + description: Resource version for concurrency control. + deletionGracePeriodSeconds: + type: integer + format: int64 + description: Seconds allowed for graceful termination. + managedFields: + type: object + description: Managed fields tracking info (complex object). + spec: + description: ReleaseSpec defines the desired state of Release. + properties: + contexts: + description: |- + To provide contextual variables + Refer to Context resource description for some explanation + Contexts are merged in the following order: + - The global default one (defined in Config) + - The namespace context (A context with a specific name, defined in config, present in the release namespace) + - This ordered list + Default: [] + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + type: object + type: array + createNamespace: + description: |- + If true, add { install: { createNamespace: true } } to config map. + Must be set, as used in module.Render() + Default: false + type: boolean + debug: + description: Group a set of parameters useful for debugging Release + and Package + properties: + dumpContext: + description: |- + DumpContext instruct to save a representation of the context + in the Status. This for user debugging? + type: boolean + dumpParameters: + description: |- + DumpParameters instruct to save a representation of the parameters + in the Status. This for user debugging? + type: boolean + type: object + dependencies: + description: |- + The roles we depend on. (appended to the one of the underlying package) + Default: [] + items: + type: string + type: array + description: + description: Short description of this release. Single line only + type: string + package: + description: The package to deploy + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys have + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container + registry. + type: boolean + interval: + default: 5m + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + description: |- + The source will be handled by a child fluxCD OciRepository resource, which will be created by this operator + All following fields will be replicated in this object + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + -kubebuilder:default:=generic + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + repository: + description: Part of OCI url oci://: + type: string + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation + of this source. + type: boolean + tag: + description: Part of OCI url oci://: + type: string + timeout: + default: 60s + description: The timeout for remote OCI Repository operations + like pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign + the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - repository + - tag + type: object + parameters: + description: The Release configuration variables + x-kubernetes-preserve-unknown-fields: true + protected: + description: |- + If true, the webhook will prevent deletion + Default: false + type: boolean + roles: + description: |- + List of roles fulfilled by this release. (appended to the one of the underlying package) + Default: [] + items: + type: string + type: array + skipDefaultContext: + description: |- + If yes, the default context(s) of the configs are not taken in account + ,Default: false + type: boolean + specPatchByModule: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + description: Allow to patch the HelmRelease.spec for each module + type: object + suspended: + description: |- + If true, HelmRelease update is suspended at KuboCD level + (This is NOT the helmRelease.spec.suspend flag, which may be set by Config part) + Default: false + type: boolean + targetNamespace: + description: |- + The namespace to deploy in. (May also be a partial name for a multi-namespaces package) + Not required, as it can be setup another way, depending on the package + (i.e. the package has a fixed namespace, or several ones). + Default: Release.metadata.namespace + type: string + required: + - package + type: object + status: + $ref: './ReleaseStatus.yaml' + diff --git a/api/openapi/v3/definition/ReleaseInfo.yaml b/api/openapi/v3/definition/ReleaseInfo.yaml new file mode 100644 index 0000000..4443caf --- /dev/null +++ b/api/openapi/v3/definition/ReleaseInfo.yaml @@ -0,0 +1,35 @@ +type: object +xml: + name: ReleaseInfo +required: +- "name" +- "package" +- "git" +properties: + name: + type: string + namespace: + type: string + description: + type: string + package: + type: object + required: + - "repository" + - "tag" + properties: + repository: + type: string + tag: + type: string + git: + type: object + required: + - "path" + - "url" + properties: + path: + type: string + url: + type: string + x-go-name: URL diff --git a/api/openapi/v3/definition/ReleaseStatus.yaml b/api/openapi/v3/definition/ReleaseStatus.yaml new file mode 100644 index 0000000..25654cc --- /dev/null +++ b/api/openapi/v3/definition/ReleaseStatus.yaml @@ -0,0 +1,80 @@ +# controller-gen crd paths=./api/v1alpha1 output:crd:dir=./api/schema +description: |- + ReleaseStatus defines the observed state of Release. + As we want Status to be explicit about provided information, we don't use 'omitempty' in its definition. + (Except for 'context', as controlled by a debug flag) +type: object +xml: + name: ReleaseStatus +properties: + context: + description: Context is the resulting context, if requested in debug + options + x-kubernetes-preserve-unknown-fields: true + dependencies: + description: The result of the package template and release value + items: + type: string + type: array + helmReleaseStates: + additionalProperties: + description: HelmReleaseState describe the observed state of a child + HelmRelease + properties: + ready: + type: string + status: + type: string + required: + - ready + type: object + description: HelmReleaseState describe the observed state of child + HelmReleases by name + type: object + missingDependency: + type: string + parameters: + description: Parameters is the resulting parameters set, if requested + in debug options + x-kubernetes-preserve-unknown-fields: true + phase: + type: string + printContexts: + description: |- + PrintContextsContexts is a string to list our context. Not technically used, but intended to be displayed + as printcolumn + type: string + printDescription: + description: |- + PrintDescription + Copy of the release description, or, if empty the (templated) package one + type: string + printProtected: + description: PrintProtected is a copy of Protected, with a Y/n flag. + To be used in display + type: string + protected: + description: |- + Protected result of Release.spec.protected defaulted to package.spec.protected + It is the value checked by the webhook + type: boolean + readyReleases: + description: |- + ReadyReleases is a string to display X/Y helmRelease ready. Not technically used, but intended to be displayed + as printcolumn + type: string + roles: + description: The result of the package template and release value + items: + type: string + type: array + usage: + additionalProperties: + type: string + description: |- + Usage is the rendering of the Package.spec.usage[key]. Aimed to provide user information. + Key could 'html', 'text', some language id, etc... + type: object + + + diff --git a/api/openapi/v3/definition/ServerError.yaml b/api/openapi/v3/definition/ServerError.yaml deleted file mode 100644 index 268d27e..0000000 --- a/api/openapi/v3/definition/ServerError.yaml +++ /dev/null @@ -1,14 +0,0 @@ -type: object -xml: - name: serverError -required: - - message - - status - - type -properties: - message: - type: string - status: - type: integer - type: - type: string diff --git a/api/openapi/v3/definition/ServerResponse.yaml b/api/openapi/v3/definition/ServerResponse.yaml new file mode 100644 index 0000000..e6e126f --- /dev/null +++ b/api/openapi/v3/definition/ServerResponse.yaml @@ -0,0 +1,32 @@ +type: object +xml: + name: ServerResponse +required: + - message + - status + - type +properties: + message: + type: string + description: The response message from the server + status: + type: integer + description: The HTTP status code + type: + type: string + enum: + - okdp_server + - registry + - git_repo + - k8s_cluster + description: The type of the server response +ServerResponseType: + type: string + enum: + - okdp_server + - registry + - git_repo + - k8s_cluster + description: An enum representing different server response types + + diff --git a/api/openapi/v3/definition/Service.yaml b/api/openapi/v3/definition/Service.yaml deleted file mode 100644 index 47eb441..0000000 --- a/api/openapi/v3/definition/Service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -type: object -xml: - name: service -required: -- "name" -- "isComposition" -- "flatComponents" -properties: - name: - type: string - x-order: 1 - isComposition: - type: "boolean" - default: false - x-order: 3 - flatComponents: - type: "array" - x-order: 4 - items: - $ref: './FlatComponent.yaml' - - - diff --git a/api/openapi/v3/definition/TemplateRelease.yaml b/api/openapi/v3/definition/TemplateRelease.yaml deleted file mode 100644 index 4b275fe..0000000 --- a/api/openapi/v3/definition/TemplateRelease.yaml +++ /dev/null @@ -1,73 +0,0 @@ -type: object -xml: - name: templateRelease -required: - - "kind" - - "spec" - - "status" -properties: - kind: - type: "string" - spec: - required: - - "name" - - "template" - - "enabled" - properties: - name: - type: "string" - template: - required: - - "Ref" - - "parameters" - - "parameterFiles" - properties: - Ref: - required: - - "Name" - - "Version" - properties: - Name: - type: "string" - Version: - type: "string" - type: "object" - parameters: - description: List of paramters as key/value pairs - additionalProperties: true - type: "object" - type: "object" - enabled: - type: "boolean" - type: "object" - status: - required: - - "file" - - "path" - - "error" - - "parameters" - - "children" - - "usage" - - "catalogs" - properties: - file: - type: "string" - path: - type: "string" - error: - type: "string" - parameters: - description: List of paramters as key/value pairs - additionalProperties: true - type: "object" - children: - type: "array" - items: - type: "string" - usage: - type: "string" - catalogs: - type: "array" - items: - type: "string" - type: "object" diff --git a/api/openapi/v3/definition/UserProfile.yaml b/api/openapi/v3/definition/UserProfile.yaml index 51df29d..985d654 100644 --- a/api/openapi/v3/definition/UserProfile.yaml +++ b/api/openapi/v3/definition/UserProfile.yaml @@ -1,6 +1,6 @@ type: object xml: - name: userProfile + name: UserProfile required: - sub - login diff --git a/api/openapi/v3/paths/catalogs/catalog-by-name.yaml b/api/openapi/v3/paths/catalogs/catalog-by-id.yaml similarity index 55% rename from api/openapi/v3/paths/catalogs/catalog-by-name.yaml rename to api/openapi/v3/paths/catalogs/catalog-by-id.yaml index 3ef81c0..3eeb306 100644 --- a/api/openapi/v3/paths/catalogs/catalog-by-name.yaml +++ b/api/openapi/v3/paths/catalogs/catalog-by-id.yaml @@ -1,23 +1,17 @@ get: - summary: Get a catalog info by name + summary: Get a catalog by id description: | - Get a catalog info by name + Get a catalog by id tags: - catalogs - operationId: getCatalog + operationId: GetCatalog parameters: - in: path - name: kadInstanceId + name: catalogId schema: type: string required: true - description: KAD instance ID - - in: path - name: name - schema: - type: string - required: true - description: Catalog name + description: Catalog ID responses: '200': description: Catalog information @@ -30,5 +24,5 @@ get: content: application/json: schema: - $ref: '../../definition/ServerError.yaml' + $ref: '../../definition/ServerResponse.yaml' diff --git a/api/openapi/v3/paths/catalogs/catalog-list.yaml b/api/openapi/v3/paths/catalogs/catalog-list.yaml new file mode 100644 index 0000000..c212b02 --- /dev/null +++ b/api/openapi/v3/paths/catalogs/catalog-list.yaml @@ -0,0 +1,23 @@ +get: + summary: List all catalogs + description: | + List all catalogs + tags: + - catalogs + operationId: ListCatalogs + responses: + '200': + description: List of the catalogs + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/Catalog.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/catalogs/catalog.yaml b/api/openapi/v3/paths/catalogs/catalog.yaml deleted file mode 100644 index 3fb37de..0000000 --- a/api/openapi/v3/paths/catalogs/catalog.yaml +++ /dev/null @@ -1,34 +0,0 @@ -get: - summary: List all catalogs - description: | - List all catalogs - tags: - - catalogs - operationId: listCatalogs - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - responses: - '200': - description: List of the catalogs - content: - application/json: - schema: - type: object - required: [catalogs] - properties: - catalogs: - type: array - items: - $ref: '../../definition/Catalog.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/catalogs/package-by-name.yaml b/api/openapi/v3/paths/catalogs/package-by-name.yaml new file mode 100644 index 0000000..9219f68 --- /dev/null +++ b/api/openapi/v3/paths/catalogs/package-by-name.yaml @@ -0,0 +1,34 @@ +get: + summary: Get package by catalog id and package name + description: | + Get package by catalog id and package name + tags: + - catalogs + operationId: GetPackage + parameters: + - in: path + name: catalogId + schema: + type: string + required: true + description: Catalog ID + - in: path + name: name + schema: + type: string + required: true + description: Package name + responses: + '200': + description: Packages information + content: + application/json: + schema: + $ref: '../../definition/Package.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/catalogs/package-definition.yaml b/api/openapi/v3/paths/catalogs/package-definition.yaml new file mode 100644 index 0000000..4b5a70d --- /dev/null +++ b/api/openapi/v3/paths/catalogs/package-definition.yaml @@ -0,0 +1,41 @@ +get: + summary: Get package definition + description: | + Get package definition + tags: + - catalogs + operationId: GetPackageDefinition + parameters: + - in: path + name: catalogId + schema: + type: string + required: true + description: Catalog ID + - in: path + name: name + schema: + type: string + required: true + description: Package name + - in: path + name: version + schema: + type: string + required: true + description: Package version + responses: + '200': + description: Package definition + content: + application/json: + schema: + type: object + additionalProperties: true + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/catalogs/package-list.yaml b/api/openapi/v3/paths/catalogs/package-list.yaml new file mode 100644 index 0000000..7326561 --- /dev/null +++ b/api/openapi/v3/paths/catalogs/package-list.yaml @@ -0,0 +1,30 @@ +get: + summary: Get a list of packages by catalog id + description: | + List of packages by catalog id + tags: + - catalogs + operationId: ListPackages + parameters: + - in: path + name: catalogId + schema: + type: string + required: true + description: Catalog ID + responses: + '200': + description: Packages information + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/Package.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/catalogs/package-schema.yaml b/api/openapi/v3/paths/catalogs/package-schema.yaml new file mode 100644 index 0000000..c84944b --- /dev/null +++ b/api/openapi/v3/paths/catalogs/package-schema.yaml @@ -0,0 +1,41 @@ +get: + summary: Get package schema (parameters, context, etc) + description: | + Get package schema (parameters, context, etc) + tags: + - catalogs + operationId: GetPackageSchema + parameters: + - in: path + name: catalogId + schema: + type: string + required: true + description: Catalog ID + - in: path + name: name + schema: + type: string + required: true + description: Package name + - in: path + name: version + schema: + type: string + required: true + description: Package version + responses: + '200': + description: Package schema + content: + application/json: + schema: + type: object + additionalProperties: true + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/catalogs/package-versions-by-name.yaml b/api/openapi/v3/paths/catalogs/package-versions-by-name.yaml new file mode 100644 index 0000000..41021ca --- /dev/null +++ b/api/openapi/v3/paths/catalogs/package-versions-by-name.yaml @@ -0,0 +1,34 @@ +get: + summary: List versions for a specific package + description: | + List versions for a specific package + tags: + - catalogs + operationId: GetPackageVersions + parameters: + - in: path + name: catalogId + schema: + type: string + required: true + description: Catalog ID + - in: path + name: name + schema: + type: string + required: true + description: Package name + responses: + '200': + description: Package versions + content: + application/json: + schema: + $ref: '../../definition/Package.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/clusters/cluster-by-id.yaml b/api/openapi/v3/paths/clusters/cluster-by-id.yaml new file mode 100644 index 0000000..78a1fc7 --- /dev/null +++ b/api/openapi/v3/paths/clusters/cluster-by-id.yaml @@ -0,0 +1,28 @@ +get: + summary: Get a kubernetes cluster by id + description: | + Get a kubernetes cluster by id + tags: + - clusters + operationId: GetCluster + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Cluster ID + responses: + '200': + description: Cluster information + content: + application/json: + schema: + $ref: '../../definition/Cluster.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/clusters/cluster-list.yaml b/api/openapi/v3/paths/clusters/cluster-list.yaml new file mode 100644 index 0000000..e803e7d --- /dev/null +++ b/api/openapi/v3/paths/clusters/cluster-list.yaml @@ -0,0 +1,23 @@ +get: + summary: List all kubernetes clusters + description: | + List all kubernetes clusters + tags: + - clusters + operationId: ListClusters + responses: + '200': + description: List of the clusters + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/Cluster.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/clusters/namespace-by-name.yaml b/api/openapi/v3/paths/clusters/namespace-by-name.yaml new file mode 100644 index 0000000..37d4b61 --- /dev/null +++ b/api/openapi/v3/paths/clusters/namespace-by-name.yaml @@ -0,0 +1,34 @@ +get: + summary: Get a kubernetes namespace by name + description: | + Get a kubernetes namespace by name + tags: + - clusters + operationId: GetNamespace + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + responses: + '200': + description: Namespace information + content: + application/json: + schema: + type: string + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/clusters/namespace-list.yaml b/api/openapi/v3/paths/clusters/namespace-list.yaml new file mode 100644 index 0000000..1445423 --- /dev/null +++ b/api/openapi/v3/paths/clusters/namespace-list.yaml @@ -0,0 +1,29 @@ +get: + summary: List all kubernetes namespaces + description: | + List all kubernetes namespaces + tags: + - clusters + operationId: ListNamespaces + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Cluster ID + responses: + '200': + description: List of the namespaces + content: + application/json: + schema: + type: array + items: + type: string + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' \ No newline at end of file diff --git a/api/openapi/v3/paths/componentreleases/component-releases-by-name.yaml b/api/openapi/v3/paths/componentreleases/component-releases-by-name.yaml deleted file mode 100644 index 9e5ef56..0000000 --- a/api/openapi/v3/paths/componentreleases/component-releases-by-name.yaml +++ /dev/null @@ -1,88 +0,0 @@ -get: - summary: Get a component release by name - description: | - Get a component release by name - tags: - - componentreleases - operationId: getComponentRelease - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: path - name: name - schema: - type: string - required: true - description: Component release name - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: Component release information - content: - application/json: - schema: - $ref: '../../definition/ComponentReleaseResponse.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - - -put: - summary: Create or update a component release - description: | - Create or update a component release - tags: - - componentreleases - operationId: createOrUpdateComponentRelease - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: path - name: name - schema: - type: string - required: true - description: Component release name - requestBody: - description: Component release payload - required: true - content: - application/json: - schema: - $ref: '../../definition/ComponentReleaseRequest.yaml' - responses: - '200': - description: Commit updated successfully - content: - application/json: - schema: - $ref: '../../definition/GitCommit.yaml' - '201': - description: Commit created successfully - content: - application/json: - schema: - $ref: '../../definition/GitCommit.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/componentreleases/component-releases.yaml b/api/openapi/v3/paths/componentreleases/component-releases.yaml deleted file mode 100644 index 08faf76..0000000 --- a/api/openapi/v3/paths/componentreleases/component-releases.yaml +++ /dev/null @@ -1,41 +0,0 @@ -get: - summary: List all component releases - description: | - todo - tags: - - componentreleases - operationId: listComponentReleases - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: List of the component releases - content: - application/json: - schema: - type: object - required: [componentreleases] - properties: - componentreleases: - type: array - items: - $ref: '../../definition/ComponentReleaseResponse.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - - diff --git a/api/openapi/v3/paths/components/component-by-name.yaml b/api/openapi/v3/paths/components/component-by-name.yaml deleted file mode 100644 index 5913e5f..0000000 --- a/api/openapi/v3/paths/components/component-by-name.yaml +++ /dev/null @@ -1,46 +0,0 @@ -get: - summary: Get a components by name - description: | - Get a components by name - tags: - - components - operationId: getComponentsByName - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: path - name: name - schema: - type: string - required: true - description: Component name - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: List of components by name - content: - application/json: - schema: - type: object - required: [components] - properties: - components: - type: array - items: - $ref: '../../definition/Component.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/components/component.yaml b/api/openapi/v3/paths/components/component.yaml deleted file mode 100644 index a26a802..0000000 --- a/api/openapi/v3/paths/components/component.yaml +++ /dev/null @@ -1,40 +0,0 @@ -get: - summary: List all components - description: | - List all components - tags: - - components - operationId: listComponents - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: List of the components - content: - application/json: - schema: - type: object - required: [components] - properties: - components: - type: array - items: - $ref: '../../definition/Component.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/k8s/release-by-name.yaml b/api/openapi/v3/paths/k8s/release-by-name.yaml new file mode 100644 index 0000000..c8ccca6 --- /dev/null +++ b/api/openapi/v3/paths/k8s/release-by-name.yaml @@ -0,0 +1,82 @@ +get: + summary: Get the deployed release by name + description: | + Get the deployed release by name + tags: + - k8s + operationId: GetK8sRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + - in: path + name: releaseName + schema: + type: string + required: true + description: KuboCD release name + responses: + '200': + description: KuboCD Release info + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + +delete: + summary: Delete the KuboCD release in kubernetes + description: | + Delete the KuboCD release in kubernetes + tags: + - k8s + operationId: DeleteK8sRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + - in: path + name: releaseName + schema: + type: string + required: true + description: KuboCD release name + responses: + '200': + description: KuboCD Release deleted successfully + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/k8s/release-status.yaml b/api/openapi/v3/paths/k8s/release-status.yaml new file mode 100644 index 0000000..a021c6f --- /dev/null +++ b/api/openapi/v3/paths/k8s/release-status.yaml @@ -0,0 +1,41 @@ +get: + summary: Get the release status + description: | + Get the release status + tags: + - k8s + operationId: GetK8sReleaseStatus + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + - in: path + name: releaseName + schema: + type: string + required: true + description: KuboCD release name + responses: + '200': + description: KuboCD Release info + content: + application/json: + schema: + $ref: '../../definition/ReleaseStatus.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/k8s/releases.yaml b/api/openapi/v3/paths/k8s/releases.yaml new file mode 100644 index 0000000..21aab7d --- /dev/null +++ b/api/openapi/v3/paths/k8s/releases.yaml @@ -0,0 +1,136 @@ +get: + summary: Get the list of the deployed releases + description: | + Get the list of the deployed releases + tags: + - k8s + operationId: ListK8sReleases + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + responses: + '200': + description: Release list + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/Release.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + +post: + summary: Create KuboCD release in Kubernetes + description: | + Create KuboCD release in Kubernetes + tags: + - k8s + operationId: CreateK8sRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + - in: query + name: dryRun + schema: + type: boolean + required: false + description: If true, performs a server-side dry run without persisting the resource + requestBody: + description: Release object to be created + required: true + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + responses: + '201': + description: Release created successfully + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + +put: + summary: Update KuboCD release in Kubernetes + description: | + Update KuboCD release in Kubernetes + tags: + - k8s + operationId: UpdateK8sRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes namespace + - in: query + name: dryRun + schema: + type: boolean + required: false + description: If true, performs a server-side dry run without persisting the resource + requestBody: + description: Release object to be updated + required: true + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + responses: + '200': + description: Release updated successfully + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' \ No newline at end of file diff --git a/api/openapi/v3/paths/kad/kad-instance-by-name.yaml b/api/openapi/v3/paths/kad/kad-instance-by-name.yaml deleted file mode 100644 index ebc7a8b..0000000 --- a/api/openapi/v3/paths/kad/kad-instance-by-name.yaml +++ /dev/null @@ -1,33 +0,0 @@ -get: - summary: Get KAD instance by name - description: Get KAD instance by name - tags: - - kad - operationId: getKadInstance - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - responses: - '200': - description: KAD instance configuration - content: - application/json: - schema: - type: object - required: [instances] - properties: - instances: - type: array - items: - $ref: '../../definition/KadInstance.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/kad/kad-instance.yaml b/api/openapi/v3/paths/kad/kad-instance.yaml deleted file mode 100644 index a98c9b2..0000000 --- a/api/openapi/v3/paths/kad/kad-instance.yaml +++ /dev/null @@ -1,26 +0,0 @@ -get: - summary: List all KAD configured instances - description: List all KAD configured instances - tags: - - kad - operationId: listKadInstances - responses: - '200': - description: List of KAD instances - content: - application/json: - schema: - type: object - required: [instances] - properties: - instances: - type: array - items: - $ref: '../../definition/KadInstance.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/repositories/release-by-name.yaml b/api/openapi/v3/paths/repositories/release-by-name.yaml new file mode 100644 index 0000000..3eeb936 --- /dev/null +++ b/api/openapi/v3/paths/repositories/release-by-name.yaml @@ -0,0 +1,99 @@ +get: + summary: Return KuboCD release by name in the git repo + description: | + Return KuboCD release by name in the git repo + tags: + - repositories + operationId: GetGitRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: releases-system + - in: path + name: releaseName + schema: + type: string + required: true + description: KuboCD release name + example: podinfo + responses: + '200': + description: KuboCD Release info + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + +delete: + summary: Delete KuboCD release by name in the git repo + description: | + Delete KuboCD release by name in the git repo + tags: + - repositories + operationId: DeleteGitRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: releases-system + - in: path + name: releaseName + schema: + type: string + required: true + description: KuboCD release name + example: podinfo + responses: + '200': + description: KuboCD Release deleted successfully + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' \ No newline at end of file diff --git a/api/openapi/v3/paths/repositories/releases.yaml b/api/openapi/v3/paths/repositories/releases.yaml new file mode 100644 index 0000000..2e700a3 --- /dev/null +++ b/api/openapi/v3/paths/repositories/releases.yaml @@ -0,0 +1,153 @@ +get: + summary: Return list of releases in the git repo + description: | + Return list of releases in the git repo + tags: + - repositories + operationId: ListGitReleases + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: releases-system + responses: + '200': + description: Release list + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/ReleaseInfo.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + + +post: + summary: Create a new KuboCD release in the git repo + description: | + Create a new KuboCD release in the git repo + tags: + - repositories + operationId: CreateGitRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: releases-system + requestBody: + description: Release object to be created + required: true + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + responses: + '201': + description: Release created successfully + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + +put: + summary: Update an existing KuboCD release in the git repo + description: | + Update an existing KuboCD release in the git repo + tags: + - repositories + operationId: UpdateGitRelease + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: releases-system + requestBody: + description: Release object to be updated + required: true + content: + application/json: + schema: + $ref: '../../definition/Release.yaml' + responses: + '200': + description: Release updated successfully + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/ServerResponse.yaml' + + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + + + + \ No newline at end of file diff --git a/api/openapi/v3/paths/repositories/repo-by-name.yaml b/api/openapi/v3/paths/repositories/repo-by-name.yaml new file mode 100644 index 0000000..fb8b144 --- /dev/null +++ b/api/openapi/v3/paths/repositories/repo-by-name.yaml @@ -0,0 +1,42 @@ +get: + summary: Return a git repo details + description: | + Return a git repo details + tags: + - repositories + operationId: GetGitRepo + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + - in: path + name: kustomizationName + schema: + type: string + required: true + description: Kubernetes fluxcd git repo name + example: podinfo + responses: + '200': + description: Git repo information + content: + application/json: + schema: + $ref: '../../definition/GitRepository.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/repositories/repo-list.yaml b/api/openapi/v3/paths/repositories/repo-list.yaml new file mode 100644 index 0000000..430891e --- /dev/null +++ b/api/openapi/v3/paths/repositories/repo-list.yaml @@ -0,0 +1,37 @@ +get: + summary: List all configured git repositories + description: | + List all configured git repositories + tags: + - repositories + operationId: ListGitRepos + parameters: + - in: path + name: clusterId + schema: + type: string + required: true + description: Kubernetes cluster ID + - in: path + name: namespace + schema: + type: string + required: true + description: Kubernetes fluxcd git repo namespace + example: flux-system + responses: + '200': + description: List of the git repositories + content: + application/json: + schema: + type: array + items: + $ref: '../../definition/GitRepository.yaml' + default: + description: Server error + content: + application/json: + schema: + $ref: '../../definition/ServerResponse.yaml' + diff --git a/api/openapi/v3/paths/services/service.yaml b/api/openapi/v3/paths/services/service.yaml deleted file mode 100644 index acfd1f4..0000000 --- a/api/openapi/v3/paths/services/service.yaml +++ /dev/null @@ -1,40 +0,0 @@ -get: - summary: List all services - description: | - List all services - tags: - - services - operationId: listServices - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: List of the services - content: - application/json: - schema: - type: object - required: [services] - properties: - services: - type: array - items: - $ref: '../../definition/Service.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/templatereleases/template-releases-by-name.yaml b/api/openapi/v3/paths/templatereleases/template-releases-by-name.yaml deleted file mode 100644 index cd648ad..0000000 --- a/api/openapi/v3/paths/templatereleases/template-releases-by-name.yaml +++ /dev/null @@ -1,40 +0,0 @@ -get: - summary: Get a template release by name - description: | - Get a template release by name - tags: - - templatereleases - operationId: getTemplateRelease - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: path - name: name - schema: - type: string - required: true - description: Template release name - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: Template release information - content: - application/json: - schema: - $ref: '../../definition/TemplateRelease.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/templatereleases/template-releases.yaml b/api/openapi/v3/paths/templatereleases/template-releases.yaml deleted file mode 100644 index 94be0ab..0000000 --- a/api/openapi/v3/paths/templatereleases/template-releases.yaml +++ /dev/null @@ -1,40 +0,0 @@ -get: - summary: List all template releases - description: | - List all template releases - tags: - - templatereleases - operationId: listTemplateReleases - parameters: - - in: path - name: kadInstanceId - schema: - type: string - required: true - description: KAD instance ID - - in: query - name: catalog - schema: - type: string - required: false - description: Filter by catalogs (comma separated) - responses: - '200': - description: List of template releases - content: - application/json: - schema: - type: object - required: [templatereleases] - properties: - templatereleases: - type: array - items: - $ref: '../../definition/TemplateRelease.yaml' - default: - description: Server error - content: - application/json: - schema: - $ref: '../../definition/ServerError.yaml' - diff --git a/api/openapi/v3/paths/users/user-profile.yaml b/api/openapi/v3/paths/users/user-profile.yaml index e8060f8..a970e26 100644 --- a/api/openapi/v3/paths/users/user-profile.yaml +++ b/api/openapi/v3/paths/users/user-profile.yaml @@ -4,7 +4,7 @@ get: Get my user profile tags: - users - operationId: getMyProfile + operationId: GetMyProfile responses: '200': description: My user profile @@ -21,5 +21,5 @@ get: content: application/json: schema: - $ref: '../../definition/ServerError.yaml' + $ref: '../../definition/ServerResponse.yaml' diff --git a/cmd/root.go b/cmd/root.go index 9d18195..93da255 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,9 +19,9 @@ package cmd import ( "os" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - log "github.com/okdp/okdp-server/internal/logging" "github.com/okdp/okdp-server/internal/server" "github.com/spf13/cobra" "github.com/spf13/viper" diff --git a/docker-compose.yml b/docker-compose.yml index 42882a4..1004f73 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,8 +28,12 @@ services: - .local:/workspace/.local - .go-cache/go-build:/go-build - .go-cache/go-mod:/go/pkg + - ~/.kube/config:/tmp/.kube/config:ro working_dir: /workspace environment: + - OCI_USERNAME=${OCI_USERNAME} + - OCI_PASSWORD=${OCI_PASSWORD} + - DOCKER_CONFIG_JSON=${DOCKER_CONFIG_JSON} - GOCACHE=/go-build - GOMODCACHE=/go/pkg depends_on: diff --git a/go.mod b/go.mod index 3631146..c1f6a24 100644 --- a/go.mod +++ b/go.mod @@ -1,87 +1,135 @@ module github.com/okdp/okdp-server -go 1.23.0 +go 1.24.0 -toolchain go1.23.6 +require kubocd v0.2.1 + +replace kubocd => github.com/kubocd/kubocd v0.2.1 require ( - github.com/casbin/casbin/v2 v2.103.0 - github.com/coreos/go-oidc/v3 v3.12.0 - github.com/fsnotify/fsnotify v1.8.0 - github.com/getkin/kin-openapi v0.129.0 - github.com/gin-contrib/cors v1.7.3 - github.com/gin-contrib/sessions v1.0.2 - github.com/gin-contrib/zap v1.1.4 + github.com/Masterminds/semver/v3 v3.3.1 + github.com/casbin/casbin/v2 v2.105.0 + github.com/coreos/go-oidc/v3 v3.14.1 + github.com/fluxcd/kustomize-controller/api v1.5.1 + github.com/fluxcd/source-controller/api v1.5.0 + github.com/fsnotify/fsnotify v1.9.0 + github.com/getkin/kin-openapi v0.132.0 + github.com/gin-contrib/cors v1.7.5 + github.com/gin-contrib/sessions v1.0.3 + github.com/gin-contrib/zap v1.1.5 github.com/gin-gonic/gin v1.10.0 - github.com/go-resty/resty/v2 v2.16.5 - github.com/goccy/go-yaml v1.15.23 + github.com/go-git/go-billy/v5 v5.6.2 + github.com/go-git/go-git/v5 v5.16.0 github.com/oapi-codegen/runtime v1.1.1 + github.com/opencontainers/image-spec v1.1.1 + github.com/skeema/knownhosts v1.3.1 github.com/spf13/cobra v1.9.1 - github.com/spf13/viper v1.19.0 + github.com/spf13/viper v1.20.1 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 go.uber.org/zap v1.27.0 - golang.org/x/net v0.35.0 - golang.org/x/oauth2 v0.26.0 + golang.org/x/net v0.40.0 + golang.org/x/oauth2 v0.30.0 + k8s.io/api v0.33.0 + k8s.io/apimachinery v0.33.0 + k8s.io/client-go v0.33.0 + oras.land/oras-go/v2 v2.6.0 + sigs.k8s.io/controller-runtime v0.20.4 + sigs.k8s.io/yaml v1.4.0 ) require ( + dario.cat/mergo v1.0.2 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProtonMail/go-crypto v1.2.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect - github.com/bytedance/sonic v1.12.8 // indirect - github.com/bytedance/sonic/loader v0.2.3 // indirect - github.com/casbin/govaluate v1.3.0 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/casbin/govaluate v1.4.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect - github.com/gin-contrib/sse v1.0.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.4 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/fluxcd/pkg/apis/acl v0.7.0 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.10.0 // indirect + github.com/fluxcd/pkg/apis/meta v1.11.0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-jose/go-jose/v4 v4.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.25.0 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.4.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/magiconair/properties v1.8.9 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8 // indirect - github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect - github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/afero v1.14.0 // indirect + github.com/spf13/cast v1.8.0 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/arch v0.14.0 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/exp v0.0.0-20250215185904-eff6e970281f // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + golang.org/x/arch v0.17.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.33.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.33.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect ) diff --git a/go.sum b/go.sum index a847fb7..da24bc4 100644 --- a/go.sum +++ b/go.sum @@ -1,76 +1,139 @@ +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs= +github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bytedance/sonic v1.12.8 h1:4xYRVRlXIgvSZ4e8iVTlMF5szgpXd4AfvuWgA8I8lgs= -github.com/bytedance/sonic v1.12.8/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0= -github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= -github.com/casbin/casbin/v2 v2.103.0 h1:dHElatNXNrr8XcseUov0ZSiWjauwmZZE6YMV3eU1yic= -github.com/casbin/casbin/v2 v2.103.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= -github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/casbin/casbin/v2 v2.105.0 h1:dLj5P6pLApBRat9SADGiLxLZjiDPvA1bsPkyV4PGx6I= +github.com/casbin/casbin/v2 v2.105.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/casbin/govaluate v1.4.0 h1:/pjx3ssi/U1qXAomngy8aNErQXDazBChu02QEbQgIj4= +github.com/casbin/govaluate v1.4.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo= -github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= +github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk= +github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/fluxcd/kustomize-controller/api v1.5.1 h1:SLVMIk/3E/GkK610S85zDBfX/TQhpE2ym+516ONXtU4= +github.com/fluxcd/kustomize-controller/api v1.5.1/go.mod h1:SnQ5blin2e25GOCvd9JqYezYhqcM7beyK1aLq9Iw0So= +github.com/fluxcd/pkg/apis/acl v0.7.0 h1:dMhZJH+g6ZRPjs4zVOAN9vHBd1DcavFgcIFkg5ooOE0= +github.com/fluxcd/pkg/apis/acl v0.7.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ= +github.com/fluxcd/pkg/apis/kustomize v1.10.0 h1:47EeSzkQvlQZdH92vHMe2lK2iR8aOSEJq95avw5idts= +github.com/fluxcd/pkg/apis/kustomize v1.10.0/go.mod h1:UsqMV4sqNa1Yg0pmTsdkHRJr7bafBOENIJoAN+3ezaQ= +github.com/fluxcd/pkg/apis/meta v1.11.0 h1:h8q95k6ZEK1HCfsLkt8Np3i6ktb6ZzcWJ6hg++oc9w0= +github.com/fluxcd/pkg/apis/meta v1.11.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI= +github.com/fluxcd/source-controller/api v1.5.0 h1:caSR+u/r2Vh0jq/0pNR0r1zLxyvgatWuGSV2mxgTB/I= +github.com/fluxcd/source-controller/api v1.5.0/go.mod h1:OZPuHMlLH2E2mnj6Q5DLkWfUOmJ20zA1LIvUVfNsYl8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30= -github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= -github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= -github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= -github.com/gin-contrib/sessions v1.0.2 h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA= -github.com/gin-contrib/sessions v1.0.2/go.mod h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs= -github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= -github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= -github.com/gin-contrib/zap v1.1.4 h1:xvxTybg6XBdNtcQLH3Tf0lFr4vhDkwzgLLrIGlNTqIo= -github.com/gin-contrib/zap v1.1.4/go.mod h1:7lgEpe91kLbeJkwBTPgtVBy4zMa6oSBEcvj662diqKQ= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk= +github.com/gin-contrib/cors v1.7.5/go.mod h1:4q3yi7xBEDDWKapjT2o1V7mScKDDr8k+jZ0fSquGoy0= +github.com/gin-contrib/sessions v1.0.3 h1:AZ4j0AalLsGqdrKNbbrKcXx9OJZqViirvNGsJTxcQps= +github.com/gin-contrib/sessions v1.0.3/go.mod h1:5i4XMx4KPtQihnzxEqG9u1K446lO3G19jAi2GtbfsAI= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-contrib/zap v1.1.5 h1:qKwhWb4DQgPriCl1AHLLob6hav/KUIctKXIjTmWIN3I= +github.com/gin-contrib/zap v1.1.5/go.mod h1:lAchUtGz9M2K6xDr1rwtczyDrThmSx6c9F384T45iOE= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= -github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ= +github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY= +github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= -github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= -github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= -github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo= -github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= @@ -79,33 +142,38 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubocd/kubocd v0.2.1 h1:2IVRs85zqznXz9pEe9yiwuIdjcrVpWlzzLdRqvzyZxk= +github.com/kubocd/kubocd v0.2.1/go.mod h1:ICIRAAcJaK2tIXObQH6LSAUFmgKYzZZU9XqKWaEjnhM= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -113,49 +181,68 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= -github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8 h1:9djga8U4+/TQzv5iMlZHZ/qbGQB9V2nlnk2bmiG+uBs= -github.com/oasdiff/yaml v0.0.0-20241214135536-5f7845c759c8/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8= -github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672 h1:+273wgr7to5QhwOOBE5LwjdNDFAI+8cbJVfB0Zj75aI= -github.com/oasdiff/yaml3 v0.0.0-20241214160948-977117996672/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= +github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= +github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk= +github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -171,43 +258,118 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4= -golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= +golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg= -golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= +k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= +k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs= +k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc= +k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= +k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= +k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg= +k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= +oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/helm/okdp-server/Chart.yaml b/helm/okdp-server/Chart.yaml index cd9bf9d..c123ff0 100644 --- a/helm/okdp-server/Chart.yaml +++ b/helm/okdp-server/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: okdp-server description: A Helm chart for okdp-server type: application -version: 0.1.0 -appVersion: "0.1.0" +version: 0.2.0-snapshot +appVersion: "0.2.0-snapshot" home: https://okdp.io maintainers: - email: idir.izitounene@kubotal.io diff --git a/helm/okdp-server/README.md b/helm/okdp-server/README.md index 75e28e8..0d74a4a 100644 --- a/helm/okdp-server/README.md +++ b/helm/okdp-server/README.md @@ -1,6 +1,6 @@ # okdp-server -![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) +![Version: 0.2.0-snapshot](https://img.shields.io/badge/Version-0.2.0--snapshot-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.2.0-snapshot](https://img.shields.io/badge/AppVersion-0.2.0--snapshot-informational?style=flat-square) A Helm chart for okdp-server @@ -31,11 +31,18 @@ A Helm chart for okdp-server | autoscaling.maxReplicas | int | `100` | | | autoscaling.minReplicas | int | `1` | | | autoscaling.targetCPUUtilizationPercentage | int | `80` | | -| configuration.kad[0] | object | `{"apiUrl":"","authBearer":"","id":"sandbox","insecureSkipVerify":true,"name":"Poc Sandbox"}` | Specify any ID. | -| configuration.kad[0].apiUrl | string | `""` | Specify KAD API URL. | -| configuration.kad[0].authBearer | string | `""` | Specify KAD AUTH Bearer. | -| configuration.kad[0].insecureSkipVerify | bool | `true` | Wether to skip the certificate validation. | -| configuration.kad[0].name | string | `"Poc Sandbox"` | Specify any name. | +| configuration.catalog | list | `[{"description":"My Storage packages","id":"storage","name":"Storage catalog","packages":[{"name":"redis"},{"name":"minio"},{"name":"cnpg"}],"repoUrl":"quay.io/kubocd/packages"},{"description":"My Auth packages","id":"auth","name":"Auth catalog","packages":[{"name":"openldap"}],"repoUrl":"quay.io/kubocd/packages"},{"description":"My Infra packages","id":"infra","name":"Infra catalog","packages":[{"name":"cert-manager"},{"name":"ingress-nginx"},{"name":"metallb"}],"repoUrl":"quay.io/kubocd/packages"},{"description":"My Stack packages","id":"stack","name":"Stack catalog","packages":[{"name":"podinfo"}],"repoUrl":"quay.io/kubocd/packages"}]` | List of catalogs available to this chart | +| configuration.catalog[0] | object | `{"description":"My Storage packages","id":"storage","name":"Storage catalog","packages":[{"name":"redis"},{"name":"minio"},{"name":"cnpg"}],"repoUrl":"quay.io/kubocd/packages"}` | Unique identifier for the catalog | +| configuration.catalog[0].description | string | `"My Storage packages"` | Description of the catalog's purpose | +| configuration.catalog[0].name | string | `"Storage catalog"` | Human-readable name of the catalog | +| configuration.catalog[0].packages | list | `[{"name":"redis"},{"name":"minio"},{"name":"cnpg"}]` | List of packages under this catalog | +| configuration.catalog[0].packages[0] | object | `{"name":"redis"}` | Name of the package | +| configuration.catalog[0].repoUrl | string | `"quay.io/kubocd/packages"` | OCI registry URL to pull packages from | +| configuration.clusters | list | `[{"auth":{"inCluster":true},"env":"dev","id":"kubo2","name":"My k8s cluster 1"}]` | List of Kubernetes clusters this chart will interact with | +| configuration.clusters[0] | object | `{"auth":{"inCluster":true},"env":"dev","id":"kubo2","name":"My k8s cluster 1"}` | Unique identifier for the cluster | +| configuration.clusters[0].auth.inCluster | bool | `true` | Use in-cluster authentication | +| configuration.clusters[0].env | string | `"dev"` | Environment tag (e.g., dev, staging, prod) | +| configuration.clusters[0].name | string | `"My k8s cluster 1"` | Human-readable name for the cluster | | configuration.logging.format | string | `"console"` | Specify the logging format. One of `console` or `json`. | | configuration.logging.level | string | `"debug"` | Specify the logging level. One of `debug`, `info`, `warn`, `error`, `fatal` or `panic`. | | configuration.security.authN.bearer.groupsAttributePath | string | `"realm_access.groups"` | Specify the groups attribute path from json access token. | @@ -45,7 +52,7 @@ A Helm chart for okdp-server | configuration.security.authN.bearer.skipIssuerCheck | bool | `false` | Wether to skip issuer check. | | configuration.security.authN.bearer.skipSignatureCheck | bool | `false` | Wether to skip issuer signature check. | | configuration.security.authN.provider | list | `["bearer"]` | Specify the oidc privider. One of `openid` or `bearer`. | -| configuration.security.authZ.inline | object | `{"model":"[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == \"*\")\n","policy":"p, role:viewers, /api/v1/users/myprofile, *\np, role:viewers, /api/v1/kad, *\np, role:viewers, /api/v1/kad/*/services, *\np, role:viewers, /api/v1/kad/*/catalog, *\np, role:viewers, /api/v1/kad/*/catalog/*, *\np, role:viewers, /api/v1/kad/*/componentreleases, *\np, role:viewers, /api/v1/kad/*/componentreleases/*, *\np, role:viewers, /api/v1/kad/*/templatereleases, *\np, role:viewers, /api/v1/kad/*/templatereleases/*, *\np, role:viewers, /api/v1/kad/*/components, *\np, role:viewers, /api/v1/kad/*/components/*, *\n\ng, role:admins, role:developers\ng, role:developers, role:viewers\n"}` | More info: https://casbin.org/docs/how-it-works/ file: modelPath: ".local/authz-model.conf" policyPath: ".local/authz-policy.csv" | +| configuration.security.authZ.inline | object | `{"model":"[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == \"*\")\n","policy":"p, role:viewers, /api/v1/users/myprofile, *\np, role:viewers, /api/v1/catalogs, *\np, role:viewers, /api/v1/catalogs/*, *\n\np, role:viewers, /api/v1/clusters, *\np, role:viewers, /api/v1/clusters/*/gitrepos, *\np, role:viewers, /api/v1/clusters/*/gitrepos/*, *\n\ng, role:admins, role:developers\ng, role:developers, role:viewers\n"}` | More info: https://casbin.org/docs/how-it-works/ file: modelPath: ".local/authz-model.conf" policyPath: ".local/authz-policy.csv" | | configuration.security.authZ.inline.model | string | `"[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == \"*\")\n"` | More info: https://casbin.org/docs/how-it-works/ | | configuration.security.authZ.provider | string | `"inline"` | Specify the authZ storage provider. One of `inline` or `file`. | | configuration.security.cors.allowCredentials | bool | `true` | Determine whether cookies and authentication credentials should be included in cross-origin requests. | @@ -73,7 +80,7 @@ A Helm chart for okdp-server | fullnameOverride | string | `""` | Overrides the release name. | | image.pullPolicy | string | `"Always"` | Image pull policy. | | image.repository | string | `"quay.io/okdp/okdp-server"` | Docker image registry. | -| image.tag | string | `"0.1.0"` | Image tag. | +| image.tag | string | `"0.2.0"` | Image tag. | | imagePullSecrets | list | `[]` | Secrets to be used for pulling images from private Docker registries. | | ingress.annotations | object | `{}` | | | ingress.className | string | `""` | Specify the ingress class (Kubernetes >= 1.18). | @@ -88,6 +95,8 @@ A Helm chart for okdp-server | podAnnotations | object | `{}` | Additional annotations for the okdp-server pod. | | podLabels | object | `{}` | Additional labels for the okdp-server pod. | | podSecurityContext | object | `{}` | | +| rbac.annotations | object | `{}` | Specify annotations for the proxy. | +| rbac.create | bool | `true` | Specify whether a RBAC should be created | | readinessProbe | object | `{"httpGet":{"path":"/readiness","port":"http"}}` | Readiness probe for the okdp-server container. | | replicaCount | int | `1` | Desired number of okdp-server pods to run. | | resources | object | `{}` | | @@ -95,8 +104,8 @@ A Helm chart for okdp-server | service.port | int | `8090` | | | service.type | string | `"ClusterIP"` | | | serviceAccount.annotations | object | `{}` | Annotations to add to the service account | -| serviceAccount.automount | bool | `false` | Automatically mount a ServiceAccount's API credentials? | -| serviceAccount.create | bool | `false` | Specify whether a service account should be created | +| serviceAccount.automount | bool | `true` | Automatically mount a ServiceAccount's API credentials? | +| serviceAccount.create | bool | `true` | Specify whether a service account should be created | | serviceAccount.name | string | `""` | If not set and create is true, a name is generated using the fullname template | | swagger-ui.configuration.extraEnv | list | `[{"name":"BASE_URL","value":"/"},{"name":"URLS","value":null},{"name":"OAUTH_CLIENT_ID","value":null},{"name":"OAUTH_SCOPES","value":"openid profile email roles"},{"name":"OAUTH_USE_PKCE","value":true},{"name":"CORS_ENABLED","value":true}]` | Specify swagger configuration with environment variables (https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/) | | swagger-ui.configuration.extraEnv[0] | object | `{"name":"BASE_URL","value":"/"}` | Specify base url. | diff --git a/helm/okdp-server/templates/NOTES.txt b/helm/okdp-server/templates/NOTES.txt index acfb453..e7caee9 100644 --- a/helm/okdp-server/templates/NOTES.txt +++ b/helm/okdp-server/templates/NOTES.txt @@ -2,7 +2,8 @@ {{- if .Values.ingress.enabled }} {{- range $host := .Values.ingress.hosts }} {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + https{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + https{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}/swagger {{- end }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} diff --git a/helm/okdp-server/templates/rbac.yaml b/helm/okdp-server/templates/rbac.yaml new file mode 100644 index 0000000..0a1026a --- /dev/null +++ b/helm/okdp-server/templates/rbac.yaml @@ -0,0 +1,43 @@ +{{- if .Values.rbac.create -}} +# Refine later +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "okdp-server.fullname" . }} + {{- with .Values.rbac.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "okdp-server.labels" . | nindent 4 }} +rules: +- apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' +- nonResourceURLs: + - '*' + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "okdp-server.fullname" . }} + {{- with .Values.rbac.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "okdp-server.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "okdp-server.serviceAccountName" $ }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "okdp-server.fullname" $ }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/helm/okdp-server/values.keycloak.yaml b/helm/okdp-server/values.keycloak.yaml index a48dc77..96a0f26 100644 --- a/helm/okdp-server/values.keycloak.yaml +++ b/helm/okdp-server/values.keycloak.yaml @@ -1,4 +1,74 @@ configuration: + # -- List of Kubernetes clusters this chart will interact with + clusters: + - id: kubo2 # -- Unique identifier for the cluster + name: "My k8s cluster 1" # -- Human-readable name for the cluster + env: dev # -- Environment tag (e.g., dev, staging, prod) + + auth: + # -- Use in-cluster authentication + inCluster: true + + # kubeconfig: + # apiServer: https://host.docker.internal:56660 # -- Kubernetes API server address + # path: /tmp/.kube/config # -- Path to the kubeconfig file + # # context: kind-kind-okdp-sandbox # -- Optional: specify kubeconfig context to use + # insecureSkipTlsVerify: true # -- Skip TLS verification (not recommended in production) + + # -- Optional certificate-based authentication + # certificate: + # apiServer: https://k8s-api-server-url:6443 # -- API server for certificate auth + # clientKey: /path/to/client-key.pem # -- Path to client key + # clientCert: /path/to/client-cert.pem # -- Path to client certificate + # caCert: /path/to/ca-cert.pem # -- Path to CA certificate + + # -- Optional bearer token authentication + # bearer: + # apiServer: https://k8s-api-server-url:6443 # -- API server for bearer token auth + # bearerToken: $(BEARER_TOKEN) # -- Bearer token used to authenticate + + # -- List of catalogs available to this chart + catalog: + - id: storage # -- Unique identifier for the catalog + name: "Storage catalog" # -- Human-readable name of the catalog + description: "My Storage packages" # -- Description of the catalog's purpose + repoUrl: quay.io/kubocd/packages # -- OCI registry URL to pull packages from + + # -- Credentials for private registries (optional) + #credentials: + # robotAccountName: $(OCI_USERNAME) # -- Robot account username for private registry + # robotAccountToken: $(OCI_PASSWORD) # -- Robot account token for private registry + # dockerconfigjson: $(DOCKER_CONFIG_JSON) # -- Base64-encoded Docker config JSON + + # -- List of packages under this catalog + packages: + - name: redis # -- Name of the package + - name: minio + - name: cnpg + + - id: auth + name: "Auth catalog" + description: "My Auth packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: openldap + + - id: infra + name: "Infra catalog" + description: "My Infra packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: cert-manager + - name: ingress-nginx + - name: metallb + + - id: stack + name: "Stack catalog" + description: "My Stack packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: podinfo + server: # -- Specify the Server listen address. listenAddress: 0.0.0.0 @@ -19,9 +89,9 @@ configuration: provider: ["bearer"] bearer: # -- Specify the issuer uri. - issuerUri: "http://keycloak.okdp.sandbox/realms/master" + issuerUri: "http://keycloak:7080/realms/master" # -- Specify the jwks URL. - jwksURL: "http://keycloak.okdp.sandbox/realms/master/protocol/openid-connect/certs" + jwksURL: "http://keycloak:7080/realms/master/protocol/openid-connect/certs" # -- Specify the roles attribute path from json access token. rolesAttributePath: "realm_access.roles" # -- Specify the groups attribute path from json access token. @@ -105,8 +175,8 @@ configuration: type: oauth2 flows: authorizationCode: - authorizationUrl: http://keycloak.okdp.sandbox/realms/master/protocol/openid-connect/auth - tokenUrl: http://keycloak.okdp.sandbox/realms/master/protocol/openid-connect/token + authorizationUrl: http://keycloak:7080/realms/master/protocol/openid-connect/auth + tokenUrl: http://keycloak:7080/realms/master/protocol/openid-connect/token scopes: openid: OpenId Authentication email: User Email @@ -115,18 +185,6 @@ configuration: security: - oauth2: [openid, email, profile, roles] - kad: - # -- Specify any ID. - - id: sandbox - # -- Specify any name. - name: Poc Sandbox - # -- Specify KAD API URL. - apiUrl: "kad.okdp.sandbox" - # -- Specify KAD AUTH Bearer. - authBearer: "4Ys3brdqnD5LVjf6hLcQsSQbHWLh5asJ" - # -- Wether to skip the certificate validation. - insecureSkipVerify: true - swagger-ui: enabled: true configuration: diff --git a/helm/okdp-server/values.yaml b/helm/okdp-server/values.yaml index 82da89f..a5f764c 100644 --- a/helm/okdp-server/values.yaml +++ b/helm/okdp-server/values.yaml @@ -7,7 +7,7 @@ image: # -- Image pull policy. pullPolicy: Always # -- Image tag. - tag: "0.1.0" + tag: "0.2.0" # -- Secrets to be used for pulling images from private Docker registries. imagePullSecrets: [] @@ -17,6 +17,85 @@ nameOverride: "" fullnameOverride: "" configuration: + # -- List of Kubernetes clusters this chart will interact with + clusters: + # -- Unique identifier for the cluster + - id: kubo2 + # -- Human-readable name for the cluster + name: "My k8s cluster 1" + # -- Environment tag (e.g., dev, staging, prod) + env: dev + auth: + # -- Use in-cluster authentication + inCluster: true + # kubeconfig: + # apiServer: https://host.docker.internal:56660 # -- Kubernetes API server address + # path: /tmp/.kube/config # -- Path to the kubeconfig file + # # context: kind-kind-okdp-sandbox # -- Optional: specify kubeconfig context to use + # insecureSkipTlsVerify: true # -- Skip TLS verification (not recommended in production) + + # -- Optional certificate-based authentication + # certificate: + # apiServer: https://k8s-api-server-url:6443 # -- API server for certificate auth + # clientKey: /path/to/client-key.pem # -- Path to client key + # clientCert: /path/to/client-cert.pem # -- Path to client certificate + # caCert: /path/to/ca-cert.pem # -- Path to CA certificate + + # -- Optional bearer token authentication + # bearer: + # apiServer: https://k8s-api-server-url:6443 # -- API server for bearer token auth + # bearerToken: $(BEARER_TOKEN) # -- Bearer token used to authenticate + + # -- List of catalogs available to this chart + catalog: + # -- Unique identifier for the catalog + - id: storage + # -- Human-readable name of the catalog + name: "Storage catalog" + # -- Description of the catalog's purpose + description: "My Storage packages" + # -- OCI registry URL to pull packages from + repoUrl: quay.io/kubocd/packages + + # -- Credentials for private registries (optional) + # credentials: + # -- Robot account username for private registry + # robotAccountName: $(OCI_USERNAME) + # -- Robot account token for private registry + # robotAccountToken: $(OCI_PASSWORD) + # -- Base64-encoded Docker config JSON + # dockerconfigjson: $(DOCKER_CONFIG_JSON) + + # -- List of packages under this catalog + packages: + # -- Name of the package + - name: redis + - name: minio + - name: cnpg + + - id: auth + name: "Auth catalog" + description: "My Auth packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: openldap + + - id: infra + name: "Infra catalog" + description: "My Infra packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: cert-manager + - name: ingress-nginx + - name: metallb + + - id: stack + name: "Stack catalog" + description: "My Stack packages" + repoUrl: quay.io/kubocd/packages + packages: + - name: podinfo + server: # -- Specify the Server listen address. listenAddress: 0.0.0.0 @@ -69,16 +148,12 @@ configuration: inline: policy: | p, role:viewers, /api/v1/users/myprofile, * - p, role:viewers, /api/v1/kad, * - p, role:viewers, /api/v1/kad/*/services, * - p, role:viewers, /api/v1/kad/*/catalog, * - p, role:viewers, /api/v1/kad/*/catalog/*, * - p, role:viewers, /api/v1/kad/*/componentreleases, * - p, role:viewers, /api/v1/kad/*/componentreleases/*, * - p, role:viewers, /api/v1/kad/*/templatereleases, * - p, role:viewers, /api/v1/kad/*/templatereleases/*, * - p, role:viewers, /api/v1/kad/*/components, * - p, role:viewers, /api/v1/kad/*/components/*, * + p, role:viewers, /api/v1/catalogs, * + p, role:viewers, /api/v1/catalogs/*, * + + p, role:viewers, /api/v1/clusters, * + p, role:viewers, /api/v1/clusters/*/gitrepos, * + p, role:viewers, /api/v1/clusters/*/gitrepos/*, * g, role:admins, role:developers g, role:developers, role:viewers @@ -135,17 +210,6 @@ configuration: security: - oauth2: [openid, email, profile, roles] - kad: - # -- Specify any ID. - - id: sandbox - # -- Specify any name. - name: Poc Sandbox - # -- Specify KAD API URL. - apiUrl: "" - # -- Specify KAD AUTH Bearer. - authBearer: "" - # -- Wether to skip the certificate validation. - insecureSkipVerify: true swagger-ui: # — Whether to enable or disable swagger UI. enabled: true @@ -173,15 +237,21 @@ swagger-ui: serviceAccount: # -- Specify whether a service account should be created - create: false + create: true # -- Automatically mount a ServiceAccount's API credentials? - automount: false + automount: true # -- Annotations to add to the service account annotations: {} # -- The name of the service account to use. # -- If not set and create is true, a name is generated using the fullname template name: "" +rbac: + # -- Specify whether a RBAC should be created + create: true + # -- Specify annotations for the proxy. + annotations: {} + # -- Additional annotations for the okdp-server pod. podAnnotations: {} # -- Additional labels for the okdp-server pod. diff --git a/internal/constants/constants.go b/internal/common/constants/constants.go similarity index 66% rename from internal/constants/constants.go rename to internal/common/constants/constants.go index 98770b4..a79c949 100644 --- a/internal/constants/constants.go +++ b/internal/common/constants/constants.go @@ -29,17 +29,13 @@ const ( // CasbinRolePrefix is used to prefix the roles/groups in the casbin policy (p, role:viewers, /api/v1/users/myprofile, *) CasbinRolePrefix = "role:" // SwaggerAPIDocsURI is the swagger API Docs public URI - SwaggerAPIDocsURI = OkdpServerBaseURL + "/api-docs" - HealthzURI = "/healthz" - ReadinessURI = "/readiness" - // ComponentURL is the kad components URI - ComponentURL = "/api/kad/v1/mycluster/components" - // ComponentURL is the kad component releases URI - ComponentReleaseURL = "/api/kad/v1/mycluster/component-releases" - // ComponentURL is the kad template releases URI - TemplateReleaseURL = "/api/kad/v1/mycluster/template-releases" - // ComponentURL is the kad catalogs URI - CatalogURL = "/api/kad/v1/mycluster/catalogs" - // GitURL is the kad GIT URI - GitURL = "/api/git/v1/mycluster" + SwaggerAPIDocsURI = OkdpServerBaseURL + "/api-docs" + HealthzURI = "/healthz" + ReadinessURI = "/readiness" + All = "All" + GitRepository = "GitRepository" + K8SAuthKubeConfig = "AuthKubeconfig" + K8SAuthCertificate = "AuthCertificate" + K8SAuthBeaer = "AuthBearer" + K8SInCluster = "InCluster" ) diff --git a/internal/logging/logging.go b/internal/common/logging/logging.go similarity index 92% rename from internal/logging/logging.go rename to internal/common/logging/logging.go index a81cc66..65c07bd 100644 --- a/internal/logging/logging.go +++ b/internal/common/logging/logging.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,6 +99,12 @@ func Panic(args ...interface{}) { // Logger returns a middleware that will write the logs to gin.DefaultWriter. // By default, gin.DefaultWriter = os.Stdout. func Logger() []gin.HandlerFunc { - return []gin.HandlerFunc{ginzap.Ginzap(instance.Desugar(), time.RFC3339, true), - ginzap.RecoveryWithZap(instance.Desugar(), true)} + logger := zap.NewNop() + + if gin.Mode() != gin.ReleaseMode { + logger = instance.Desugar() + } + + return []gin.HandlerFunc{ginzap.Ginzap(logger, time.RFC3339, true), + ginzap.RecoveryWithZap(logger, true)} } diff --git a/internal/config/config.go b/internal/config/config.go index 5f8a3a4..4ef93b9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -22,17 +22,18 @@ import ( "github.com/fsnotify/fsnotify" "github.com/getkin/kin-openapi/openapi3" - "github.com/okdp/okdp-server/api/openapi/v3/_api" + "github.com/okdp/okdp-server/internal/model" "github.com/spf13/viper" ) // Application configuration type ApplicationConfig struct { - Server Server `mapstructure:"server"` - Security Security `mapstructure:"security"` - Logging Logging `mapstructure:"logging"` - Swagger Swagger `mapstructure:"swagger"` - Kad []KadInstance `mapstructure:"kad"` + Server Server `mapstructure:"server"` + Security Security `mapstructure:"security"` + Logging Logging `mapstructure:"logging"` + Swagger Swagger `mapstructure:"swagger"` + Catalogs []*model.Catalog `mapstructure:"catalog"` + Clusters []*model.Cluster `yaml:"clusters"` } // Server configuration @@ -140,8 +141,6 @@ type Swagger struct { Security openapi3.SecurityRequirements `yaml:"security,omitempty"` } -type KadInstance _api.KadInstance - var ( instance *ApplicationConfig once sync.Once diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 685eb8e..096ae29 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -22,6 +22,7 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_LoadConfig_Server(t *testing.T) { @@ -167,17 +168,60 @@ func Test_LoadConfig_Swagger(t *testing.T) { } -func Test_LoadConfig_Kad(t *testing.T) { +func Test_LoadConfig_Catalog(t *testing.T) { // Given viper.Set("config", "testdata/application.yaml") // When - KadInstances := GetAppConfig().Kad + catalogs := GetAppConfig().Catalogs // Then - assert.Equal(t, "sandbox", KadInstances[0].ID, "Id") - assert.Equal(t, "Sandbox de idir", KadInstances[0].Name, "Name") - assert.Equal(t, "https://host.docker.internal:6553/api/kad/v1", KadInstances[0].APIURL, "ApiUrl") - assert.Equal(t, "JUDtoP55C2dLfeaXqSbehhKKRdmAWTfj", KadInstances[0].AuthBearer, "AuthBearer") - assert.True(t, KadInstances[0].InsecureSkipVerify, "InsecureSkipVerify should be true") + require.NotEmpty(t, catalogs, "Catalogs should not be empty") + catalog := catalogs[0] + assert.True(t, catalog.IsAuthenticated(), "The catalog should be authenticated") + assert.Equal(t, "infra01", catalog.ID, "ID") + assert.Equal(t, "infra01 catalog", catalog.Name, "Name") + assert.Equal(t, "My infrastructure components", catalog.Description, "Description") + assert.Equal(t, "quay.io/okdp/applications", catalog.RepoURL, "RepoURL") + assert.Equal(t, "$(OCI_USERNAME)", *catalog.Credentials.RobotAccountName, "Credentials.RobotAccountName") + assert.Equal(t, "$(OCI_PASSWORD)", *catalog.Credentials.RobotAccountToken, "Credentials.RobotAccountToken") + assert.Equal(t, "quay.io", catalog.RepoHost(), "RepoHost") + + require.NotEmpty(t, catalog.Packages, "Packages catalogs should not be empty") + require.Len(t, catalog.Packages, 3, "The catalog should contain exactly 3 Packages") + assert.Equal(t, "redis", catalog.Packages[0].Name, "Packages") + assert.Equal(t, "podinfo", catalog.Packages[1].Name, "Packages") + assert.Equal(t, "cert-manager", catalog.Packages[2].Name, "Packages") + + catalog = catalogs[1] + assert.Equal(t, "infra02", catalog.ID, "ID") + assert.False(t, catalog.IsAuthenticated(), fmt.Sprintf("The catalog '%s' should not be authenticated", catalog.ID)) +} + +func Test_LoadConfig_Clusters(t *testing.T) { + // Given + viper.Set("config", "testdata/application.yaml") + // When + clusters := GetAppConfig().Clusters + // Then + require.NotEmpty(t, clusters, "K8S clusters should not be empty") + cluster := clusters[0] + assert.Equal(t, "kubo03dev", cluster.ID, "ID") + assert.Equal(t, "k8s infra dev", cluster.Name, "Name") + assert.Equal(t, "dev", cluster.Env, "Env") + assert.Equal(t, "/path/to/kubeconfig", cluster.Auth.Kubeconfig.Path, "cluster.Auth.Kubeconfig") + assert.Equal(t, "dev-context", cluster.Auth.Kubeconfig.Context, "cluster.Auth.Context") + assert.Equal(t, "https://host.docker.internal:56660", cluster.Auth.Kubeconfig.APIServer, "cluster.Auth.Kubeconfig.APIServer") + assert.True(t, cluster.Auth.Kubeconfig.InsecureSkipTlsVerify, "cluster.Auth.Kubeconfig.InsecureSkipTlsVerify") + + assert.Equal(t, "https://k8s-api-server-url:6443", cluster.Auth.Certificate.APIServer, "cluster.Auth.Certificate.ApiServer") + assert.Equal(t, "/path/to/client-key.pem", cluster.Auth.Certificate.ClientKey, "cluster.Auth.Certificate.ClientKey") + assert.Equal(t, "/path/to/client-cert.pem", cluster.Auth.Certificate.ClientCert, "cluster.Auth.Certificate.ClientCert") + assert.Equal(t, "/path/to/ca-cert.pem", cluster.Auth.Certificate.CACert, "cluster.Auth.Certificate.CaCert") + + assert.Equal(t, "https://k8s-api-server-url:6443", cluster.Auth.Bearer.APIServer, "cluster.Auth.Bearer.ApiServer") + assert.Equal(t, "$(BEARER_TOKEN)", cluster.Auth.Bearer.BearerToken, "cluster.Auth.Bearer.BearerToken") + + assert.True(t, *cluster.Auth.InCluster, "cluster.Auth.InCluster") + } func Test_LoadConfig_ConfigFileNotFound(t *testing.T) { diff --git a/internal/config/testdata/application.yaml b/internal/config/testdata/application.yaml index 29a4583..87a74d4 100644 --- a/internal/config/testdata/application.yaml +++ b/internal/config/testdata/application.yaml @@ -74,10 +74,45 @@ swagger: security: - oauth2: [openid, email, profile, roles] -kad: - - id: sandbox - name: Sandbox de idir - apiUrl: https://host.docker.internal:6553/api/kad/v1 - authBearer: JUDtoP55C2dLfeaXqSbehhKKRdmAWTfj - insecureSkipVerify: true - +catalog: + - id: infra01 + name: infra01 catalog + description: My infrastructure components + repoUrl: quay.io/okdp/applications + credentials: + robotAccountName: $(OCI_USERNAME) + robotAccountToken: $(OCI_PASSWORD) + packages: + - name: redis + - name: podinfo + - name: cert-manager + + - id: infra02 + name: infra02 catalog + description: My infrastructure components + repoUrl: quay.io/okdp/applications + packages: + - name: minio + +clusters: + - id: kubo03dev + name: k8s infra dev + env: dev + auth: + inCluster: true + kubeconfig: + apiServer: https://host.docker.internal:56660 + path: /path/to/kubeconfig + context: dev-context + insecureSkipTlsVerify: True + certificate: + apiServer: https://k8s-api-server-url:6443 + clientKey: /path/to/client-key.pem + clientCert: /path/to/client-cert.pem + caCert: /path/to/ca-cert.pem + bearer: + apiServer: https://k8s-api-server-url:6443 + bearerToken: $(BEARER_TOKEN) + + + diff --git a/internal/controllers/catalog_controller.go b/internal/controllers/catalog_controller.go index 1e4f427..0f12e2d 100644 --- a/internal/controllers/catalog_controller.go +++ b/internal/controllers/catalog_controller.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,10 @@ package controllers import ( - "fmt" "net/http" "github.com/gin-gonic/gin" - log "github.com/okdp/okdp-server/internal/logging" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/services" ) @@ -35,27 +34,66 @@ func CatalogController() *ICatalogController { } } -func (r ICatalogController) ListCatalogs(c *gin.Context, kadInstanceID string) { - catalogs, err := r.catalogService.List(kadInstanceID) +func (r ICatalogController) ListCatalogs(c *gin.Context) { + catalogs := r.catalogService.ListCatalogs() + c.JSON(http.StatusOK, catalogs) +} + +func (r ICatalogController) GetCatalog(c *gin.Context, catalogID string) { + catalog, err := r.catalogService.GetCatalog(catalogID) if err != nil { - log.Error("Unable to list Catalogs on kad instance %s, details: %+v", kadInstanceID, err) + log.Error("Unable to find the Catalog with ID '%s', details: %+v", catalogID, err) c.JSON(err.Status, err) return } - c.JSON(http.StatusOK, catalogs) + c.JSON(http.StatusOK, catalog) } -func (r ICatalogController) GetCatalog(c *gin.Context, kadInstanceID string, name string) { - catalog, err := r.catalogService.Get(kadInstanceID, name) +func (r ICatalogController) ListPackages(c *gin.Context, catalogID string) { + packages, err := r.catalogService.GetPackages(catalogID) if err != nil { - log.Error("Unable to get Catalog info '%s' on kad instance %s, details: %+v", name, kadInstanceID, err) + log.Error("Unable to find the packages with Catalog ID '%s', details: %+v", catalogID, err) c.JSON(err.Status, err) return } - if catalog == nil { - c.JSON(http.StatusNotFound, fmt.Sprintf("Component with id %s not found", name)) + c.JSON(http.StatusOK, packages) +} + +func (r ICatalogController) GetPackage(c *gin.Context, catalogID string, name string) { + result, err := r.catalogService.GetPackage(catalogID, name) + if err != nil { + log.Error("Unable to find the package '%s' with Catalog ID '%s', details: %+v", name, catalogID, err) + c.JSON(err.Status, err) return } - c.JSON(http.StatusOK, catalog) + c.JSON(http.StatusOK, result) +} + +func (r ICatalogController) GetPackageVersions(c *gin.Context, catalogID string, name string) { + r.GetPackage(c, catalogID, name) +} +func (r ICatalogController) GetPackageDefinition(c *gin.Context, catalogID string, name string, version string) { + definition, err := r.catalogService.GetPackageDefinition(catalogID, name, version) + if err != nil { + log.Error("Unable to find the package definition for package '%s:%s' with Catalog ID '%s', details: %+v", name, version, catalogID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, definition) +} + +func (r ICatalogController) GetPackageSchema(c *gin.Context, catalogID string, name string, version string) { + definition, err := r.catalogService.GetPackageDefinition(catalogID, name, version) + if err != nil { + log.Error("Unable to find the package definition for package '%s:%s' with Catalog ID '%s', details: %+v", name, version, catalogID, err) + c.JSON(err.Status, err) + return + } + schema, ok := definition["schema"] + if !ok { + c.JSON(http.StatusOK, struct{}{}) + return + } + c.JSON(http.StatusOK, schema) } diff --git a/internal/controllers/cluster_controller.go b/internal/controllers/cluster_controller.go new file mode 100644 index 0000000..aa50183 --- /dev/null +++ b/internal/controllers/cluster_controller.go @@ -0,0 +1,70 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package controllers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/services" +) + +type IClusterController struct { + clusterService *services.ClusterService +} + +func ClusterController() *IClusterController { + return &IClusterController{ + clusterService: services.NewClusterService(), + } +} + +func (r IClusterController) ListClusters(c *gin.Context) { + clusters := r.clusterService.ListClusters() + c.JSON(http.StatusOK, clusters) +} + +func (r IClusterController) GetCluster(c *gin.Context, clusterID string) { + cluster, err := r.clusterService.GetCluster(clusterID) + if err != nil { + log.Error("%+v", clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, cluster) +} + +func (r IClusterController) ListNamespaces(c *gin.Context, clusterID string) { + namespaces, err := r.clusterService.ListNamespaces(clusterID) + if err != nil { + log.Error("%+v", clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, namespaces) +} + +func (r IClusterController) GetNamespace(c *gin.Context, clusterID string, namespace string) { + namespace, err := r.clusterService.GetNamespaceByName(clusterID, namespace) + if err != nil { + log.Error("%+v", clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, namespace) +} diff --git a/internal/controllers/component_controller.go b/internal/controllers/component_controller.go deleted file mode 100644 index 0b82e40..0000000 --- a/internal/controllers/component_controller.go +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package controllers - -import ( - "net/http" - - "github.com/gin-gonic/gin" - _component "github.com/okdp/okdp-server/api/openapi/v3/_api/components" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/model" - "github.com/okdp/okdp-server/internal/services" -) - -type IComponentController struct { - componentService *services.ComponentService -} - -func ComponentController() *IComponentController { - return &IComponentController{ - componentService: services.NewComponentService(), - } -} - -func (r IComponentController) ListComponents(c *gin.Context, kadInstanceID string, params _component.ListComponentsParams) { - components, err := r.componentService.List(kadInstanceID, params.Catalog) - if err != nil { - log.Error("Unable to list Components on kad instance %s, details: %+v", kadInstanceID, err) - c.JSON(err.Status, err) - return - } - c.JSON(http.StatusOK, components) -} - -func (r IComponentController) GetComponentsByName(c *gin.Context, kadInstanceID string, name string, params _component.GetComponentsByNameParams) { - // Workaround - Kad should return a components by name - log.Info("Get component by name '%s' and catalog '%s' on kad instanceId '%s'", name, params.Catalog, kadInstanceID) - components, err := r.componentService.List(kadInstanceID, params.Catalog) - if err != nil { - log.Error("Unable to list Components on kad instance %s, details: %+v", kadInstanceID, err) - c.JSON(err.Status, err) - return - } - var filtered model.Components = []*model.Component{} - for _, component := range *components { - if component.Spec.Name == name { - filtered = append(filtered, component) - } - } - c.JSON(http.StatusOK, filtered) -} diff --git a/internal/controllers/component_release_controller.go b/internal/controllers/component_release_controller.go deleted file mode 100644 index b6ad5db..0000000 --- a/internal/controllers/component_release_controller.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package controllers - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - _component "github.com/okdp/okdp-server/api/openapi/v3/_api/componentreleases" - "github.com/okdp/okdp-server/internal/constants" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/model" - auth "github.com/okdp/okdp-server/internal/security/authc/model" - "github.com/okdp/okdp-server/internal/services" -) - -type IComponentReleaseController struct { - componentReleaseService *services.ComponentReleaseService -} - -func ComponentReleaseController() *IComponentReleaseController { - return &IComponentReleaseController{ - componentReleaseService: services.NewComponentReleaseService(), - } -} - -func (r IComponentReleaseController) ListComponentReleases(c *gin.Context, kadInstanceID string, params _component.ListComponentReleasesParams) { - components, err := r.componentReleaseService.List(kadInstanceID, params.Catalog) - if err != nil { - log.Error("Unable to list Component Releases on kad instance %s, details: %+v", kadInstanceID, err) - c.JSON(err.Status, err) - return - } - c.JSON(http.StatusOK, components) -} - -func (r IComponentReleaseController) GetComponentRelease(c *gin.Context, kadInstanceID string, name string, params _component.GetComponentReleaseParams) { - component, err := r.componentReleaseService.Get(kadInstanceID, name, params.Catalog) - if err != nil { - log.Error("Unable to get Component Release '%s' on kad instance %s, details: %+v", name, kadInstanceID, err) - c.JSON(err.Status, err) - return - } - if component == nil { - c.JSON(http.StatusNotFound, fmt.Sprintf("Component with id %s not found", name)) - return - } - c.JSON(http.StatusOK, component) - -} - -func (r IComponentReleaseController) CreateOrUpdateComponentRelease(c *gin.Context, kadInstanceID string, name string) { - - var componentReleaseRequest model.ComponentReleaseRequest - if err := c.ShouldBindJSON(&componentReleaseRequest); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - maybeUserInfo, _ := c.Get(constants.OAuth2UserInfo) - userInfo, _ := maybeUserInfo.(*auth.UserInfo) - commitData := map[string]string{ - "commit-message": componentReleaseRequest.Comment, - "committer-name": userInfo.Name, - "committer-email": userInfo.Email, - } - - gitCommitReponse, err := r.componentReleaseService.CreateOrUpdateComponentRelease(kadInstanceID, name, componentReleaseRequest, commitData) - if err != nil { - log.Error("Unable to create or update component release '%s' in Git folder '%s' on kad instance %s, details: %+v", name, componentReleaseRequest.GitRepoFolder, kadInstanceID, err) - c.JSON(err.Status, err) - return - } - - c.JSON(http.StatusOK, gitCommitReponse) - -} diff --git a/internal/controllers/git_controller.go b/internal/controllers/git_controller.go new file mode 100644 index 0000000..5ec4c1c --- /dev/null +++ b/internal/controllers/git_controller.go @@ -0,0 +1,150 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package controllers + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/services" +) + +type IGitRepoController struct { + gitRepoService *services.GitRepoService +} + +func GitRepoController() *IGitRepoController { + return &IGitRepoController{ + gitRepoService: services.NewGitRepoService(), + } +} + +func (r IGitRepoController) ListGitRepos(c *gin.Context, clusterID string, namespace string) { + gitRepos, err := r.gitRepoService.ListGitRepos(clusterID, namespace) + if err != nil { + log.Error("Unable to list Git repos on namespace '%s' with cluster ID '%s', details: %+v", namespace, clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, gitRepos) +} + +func (r IGitRepoController) GetGitRepo(c *gin.Context, clusterID string, namespace string, kustomizationName string) { + gitRepo, err := r.gitRepoService.GetGitRepo(clusterID, namespace, kustomizationName) + if err != nil { + log.Error("Unable to find Git repo '%s' on namespace '%s' with cluster id '%s', details: %+v", kustomizationName, namespace, clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, gitRepo) +} + +func (r IGitRepoController) ListGitReleases(c *gin.Context, clusterID string, namespace string, kustomizationName string) { + releasesInfo, err := r.gitRepoService.ListReleases(clusterID, namespace, kustomizationName) + if err != nil { + log.Error("Unable to get releases from Git repo '%s/%s' on cluster ID '%s', details: %+v", namespace, kustomizationName, clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, releasesInfo) +} + +func (r IGitRepoController) GetGitRelease(c *gin.Context, clusterID string, namespace string, kustomizationName string, releaseName string) { + release, err := r.gitRepoService.GetRelease(clusterID, namespace, kustomizationName, releaseName) + if err != nil { + log.Error("Unable to get release from Git repo '%s/%s' on cluster ID '%s', details: %+v", namespace, kustomizationName, clusterID, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, release) +} + +func (r IGitRepoController) CreateGitRelease(c *gin.Context, clusterID string, namespace string, kustomizationName string) { + var release model.Release + userInfo, err := GetUserInfo(c) + if err != nil { + c.JSON(err.Status, err) + } + + if err := c.ShouldBindJSON(&release); err != nil { + resp := model.NewServerResponse(model.OkdpServerResponse).BadRequest("%+v", err.Error()) + c.JSON(resp.Status, resp) + return + } + + msg := fmt.Sprintf("Create new KuboCD release %s/%s on cluster id %s", namespace, release.Name, clusterID) + commitOpts := model.NewGitCommitOptions(msg). + Author(userInfo.Name). + Email(userInfo.Email) + resp, err := r.gitRepoService.CreateGitRelease(clusterID, namespace, kustomizationName, &release, commitOpts) + + if err != nil { + c.JSON(err.Status, err) + return + } + + c.JSON(http.StatusCreated, resp) + +} + +func (r IGitRepoController) UpdateGitRelease(c *gin.Context, clusterID string, namespace string, kustomizationName string) { + var release model.Release + userInfo, err := GetUserInfo(c) + if err != nil { + c.JSON(err.Status, err) + } + + if err := c.ShouldBindJSON(&release); err != nil { + resp := model.NewServerResponse(model.OkdpServerResponse).BadRequest("%+v", err.Error()) + c.JSON(resp.Status, resp) + return + } + + msg := fmt.Sprintf("Update KuboCD release %s/%s on cluster id %s", namespace, release.Name, clusterID) + commitOpts := model.NewGitCommitOptions(msg). + Author(userInfo.Name). + Email(userInfo.Email) + resp, err := r.gitRepoService.UpdateGitRelease(clusterID, namespace, kustomizationName, &release, commitOpts) + + if err != nil { + c.JSON(err.Status, err) + return + } + + c.JSON(http.StatusOK, resp) +} + +func (r IGitRepoController) DeleteGitRelease(c *gin.Context, clusterID string, namespace string, kustomizationName string, releaseName string) { + + userInfo, err := GetUserInfo(c) + if err != nil { + c.JSON(err.Status, err) + } + + msg := fmt.Sprintf("Delete KuboCD release %s/%s on cluster id %s", namespace, releaseName, clusterID) + commitOpts := model.NewGitCommitOptions(msg). + Author(userInfo.Name). + Email(userInfo.Email) + + resp := r.gitRepoService.DeleteGitRelease(clusterID, namespace, kustomizationName, releaseName, commitOpts) + + c.JSON(http.StatusOK, resp) + +} diff --git a/internal/controllers/kubocd_controller.go b/internal/controllers/kubocd_controller.go new file mode 100644 index 0000000..bd80b16 --- /dev/null +++ b/internal/controllers/kubocd_controller.go @@ -0,0 +1,86 @@ +package controllers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + _api "github.com/okdp/okdp-server/api/openapi/v3/_api/k8s" + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/services" + "github.com/okdp/okdp-server/internal/utils" +) + +type IKuboCDController struct { + k8sService *services.KuboCDService +} + +func KuboCDController() *IKuboCDController { + return &IKuboCDController{ + k8sService: services.NewKuboCDService(), + } +} + +func (r IKuboCDController) ListK8sReleases(c *gin.Context, clusterID string, namespace string) { + releasesInfo, err := r.k8sService.ListReleases(clusterID, namespace) + if err != nil { + log.Error("Unable to get releases from Kubernetes cluster '%s' on namespace '%s', details: %+v", clusterID, namespace, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, releasesInfo) +} + +func (r IKuboCDController) GetK8sRelease(c *gin.Context, clusterID string, namespace string, releaseName string) { + release, err := r.k8sService.GetRelease(clusterID, namespace, releaseName) + if err != nil { + log.Error("Unable to get release from Kubernetes cluster '%s' on namespace '%s', details: %+v", clusterID, namespace, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, release) +} + +func (r IKuboCDController) GetK8sReleaseStatus(c *gin.Context, clusterID string, namespace string, releaseName string) { + release, err := r.k8sService.GetReleaseStatus(clusterID, namespace, releaseName) + if err != nil { + log.Error("Unable to get release status from Kubernetes cluster '%s' on namespace '%s', details: %+v", clusterID, namespace, err) + c.JSON(err.Status, err) + return + } + c.JSON(http.StatusOK, release) +} + +func (r IKuboCDController) CreateK8sRelease(c *gin.Context, clusterID string, namespace string, params _api.CreateK8sReleaseParams) { + var release model.Release + + if err := c.ShouldBindJSON(&release); err != nil { + resp := model.NewServerResponse(model.OkdpServerResponse).BadRequest("%+v", err.Error()) + c.JSON(resp.Status, resp) + return + } + + response := r.k8sService.CreateRelease(clusterID, namespace, &release, utils.OrFalse(params.DryRun)) + + c.JSON(response.Status, response) + +} + +func (r IKuboCDController) UpdateK8sRelease(c *gin.Context, clusterID string, namespace string, params _api.UpdateK8sReleaseParams) { + var release model.Release + + if err := c.ShouldBindJSON(&release); err != nil { + resp := model.NewServerResponse(model.OkdpServerResponse).BadRequest("%+v", err.Error()) + c.JSON(resp.Status, resp) + return + } + + response := r.k8sService.UpdateRelease(clusterID, namespace, &release, utils.OrFalse(params.DryRun)) + c.JSON(response.Status, response) +} + +func (r IKuboCDController) DeleteK8sRelease(c *gin.Context, clusterID string, namespace string, releaseName string) { + response := r.k8sService.DeleteRelease(clusterID, namespace, releaseName) + c.JSON(response.Status, response) +} diff --git a/internal/controllers/register.go b/internal/controllers/register.go index 975e55b..e2387d1 100644 --- a/internal/controllers/register.go +++ b/internal/controllers/register.go @@ -19,14 +19,12 @@ package controllers import ( "github.com/gin-gonic/gin" _catalog "github.com/okdp/okdp-server/api/openapi/v3/_api/catalogs" - _componentrelease "github.com/okdp/okdp-server/api/openapi/v3/_api/componentreleases" - _component "github.com/okdp/okdp-server/api/openapi/v3/_api/components" - _kad "github.com/okdp/okdp-server/api/openapi/v3/_api/kad" - _service "github.com/okdp/okdp-server/api/openapi/v3/_api/services" - _templaterelease "github.com/okdp/okdp-server/api/openapi/v3/_api/templatereleases" + _cluster "github.com/okdp/okdp-server/api/openapi/v3/_api/clusters" + _k8s "github.com/okdp/okdp-server/api/openapi/v3/_api/k8s" + _repositories "github.com/okdp/okdp-server/api/openapi/v3/_api/repositories" _user "github.com/okdp/okdp-server/api/openapi/v3/_api/users" + "github.com/okdp/okdp-server/internal/common/constants" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" ) type Router struct { @@ -39,12 +37,10 @@ type Group struct { func (g *Group) RegisterControllers() { _user.RegisterHandlers(g, UserProfileController()) + _cluster.RegisterHandlers(g, ClusterController()) _catalog.RegisterHandlers(g, CatalogController()) - _componentrelease.RegisterHandlers(g, ComponentReleaseController()) - _templaterelease.RegisterHandlers(g, TemplateReleaseController()) - _component.RegisterHandlers(g, ComponentController()) - _service.RegisterHandlers(g, ServiceController()) - _kad.RegisterHandlers(g, KadController()) + _repositories.RegisterHandlers(g, GitRepoController()) + _k8s.RegisterHandlers(g, KuboCDController()) } func (r *Router) RegisterSwaggerAPIDoc(swaggerConf config.Swagger) { diff --git a/internal/controllers/service_controller.go b/internal/controllers/service_controller.go deleted file mode 100644 index 67c7c59..0000000 --- a/internal/controllers/service_controller.go +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package controllers - -import ( - "net/http" - - "github.com/gin-gonic/gin" - _services "github.com/okdp/okdp-server/api/openapi/v3/_api/services" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/services" -) - -type IServiceController struct { - service *services.Service -} - -func ServiceController() *IServiceController { - service, err := services.NewService() - if err != nil { - return nil - } - return &IServiceController{ - service: service, - } -} - -func (r IServiceController) ListServices(c *gin.Context, kadInstanceID string, params _services.ListServicesParams) { - services, err := r.service.List(kadInstanceID, params.Catalog) - if err != nil { - log.Error("Unable to list services, details: %+v", err) - c.JSON(err.Status, err) - return - } - c.JSON(http.StatusOK, services) -} diff --git a/internal/controllers/template_release_controller.go b/internal/controllers/template_release_controller.go deleted file mode 100644 index b27106a..0000000 --- a/internal/controllers/template_release_controller.go +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package controllers - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - _component "github.com/okdp/okdp-server/api/openapi/v3/_api/templatereleases" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/services" -) - -type ITemplateReleaseController struct { - templateReleaseService *services.TemplateReleaseService -} - -func TemplateReleaseController() *ITemplateReleaseController { - return &ITemplateReleaseController{ - templateReleaseService: services.NewTemplateReleaseService(), - } -} - -func (r ITemplateReleaseController) ListTemplateReleases(c *gin.Context, kadInstanceID string, params _component.ListTemplateReleasesParams) { - components, err := r.templateReleaseService.List(kadInstanceID, params.Catalog) - if err != nil { - log.Error("Unable to list Template Releases on kad instance '%s', details: %+v", kadInstanceID, err) - c.JSON(err.Status, err) - return - } - c.JSON(http.StatusOK, components) -} - -func (r ITemplateReleaseController) GetTemplateRelease(c *gin.Context, kadInstanceID string, name string, params _component.GetTemplateReleaseParams) { - component, err := r.templateReleaseService.Get(kadInstanceID, name, params.Catalog) - if err != nil { - log.Error("Unable to get Template Release: '%s' on kad instance '%s', details: %+v", name, kadInstanceID, err) - c.JSON(err.Status, err) - return - } - if component == nil { - c.JSON(http.StatusNotFound, fmt.Sprintf("Component with id %s not found", name)) - return - } - c.JSON(http.StatusOK, component) - -} diff --git a/internal/controllers/user_profile.go b/internal/controllers/user_profile.go index 32b2247..538e606 100644 --- a/internal/controllers/user_profile.go +++ b/internal/controllers/user_profile.go @@ -20,8 +20,9 @@ import ( "net/http" "github.com/gin-gonic/gin" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/security/authc/model" + "github.com/okdp/okdp-server/internal/common/constants" + "github.com/okdp/okdp-server/internal/model" + authc "github.com/okdp/okdp-server/internal/security/authc/model" ) type IUserProfileController struct { @@ -34,7 +35,24 @@ func UserProfileController() *IUserProfileController { func (r IUserProfileController) GetMyProfile(c *gin.Context) { if maybeUserInfo, found := c.Get(constants.OAuth2UserInfo); found { - c.JSON(http.StatusOK, maybeUserInfo.(*model.UserInfo)) + c.JSON(http.StatusOK, maybeUserInfo.(*authc.UserInfo)) } } + +func GetUserInfo(c *gin.Context) (*authc.UserInfo, *model.ServerResponse) { + maybeUserInfo, found := c.Get(constants.OAuth2UserInfo) + err := model. + NewServerResponse(model.OkdpServerResponse). + Unauthorized("Unauthorized") + if !found { + return nil, err + } + + userInfo, ok := maybeUserInfo.(*authc.UserInfo) + if !ok { + return nil, err + } + + return userInfo, nil +} diff --git a/internal/errors/server_errors.go b/internal/errors/server_errors.go deleted file mode 100644 index 253a41e..0000000 --- a/internal/errors/server_errors.go +++ /dev/null @@ -1,47 +0,0 @@ -package errors - -import ( - "fmt" - "net/http" - - "github.com/okdp/okdp-server/api/openapi/v3/_api" -) - -type ServerError _api.ServerError - -const ( - // Error types - Kad = "kad" - OkdpServer = "okdp_server" -) - -func OfType(errorType string) *ServerError { - return &ServerError{ - Type: errorType, - } -} - -func (s *ServerError) NotFoundError(messages ...interface{}) *ServerError { - s.Message = toError(messages...) - s.Status = http.StatusNotFound - return s -} - -func (s *ServerError) Forbidden(messages ...interface{}) *ServerError { - s.Message = toError(messages...) - s.Status = http.StatusForbidden - return s -} - -func (s *ServerError) GenericError(statusCode int, messages ...interface{}) *ServerError { - s.Message = toError(messages...) - s.Status = statusCode - return s -} - -func toError(messages ...interface{}) string { - if len(messages) == 1 { - return fmt.Errorf("%+v", messages...).Error() - } - return fmt.Errorf(messages[0].(string), messages[1:]...).Error() -} diff --git a/internal/integrations/git/client/client.go b/internal/integrations/git/client/client.go new file mode 100644 index 0000000..c3526ff --- /dev/null +++ b/internal/integrations/git/client/client.go @@ -0,0 +1,144 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "github.com/go-git/go-billy/v5/memfs" + git "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/storage/memory" + + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +type LocalRepo struct { + *git.Repository + *git.Worktree +} + +func NewLocalRepo(url string, ref string, auth transport.AuthMethod) (*LocalRepo, *model.ServerResponse) { + + fs := memfs.New() + repo, er := git.Clone(memory.NewStorage(), fs, &git.CloneOptions{ + URL: url, + Auth: auth, + Depth: 1, + Progress: nil, + SingleBranch: true, + ReferenceName: plumbing.ReferenceName(ref), + }) + + if er != nil { + return nil, model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity(er.Error()) + } + worktree, err := repo.Worktree() + if err != nil { + return nil, model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Unable to access local git repo filesystem %s, %s, details: %s", url, ref, err.Error()) + } + + return &LocalRepo{ + repo, worktree, + }, nil +} + +func DoReadContent(repo *model.GitRepository, auth transport.AuthMethod) ([]*model.GitContent, *model.ServerResponse) { + contents := []*model.GitContent{} + + localrepo, err := NewLocalRepo(repo.RepoURL, repo.Ref, auth) + if err != nil { + return nil, err + } + + fs := localrepo.Filesystem + + filePaths, err := ListFiles(fs, repo.Path) + if err != nil { + return nil, err + } + for _, filePath := range filePaths { + if !utils.IsYaml(filePath) { + log.Warn("Ignoring file '%s' in folder '%s': not a YAML file", filePath, repo.Path) + continue + } + content, err := ReadContent(fs, filePath) + if err != nil { + return nil, err + } + content.URL = repo.RepoURL + contents = append(contents, content) + } + + return contents, nil + +} + +func DoPushContent(repo *model.GitRepository, auth transport.AuthMethod, content string, commitOpts *model.GitCommit, path string) *model.ServerResponse { + localrepo, er := NewLocalRepo(repo.RepoURL, repo.Ref, auth) + if er != nil { + return er + } + + err := localrepo.CommitFile(content, path, commitOpts) + + if err != nil { + return model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Unable to commit file %s (%s/%s) => %s (%s), details: %s", path, repo.Namespace, repo.Name, repo.RepoURL, repo.Ref, err.Error()) + } + + err = localrepo.SafePush(auth) + + if err != nil && err != git.NoErrAlreadyUpToDate { + return model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Unable to push %s (%s/%s) => %s (%s), details: %s", path, repo.Namespace, repo.Name, repo.RepoURL, repo.Ref, err.Error()) + } + + return nil +} + +func DoDeleteFile(repo *model.GitRepository, auth transport.AuthMethod, commitOpts *model.GitCommit, path string) *model.ServerResponse { + localrepo, er := NewLocalRepo(repo.RepoURL, repo.Ref, auth) + if er != nil { + return er + } + + err := localrepo.DeleteFile(path, commitOpts) + + if err != nil { + return model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Unable to delete file %s (%s/%s) => %s (%s), details: %s", path, repo.Namespace, repo.Name, repo.RepoURL, repo.Ref, err.Error()) + } + + err = localrepo.SafePush(auth) + + if err != nil && err != git.NoErrAlreadyUpToDate { + return model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Unable to push %s (%s/%s) => %s (%s), details: %s", path, repo.Namespace, repo.Name, repo.RepoURL, repo.Ref, err.Error()) + } + + return model.NewServerResponse(model.OkdpServerResponse).Deleted("Release name %s successfully deleted", path) +} diff --git a/internal/integrations/git/client/common.go b/internal/integrations/git/client/common.go new file mode 100644 index 0000000..4570450 --- /dev/null +++ b/internal/integrations/git/client/common.go @@ -0,0 +1,149 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "io" + "path/filepath" + + "github.com/go-git/go-billy/v5" + git "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/transport" + + "github.com/okdp/okdp-server/internal/model" +) + +func (r LocalRepo) SafePush(auth transport.AuthMethod) error { + + // err := r.Worktree.Pull(&git.PullOptions{ + // RemoteName: "origin", + // Auth: auth, + // }) + // if err != nil && err != git.NoErrAlreadyUpToDate { + // return err + // } + + err := r.Push(&git.PushOptions{ + Auth: auth, + }) + + if err != nil && err != git.NoErrAlreadyUpToDate { + return err + } + + return nil + +} + +func (r LocalRepo) CommitFile(content string, path string, commitOpts *model.GitCommit) error { + + fs := r.Worktree.Filesystem + + f, err := fs.Create(path) + if err != nil { + return err + } + defer f.Close() + + if _, err := f.Write([]byte(content)); err != nil { + return err + } + + _, err = r.Worktree.Add(path) + if err != nil { + return err + } + _, err = r.Worktree.Commit(commitOpts.Message, &commitOpts.CommitOptions) + + return err +} + +func (r LocalRepo) DeleteFile(path string, commitOpts *model.GitCommit) error { + + fs := r.Worktree.Filesystem + + if err := fs.Remove(path); err != nil { + return err + } + _, err := r.Worktree.Remove(path) + if err != nil { + return err + } + + _, err = r.Worktree.Commit(commitOpts.Message, &commitOpts.CommitOptions) + + return err +} + +func ListFiles(fs billy.Filesystem, folder string) ([]string, *model.ServerResponse) { + var fileNames []string + + var walk func(string) *model.ServerResponse + walk = func(currentPath string) *model.ServerResponse { + stat, err := fs.Stat(currentPath) + if err != nil || !stat.IsDir() { + return nil // Skip if not a directory or doesn't exist + } + + dirEntries, err := fs.ReadDir(currentPath) + if err != nil { + return model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Failed to read git folder %s: %s", currentPath, err.Error()) + } + + for _, entry := range dirEntries { + fullPath := filepath.Join(currentPath, entry.Name()) + if entry.IsDir() { + if walkErr := walk(fullPath); walkErr != nil { + return walkErr + } + } else { + fileNames = append(fileNames, fullPath) + } + } + return nil + } + + if err := walk(folder); err != nil { + return nil, err + } + + return fileNames, nil +} + +func ReadContent(fs billy.Filesystem, filePath string) (*model.GitContent, *model.ServerResponse) { + file, err := fs.Open(filePath) + if err != nil { + return nil, model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Failed to open file path %s", filePath, err.Error()) + } + + content, err := io.ReadAll(file) + + if err != nil { + return nil, model. + NewServerResponse(model.GitRepoResponse). + UnprocessableEntity("Failed to read file %s", filePath, err.Error()) + } + + return &model.GitContent{ + Content: &content, + Path: filePath, + }, nil +} diff --git a/internal/integrations/git/git_repo.go b/internal/integrations/git/git_repo.go new file mode 100644 index 0000000..5744295 --- /dev/null +++ b/internal/integrations/git/git_repo.go @@ -0,0 +1,106 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package git + +import ( + "path/filepath" + + "github.com/okdp/okdp-server/internal/integrations/git/client" + k8sclient "github.com/okdp/okdp-server/internal/integrations/k8s/client" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +type Repository struct { + *k8sclient.KubeClients +} + +func NewRepository() *Repository { + return &Repository{ + k8sclient.GetClients(), + } +} + +func (r Repository) ListGitRepos(clusterID string, namespace string) ([]*model.GitRepository, *model.ServerResponse) { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return nil, err + } + return kubeClient.ListGitRepos(namespace) +} + +func (r Repository) GetGitRepo(clusterID string, namespace string, kustomizationName string) (*model.GitRepository, *model.ServerResponse) { + gitRepos, err := r.ListGitRepos(clusterID, namespace) + if err != nil { + return nil, err + } + + for _, repo := range gitRepos { + if repo.Name == kustomizationName { + return repo, nil + } + } + return nil, model.RepoNotFoundError(clusterID, namespace, kustomizationName) +} + +func (r Repository) GetContents(clusterID string, namespace string, kustomizationName string) ([]*model.GitContent, *model.ServerResponse) { + repo, err := r.GetGitRepo(clusterID, namespace, kustomizationName) + if err != nil { + return nil, err + } + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return nil, err + } + auth, err := kubeClient.GetAuthMethod(repo.Credentials.SecretRef, namespace) + if err != nil { + return nil, err + } + return client.DoReadContent(repo, auth) +} + +func (r Repository) Write(clusterID string, namespace string, kustomizationName string, content string, commitOpts *model.GitCommit, path string) *model.ServerResponse { + repo, err := r.GetGitRepo(clusterID, namespace, kustomizationName) + if err != nil { + return err + } + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return err + } + auth, err := kubeClient.GetAuthMethod(repo.Credentials.SecretRef, namespace) + if err != nil { + return err + } + return client.DoPushContent(repo, auth, content, commitOpts, utils.PathOrFallback(path, filepath.Join(repo.Path, path))) +} + +func (r Repository) DeleteFile(clusterID string, namespace string, kustomizationName string, commitOpts *model.GitCommit, path string) *model.ServerResponse { + repo, err := r.GetGitRepo(clusterID, namespace, kustomizationName) + if err != nil { + return err + } + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return err + } + auth, err := kubeClient.GetAuthMethod(repo.Credentials.SecretRef, namespace) + if err != nil { + return err + } + return client.DoDeleteFile(repo, auth, commitOpts, path) +} diff --git a/internal/integrations/k8s/client/client.go b/internal/integrations/k8s/client/client.go new file mode 100644 index 0000000..84df365 --- /dev/null +++ b/internal/integrations/k8s/client/client.go @@ -0,0 +1,169 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "fmt" + "sync" + + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + corev1 "k8s.io/api/core/v1" + apiruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + k8s "sigs.k8s.io/controller-runtime/pkg/client" + + kubocdv1alpha1 "kubocd/api/v1alpha1" + + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/config" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +var ( + instance *KubeClients + once sync.Once +) + +type KubeClients struct { + clients map[string]*KubeClient +} + +type KubeClient struct { + k8s.Client + clusterID string +} + +func GetClients() *KubeClients { + once.Do(func() { + clients := make(map[string]*KubeClient) + clusters := config.GetAppConfig().Clusters + + for _, cluster := range clusters { + log.Info("K8S Cluster configuration: %+v", cluster) + + config, err := buildConfig(cluster) + if err != nil { + log.Fatal("Failed to get config for cluster ID '%s (%s)': %v", cluster.ID, cluster.Env, err) + } + + kubeClient, err := k8s.New(config, k8s.Options{ + Scheme: newScheme(), + }) + if err != nil { + log.Fatal("Error creating new k8s client for cluster ID '%s (%s)': %v", cluster.ID, cluster.Env, err) + } + + clients[utils.MapKey(cluster.ID)] = &KubeClient{kubeClient, cluster.ID} + } + + instance = &KubeClients{clients: clients} + }) + + return instance +} + +func (c KubeClients) GetClient(clusterID string) (*KubeClient, *model.ServerResponse) { + client, found := c.clients[clusterID] + if !found { + return nil, model.ClusterNotFoundError(clusterID) + } + + return client, nil +} + +func newScheme() *apiruntime.Scheme { + scheme := apiruntime.NewScheme() + _ = sourcev1.AddToScheme(scheme) + _ = kustomizev1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + _ = kubocdv1alpha1.AddToScheme(scheme) + return scheme +} + +// buildConfig constructs a Kubernetes REST config based on the cluster's authentication method. +// Supported auth types: +// - K8SAuthKubeConfig: uses a kubeconfig file and context. +// - K8SInCluster: uses in-cluster service account credentials. +// Unsupported auth types will return an error. +// +// Params: +// +// cluster - pointer to the cluster configuration model. +// +// Returns: +// +// *restclient.Config - Kubernetes REST configuration. +// error - any error encountered during config building. +func buildConfig(cluster *model.Cluster) (*restclient.Config, error) { + switch cluster.AuthType() { + case constants.K8SAuthKubeConfig: + config, err := buildKubeConfig( + cluster.Auth.Kubeconfig.APIServer, + cluster.Auth.Kubeconfig.Context, + cluster.Auth.Kubeconfig.Path, + ) + if err != nil { + return nil, err + } + if cluster.Auth.Kubeconfig.InsecureSkipTlsVerify { + log.Warn("TLS verification is disabled for cluster ID: %s (%s).", cluster.ID, cluster.Env) + config.Insecure = true + config.CAFile = "" + config.CAData = nil + } + return config, nil + + case constants.K8SInCluster: + return rest.InClusterConfig() + + case constants.K8SAuthCertificate, constants.K8SAuthBeaer: + return nil, fmt.Errorf("authentication method %s not supported", cluster.AuthType()) + + default: + return nil, fmt.Errorf("no authentication credentials found") + } +} + +// buildKubeConfig builds Kubernetes client config using optional apiServer URL, +// optional context (defaults to current context if empty), +// and explicit kubeconfig path. +func buildKubeConfig(masterURL, context, kubeconfigPath string) (*restclient.Config, error) { + loadingRules := &clientcmd.ClientConfigLoadingRules{ + ExplicitPath: kubeconfigPath, + } + + overrides := &clientcmd.ConfigOverrides{} + + if context != "" { + overrides.CurrentContext = context + } + + if masterURL != "" { + overrides.ClusterInfo = clientcmdapi.Cluster{ + Server: masterURL, + } + } + + clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) + return clientConfig.ClientConfig() +} diff --git a/internal/integrations/k8s/client/fluxcd.go b/internal/integrations/k8s/client/fluxcd.go new file mode 100644 index 0000000..ae660b7 --- /dev/null +++ b/internal/integrations/k8s/client/fluxcd.go @@ -0,0 +1,109 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2" + k8s "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +func (c KubeClient) ListKutomizations(ctx context.Context, namespaces ...string) ([]*kustomizev1.Kustomization, *model.ServerResponse) { + var kustomizationList kustomizev1.KustomizationList + if err := c.List(ctx, &kustomizationList); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to list Kustomizations '%s' ", err.Error()) + } + + filtered := utils.Filter(kustomizationList.Items, func(k kustomizev1.Kustomization) bool { + return len(namespaces) == 0 || utils.Contains(namespaces, k.Namespace) + }) + + return filtered, nil + +} + +func (c KubeClient) ListGitRepositories(ctx context.Context, namespaces ...string) ([]*sourcev1.GitRepository, *model.ServerResponse) { + + var repos sourcev1.GitRepositoryList + if err := c.List(ctx, &repos); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to list Git Repositories '%s'", err.Error()) + } + + filtered := utils.Filter(repos.Items, func(k sourcev1.GitRepository) bool { + return utils.Contains(namespaces, k.Namespace) + }) + + return filtered, nil +} + +func (c KubeClient) GetGitRepository(ctx context.Context, name string, namespace string) (*sourcev1.GitRepository, *model.ServerResponse) { + repoKey := k8s.ObjectKey{ + Namespace: namespace, + Name: name, + } + var repo sourcev1.GitRepository + err := c.Get(ctx, repoKey, &repo) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to get fluxcd Git Repository '%s' in namespace '%s', details: '%s'", name, namespace, err.Error()) + } + + return &repo, nil +} + +func (c KubeClient) ListOCIRepositories(ctx context.Context, namespaces ...string) ([]*sourcev1b2.OCIRepository, *model.ServerResponse) { + + var repos sourcev1b2.OCIRepositoryList + if err := c.List(ctx, &repos); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to list OCI Repositories '%s'", err.Error()) + } + + filtered := utils.Filter(repos.Items, func(k sourcev1b2.OCIRepository) bool { + return utils.Contains(namespaces, k.Namespace) + }) + + return filtered, nil +} + +func (c KubeClient) GetOCIRepository(ctx context.Context, name string, namespace string) (*sourcev1b2.OCIRepository, *model.ServerResponse) { + repoKey := k8s.ObjectKey{ + Namespace: namespace, + Name: name, + } + var repo sourcev1b2.OCIRepository + err := c.Get(ctx, repoKey, &repo) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to get fluxcd OCI Repository '%s' in namespace '%s', details: '%s'", name, namespace, err.Error()) + } + + return &repo, nil +} diff --git a/internal/integrations/k8s/client/git.go b/internal/integrations/k8s/client/git.go new file mode 100644 index 0000000..92a5d43 --- /dev/null +++ b/internal/integrations/k8s/client/git.go @@ -0,0 +1,70 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" + + "github.com/okdp/okdp-server/internal/common/constants" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +func (c KubeClient) ListGitRepos(namespaces ...string) ([]*model.GitRepository, *model.ServerResponse) { + + ctx := context.Background() + + var kustomizations []*kustomizev1.Kustomization + kustomizations, err := c.ListKutomizations(ctx, namespaces...) + if err != nil { + return nil, err + } + + kustomizations = utils.Filter2(kustomizations, func(k kustomizev1.Kustomization) bool { + return k.Spec.SourceRef.Kind == constants.GitRepository + }) + + gitRepos := make([]*model.GitRepository, 0, len(kustomizations)) + + for _, k := range kustomizations { + namespace := utils.DefaultIfEmpty(k.Spec.SourceRef.Namespace, k.Namespace) + fluxRepo, err := c.GetGitRepository(ctx, k.Spec.SourceRef.Name, namespace) + if err != nil { + return nil, err + } + gitRepo := &model.GitRepository{ + RepoURL: fluxRepo.Spec.URL, + Ref: BranchOrTag(fluxRepo.Spec.Reference.Branch, fluxRepo.Spec.Reference.Tag), + Name: k.Name, + Namespace: k.Namespace, + Path: k.Spec.Path, + } + gitRepo.Credentials.SecretRef = fluxRepo.Spec.SecretRef.Name + gitRepos = append(gitRepos, gitRepo) + } + + return gitRepos, nil +} + +func BranchOrTag(branch, tag string) string { + if branch != "" { + return "refs/heads/" + branch + } + return "refs/tags/" + tag +} diff --git a/internal/integrations/k8s/client/k8s.go b/internal/integrations/k8s/client/k8s.go new file mode 100644 index 0000000..11f717f --- /dev/null +++ b/internal/integrations/k8s/client/k8s.go @@ -0,0 +1,50 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + "strings" + + corev1 "k8s.io/api/core/v1" + + "github.com/okdp/okdp-server/internal/model" +) + +func (c KubeClient) ListNamespaces(ctx context.Context) ([]string, *model.ServerResponse) { + var namespaceList corev1.NamespaceList + err := c.List(ctx, &namespaceList) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to list Kubernetes namespaces on clusterId '%s', details: '%s'", c.clusterID, err.Error()) + } + + exclude := map[string]bool{ + "local-path-storage": true, + } + + namespaces := []string{} + for _, ns := range namespaceList.Items { + if exclude[ns.Name] || strings.HasPrefix(ns.Name, "kube-") { + continue + } + namespaces = append(namespaces, ns.Name) + } + + return namespaces, nil +} diff --git a/internal/integrations/k8s/client/kubocd.go b/internal/integrations/k8s/client/kubocd.go new file mode 100644 index 0000000..88b8251 --- /dev/null +++ b/internal/integrations/k8s/client/kubocd.go @@ -0,0 +1,142 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8s "sigs.k8s.io/controller-runtime/pkg/client" + + kubocdv1alpha1 "kubocd/api/v1alpha1" + + "github.com/okdp/okdp-server/internal/common/constants" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +func (c KubeClient) ListReleases(ctx context.Context, namespaces ...string) ([]*model.Release, *model.ServerResponse) { + + var releaseList kubocdv1alpha1.ReleaseList + if err := c.List(ctx, &releaseList); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to list KuboCD Releases '%s'", err.Error()) + } + + converted := model.ReleaseList(releaseList) + + filtered := utils.Filter2(converted.ToReleases(), func(k model.Release) bool { + return len(namespaces) == 0 || utils.Contains(namespaces, k.Namespace) + }) + + return filtered, nil +} + +func (c KubeClient) GetRelease(ctx context.Context, namespace string, releaseName string) (*model.Release, *model.ServerResponse) { + releaseKey := k8s.ObjectKey{ + Namespace: namespace, + Name: releaseName, + } + + var release kubocdv1alpha1.Release + if err := c.Get(ctx, releaseKey, &release); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to get KuboCD Release '%s'", err.Error()) + } + + converted := model.Release(release) + converted.SanitizeMetadata() + + return &converted, nil +} + +func (c KubeClient) GetReleaseStatus(ctx context.Context, namespace string, releaseName string) (*model.ReleaseStatus, *model.ServerResponse) { + releaseKey := k8s.ObjectKey{ + Namespace: namespace, + Name: releaseName, + } + + var release kubocdv1alpha1.Release + if err := c.Get(ctx, releaseKey, &release); err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to get KuboCD Release Status '%s'", err.Error()) + } + + converted := model.ReleaseStatus(release.Status) + + return &converted, nil +} + +func (c KubeClient) CreateRelease(ctx context.Context, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + rel := kubocdv1alpha1.Release(*release) + rel.Namespace = namespace + var err error + + if dryRun { + err = c.Create(ctx, &rel, &k8s.CreateOptions{DryRun: []string{constants.All}}) + } else { + err = c.Create(ctx, &rel) + } + if err != nil { + return model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to create KuboCD Release '%s/%s (%s)', details: '%s'", release.Namespace, release.Name, dryRun, err.Error()) + } + + return model.NewServerResponse(model.K8sClusterResponse).Created("Successfuly created release %s/%s", release.Namespace, release.Name) +} + +func (c KubeClient) UpdateRelease(ctx context.Context, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + rel := kubocdv1alpha1.Release(*release) + rel.Namespace = namespace + var err error + + if dryRun { + err = c.Update(ctx, &rel, &k8s.UpdateOptions{DryRun: []string{constants.All}}) + } else { + err = c.Update(ctx, &rel) + } + if err != nil { + return model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to update KuboCD Release '%s/%s (%s)', details: '%s'", release.Namespace, release.Name, dryRun, err.Error()) + } + + return model.NewServerResponse(model.K8sClusterResponse).Updated("Successfuly updated release %s/%s", release.Namespace, release.Name) +} + +func (c KubeClient) DeleteRelease(ctx context.Context, namespace string, releaseName string) *model.ServerResponse { + rel := kubocdv1alpha1.Release{ + ObjectMeta: metav1.ObjectMeta{ + Name: releaseName, + Namespace: namespace, + }, + } + + err := c.Delete(ctx, &rel) + if err != nil { + return model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to delete KuboCD Release '%s/%s', details: '%s'", namespace, releaseName, err.Error()) + } + + return model.NewServerResponse(model.K8sClusterResponse).Deleted("Successfuly deleted release %s", releaseName) + +} diff --git a/internal/integrations/k8s/client/secret.go b/internal/integrations/k8s/client/secret.go new file mode 100644 index 0000000..4cc8688 --- /dev/null +++ b/internal/integrations/k8s/client/secret.go @@ -0,0 +1,120 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + "os" + + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" + "github.com/okdp/okdp-server/internal/model" + "github.com/skeema/knownhosts" + corev1 "k8s.io/api/core/v1" + k8s "sigs.k8s.io/controller-runtime/pkg/client" + + log "github.com/okdp/okdp-server/internal/common/logging" +) + +type K8SSecret struct { + corev1.Secret +} + +func (c KubeClient) GetSecret(ctx context.Context, name string, namespace string) (*K8SSecret, *model.ServerResponse) { + secretKey := k8s.ObjectKey{ + Namespace: namespace, + Name: name, + } + var secret corev1.Secret + err := c.Get(ctx, secretKey, &secret) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to get Kubernetes secret '%s' in namespace '%s', details: '%s'", name, namespace, err.Error()) + } + + return &K8SSecret{secret}, nil + +} + +func (c KubeClient) GetAuthMethod(secretName string, namespace string) (transport.AuthMethod, *model.ServerResponse) { + secret, err := c.GetSecret(context.Background(), secretName, namespace) + if err != nil { + return nil, err + } + auth, err := secret.ToAuthMethod() + if err != nil { + return nil, err + } + return auth, nil +} + +func (s K8SSecret) ToAuthMethod() (transport.AuthMethod, *model.ServerResponse) { + switch { + case s.Data != nil && s.Data["password"] != nil: + log.Fatal("GIT repository access will use git token") + return &http.BasicAuth{ + Username: string(s.Data["username"]), + Password: string(s.Data["password"]), + }, nil + + case s.Data != nil && s.Data["identity"] != nil: + return BuildKey(s.Secret) + + default: + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Invalid secret %s=%s", s.Name, s.Namespace) + } +} + +func BuildKey(secret corev1.Secret) (*ssh.PublicKeys, *model.ServerResponse) { + key, err := ssh.NewPublicKeys("git", secret.Data["identity"], "") + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to create new public key from secret %s=%s, details: %s", secret.Name, secret.Namespace, err.Error()) + } + file, err := os.CreateTemp(os.TempDir(), "git_known_hosts") + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to create new tmp dir for git_known_hosts from secret %s=%s, details: %s", secret.Name, secret.Namespace, err.Error()) + } + defer func() { + if err := file.Close(); err != nil { + log.Error("Error closing file: %v", err) + } + _ = os.Remove(file.Name()) + }() + + _, err = file.Write(secret.Data["known_hosts"]) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to write known_hosts from secret %s=%s, details: %s", secret.Name, secret.Namespace, err.Error()) + } + db, err := knownhosts.NewDB(file.Name()) + if err != nil { + return nil, model. + NewServerResponse(model.K8sClusterResponse). + UnprocessableEntity("Failed to create a new known hosts database from secret %s=%s, details: %s", secret.Name, secret.Namespace, err.Error()) + } + key.HostKeyCallback = db.HostKeyCallback() + return key, nil +} diff --git a/internal/services/component.go b/internal/integrations/k8s/cluster.go similarity index 50% rename from internal/services/component.go rename to internal/integrations/k8s/cluster.go index c1fa13f..a79d23d 100644 --- a/internal/services/component.go +++ b/internal/integrations/k8s/cluster.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,28 +14,29 @@ * limitations under the License. */ -package services +package k8s import ( - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad" + "strings" + + "github.com/okdp/okdp-server/internal/config" "github.com/okdp/okdp-server/internal/model" ) -type ComponentService struct { - component *kad.ComponentClient -} - -func NewComponentService() *ComponentService { - return &ComponentService{ - component: kad.NewComponentClient(), +func (r K8S) ListClusters() []*model.Cluster { + clusters := config.GetAppConfig().Clusters + if clusters == nil { + return []*model.Cluster{} } + return clusters } -func (s ComponentService) Get(kadInstanceID string, name string, catalog *string) (*model.Component, *errors.ServerError) { - return s.component.Get(kadInstanceID, name, catalog) -} - -func (s ComponentService) List(kadInstanceID string, catalog *string) (*model.Components, *errors.ServerError) { - return s.component.List(kadInstanceID, catalog) +func (r K8S) GetCluster(clusterID string) (*model.Cluster, *model.ServerResponse) { + clusters := config.GetAppConfig().Clusters + for _, cluster := range clusters { + if strings.EqualFold(cluster.ID, clusterID) { + return cluster, nil + } + } + return nil, model.ClusterNotFoundError(clusterID) } diff --git a/internal/model/component.go b/internal/integrations/k8s/k8s.go similarity index 55% rename from internal/model/component.go rename to internal/integrations/k8s/k8s.go index bf3c2f1..1383ec8 100644 --- a/internal/model/component.go +++ b/internal/integrations/k8s/k8s.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,29 @@ * limitations under the License. */ -package model +package k8s import ( - "github.com/okdp/okdp-server/api/openapi/v3/_api" + "context" + + "github.com/okdp/okdp-server/internal/integrations/k8s/client" + "github.com/okdp/okdp-server/internal/model" ) -type Component = _api.Component -type Components = []*Component +type K8S struct { + *client.KubeClients +} + +func NewK8S() *K8S { + return &K8S{ + client.GetClients(), + } +} + +func (s K8S) ListNamespaces(clusterID string) ([]string, *model.ServerResponse) { + kubeClient, err := s.GetClient(clusterID) + if err != nil { + return nil, err + } + return kubeClient.ListNamespaces(context.Background()) +} diff --git a/internal/integrations/k8s/kubocd.go b/internal/integrations/k8s/kubocd.go new file mode 100644 index 0000000..fe06c9c --- /dev/null +++ b/internal/integrations/k8s/kubocd.go @@ -0,0 +1,71 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package k8s + +import ( + "context" + + "github.com/okdp/okdp-server/internal/model" +) + +func (r K8S) ListReleases(clusterID string, namespaces ...string) ([]*model.Release, *model.ServerResponse) { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return nil, err + } + return kubeClient.ListReleases(context.Background(), namespaces...) +} + +func (r K8S) GetRelease(clusterID string, namespace string, releaseName string) (*model.Release, *model.ServerResponse) { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return nil, err + } + return kubeClient.GetRelease(context.Background(), namespace, releaseName) +} + +func (r K8S) GetReleaseStatus(clusterID string, namespace string, releaseName string) (*model.ReleaseStatus, *model.ServerResponse) { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return nil, err + } + return kubeClient.GetReleaseStatus(context.Background(), namespace, releaseName) +} + +func (r K8S) CreateRelease(clusterID string, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return err + } + return kubeClient.CreateRelease(context.Background(), namespace, release, dryRun) +} + +func (r K8S) UpdateRelease(clusterID string, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return err + } + return kubeClient.UpdateRelease(context.Background(), namespace, release, dryRun) +} + +func (r K8S) DeleteRelease(clusterID string, namespace string, releaseName string) *model.ServerResponse { + kubeClient, err := r.GetClient(clusterID) + if err != nil { + return err + } + return kubeClient.DeleteRelease(context.Background(), namespace, releaseName) +} diff --git a/internal/integrations/oci/client/client.go b/internal/integrations/oci/client/client.go new file mode 100644 index 0000000..22f9307 --- /dev/null +++ b/internal/integrations/oci/client/client.go @@ -0,0 +1,271 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package client + +import ( + "context" + "encoding/json" + "errors" + "io" + "net/http" + "strings" + "sync" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content/memory" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" + "oras.land/oras-go/v2/registry/remote/errcode" + "oras.land/oras-go/v2/registry/remote/retry" + + log "github.com/okdp/okdp-server/internal/common/logging" + "github.com/okdp/okdp-server/internal/config" + "github.com/okdp/okdp-server/internal/model" + "github.com/okdp/okdp-server/internal/utils" +) + +var ( + instance *RepositoryClients + once sync.Once +) + +type RepositoryClients struct { + clients map[string]*RepositoryClient +} + +type RepositoryClient struct { + *remote.Repository +} + +func GetClients() *RepositoryClients { + once.Do(func() { + clients := make(map[string]*RepositoryClient) + catalogs := config.GetAppConfig().Catalogs + for _, catalog := range catalogs { + log.Info("Container Registry configuration: %+v", catalog) + for _, p := range catalog.Packages { + repo, err := remote.NewRepository(strings.TrimSuffix(catalog.RepoURL, "/") + "/" + p.Name) + if err != nil { + log.Fatal("Failed to create a client to the remote repository %s: %v", catalog.RepoURL, err) + } + + creds, err := getOCIRepoCredentials(catalog) + + if err != nil { + log.Fatal("Unable to get login and password from dockerconfigjson for the repo: %s/%s", catalog.ID, catalog.RepoURL) + } + + repo.Client = &auth.Client{ + Client: retry.DefaultClient, + Cache: auth.NewCache(), + Credential: creds, + } + clients[utils.MapKey(catalog.ID, p.Name)] = &RepositoryClient{repo} + } + } + instance = &RepositoryClients{clients: clients} + }) + return instance +} + +func ListCatalogs() []*model.Catalog { + catalogs := config.GetAppConfig().Catalogs + if catalogs == nil { + return []*model.Catalog{} + } + return catalogs +} + +func GetCatalog(catalogID string) (*model.Catalog, *model.ServerResponse) { + catalogs := config.GetAppConfig().Catalogs + for _, catalog := range catalogs { + if strings.EqualFold(catalog.ID, catalogID) { + return catalog, nil + } + } + return nil, model.CatalogNotFoundError(catalogID) +} + +func GetPackages(catalogID string) ([]*model.Package, *model.ServerResponse) { + catalog, err := GetCatalog(catalogID) + if err != nil { + return nil, err + } + packages := make([]*model.Package, 0, len(catalog.Packages)) + for _, p := range catalog.Packages { + result, err := getPackage(catalogID, p.Name, catalog.RepoURL) + if err != nil { + return nil, err + } + packages = append(packages, result) + } + return packages, nil +} + +func GetPackage(catalogID string, name string) (*model.Package, *model.ServerResponse) { + catalog, err := GetCatalog(catalogID) + if err != nil { + return nil, err + } + for _, p := range catalog.Packages { + if strings.EqualFold(p.Name, name) { + return getPackage(catalogID, p.Name, catalog.RepoURL) + } + } + return nil, model.CatalogPackageNotFoundError(catalogID, name) +} + +func GetPackageDefinition(catalogID string, name string, version string) (map[string]interface{}, *model.ServerResponse) { + repo, err := getRepoClient(catalogID, name) + if err != nil { + return nil, err + } + return repo.fetchDefinition(version) +} + +func getPackage(catalogID string, name string, repoURL string) (*model.Package, *model.ServerResponse) { + repo, err := getRepoClient(catalogID, name) + if err != nil { + return nil, err + } + versions, err := repo.listTags() + if err != nil { + return nil, err + } + return &model.Package{ + Name: name, + Versions: utils.SortVersions(versions), + RepoURL: repoURL, + }, nil +} + +func (r RepositoryClient) listTags() ([]string, *model.ServerResponse) { + ctx := context.Background() + var allTags []string + var last string + var err *model.ServerResponse + for { + er := r.Tags(ctx, last, func(tags []string) error { + if len(tags) == 0 { + return io.EOF + } + last = tags[len(tags)-1] + allTags = append(allTags, tags...) + return nil + }) + + statusCode := http.StatusBadGateway + if er != nil { + if er != io.EOF { + var httpErr *errcode.ErrorResponse + if errors.As(er, &httpErr) { + err = model. + NewServerResponse(model.RegistryResponse).GenericError(httpErr.StatusCode, httpErr.Error()) + } else { + err = model. + NewServerResponse(model.RegistryResponse).GenericError(statusCode, er.Error()) + } + } + break + } + } + + return allTags, err +} + +func (r RepositoryClient) fetchDefinition(version string) (map[string]interface{}, *model.ServerResponse) { + ctx := context.Background() + // Pull to memory + memStore := memory.New() + desc, err := oras.Copy(ctx, r.Repository, version, memStore, version, oras.DefaultCopyOptions) + if err != nil { + log.Error("Failed to copy definition into the memstore: %v", err) + return nil, model. + NewServerResponse(model.OkdpServerResponse).UnprocessableEntity(err.Error()) + } + + // Decode manifest + manifestReader, err := memStore.Fetch(ctx, desc) + if err != nil { + log.Error("Failed to fetch definition from the memstore: %v", err) + return nil, model. + NewServerResponse(model.OkdpServerResponse).UnprocessableEntity(err.Error()) + } + defer manifestReader.Close() + + var manifest ocispec.Manifest + if err := json.NewDecoder(manifestReader).Decode(&manifest); err != nil { + log.Error("Failed to decode definition: %v", err) + return nil, model. + NewServerResponse(model.OkdpServerResponse).UnprocessableEntity(err.Error()) + } + + configReader, err := memStore.Fetch(ctx, manifest.Config) + if err != nil { + log.Error("Failed to fetch the definition content: %v", err) + return nil, model. + NewServerResponse(model.OkdpServerResponse).UnprocessableEntity(err.Error()) + } + defer configReader.Close() + + var definition map[string]interface{} + if err := json.NewDecoder(configReader).Decode(&definition); err != nil { + log.Error("Failed to decode the definition content: %v", err) + return nil, model. + NewServerResponse(model.OkdpServerResponse).UnprocessableEntity(err.Error()) + } + return definition, nil +} + +func getRepoClient(catalogID string, packageName string) (*RepositoryClient, *model.ServerResponse) { + instance, found := instance.clients[utils.MapKey(catalogID, packageName)] + if !found { + return nil, model.CatalogPackageNotFoundError(catalogID, packageName) + } + return instance, nil +} + +func getOCIRepoCredentials(catalog *model.Catalog) (auth.CredentialFunc, error) { + + var empty auth.CredentialFunc = func(_ context.Context, _ string) (auth.Credential, error) { + return auth.EmptyCredential, nil + } + + if !catalog.IsAuthenticated() { + return empty, nil + } + + login := utils.ResolveEnv(*catalog.Credentials.RobotAccountName) + passwd := utils.ResolveEnv(*catalog.Credentials.RobotAccountToken) + dockerjson := utils.ResolveEnv(*catalog.Credentials.Dockerconfigjson) + + if login == "" && passwd == "" { + if dockerjson == "" { + return empty, nil + } + var err error + login, passwd, err = utils.ToLoginPassword(dockerjson) + if err != nil { + return nil, err + } + } + return auth.StaticCredential(catalog.RepoHost(), auth.Credential{ + Username: login, + Password: passwd, + }), nil +} diff --git a/internal/integrations/oci/repo_catalog.go b/internal/integrations/oci/repo_catalog.go new file mode 100644 index 0000000..ff1138f --- /dev/null +++ b/internal/integrations/oci/repo_catalog.go @@ -0,0 +1,52 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package oci + +import ( + "github.com/okdp/okdp-server/internal/integrations/oci/client" + "github.com/okdp/okdp-server/internal/model" +) + +type RepoCatalog struct { + r *client.RepositoryClients +} + +func NewRepoCatalog() *RepoCatalog { + return &RepoCatalog{ + r: client.GetClients(), + } +} + +func (r RepoCatalog) ListCatalogs() []*model.Catalog { + return client.ListCatalogs() +} + +func (r RepoCatalog) GetCatalog(catalogID string) (*model.Catalog, *model.ServerResponse) { + return client.GetCatalog(catalogID) +} + +func (r RepoCatalog) GetPackages(catalogID string) ([]*model.Package, *model.ServerResponse) { + return client.GetPackages(catalogID) +} + +func (r RepoCatalog) GetPackage(catalogID string, name string) (*model.Package, *model.ServerResponse) { + return client.GetPackage(catalogID, name) +} + +func (r RepoCatalog) GetPackageDefinition(catalogID string, name string, version string) (map[string]interface{}, *model.ServerResponse) { + return client.GetPackageDefinition(catalogID, name, version) +} diff --git a/internal/kad/catalog_client.go b/internal/kad/catalog_client.go deleted file mode 100644 index b064f74..0000000 --- a/internal/kad/catalog_client.go +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kad - -import ( - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad/client" - "github.com/okdp/okdp-server/internal/model" -) - -type CatalogClient struct { - KAD *client.KadClients -} - -func NewCatalogClient() *CatalogClient { - return &CatalogClient{ - KAD: client.GetClients(), - } -} - -func (c CatalogClient) Get(kadInstanceID string, name string) (*model.Catalog, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.CatalogURL + "/" + name) - return client.DoGet[model.Catalog](req) -} - -func (c CatalogClient) List(kadInstanceID string) (*model.Catalogs, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.CatalogURL) - return client.DoGet[model.Catalogs](req) -} diff --git a/internal/kad/client/client.go b/internal/kad/client/client.go deleted file mode 100644 index 06db19d..0000000 --- a/internal/kad/client/client.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package client - -import ( - "crypto/tls" - "encoding/json" - "net/http" - "sync" - - "github.com/go-resty/resty/v2" - "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/errors" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/utils" -) - -var ( - instance *KadClients - once sync.Once -) - -type KadClients struct { - clients map[string]*KadClient -} - -type KadClient struct { - *resty.Client -} - -type Request struct { - *resty.Request -} - -// KAD errors response are plain text -// type KadError struct { -// message string -// statusCode int -// } - -func GetClients() *KadClients { - once.Do(func() { - clients := make(map[string]*KadClient) - kadsConf := config.GetAppConfig().Kad - for _, kadConf := range kadsConf { - log.Info("KAD configuration: %s", kadConf) - client := resty.New() - client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: kadConf.InsecureSkipVerify}). - SetAuthToken(kadConf.AuthBearer). - SetHeader("Content-Type", "application/json"). - SetBaseURL(kadConf.APIURL) - clients[kadConf.ID] = &KadClient{client} - } - instance = &KadClients{clients: clients} - }) - return instance -} - -func (c *KadClients) ID(id string) (*KadClient, *errors.ServerError) { - client, found := c.clients[id] - if !found { - return nil, invalidInstanceError(id) - } - return client, nil -} - -func ListInstances() []config.KadInstance { - return config.GetAppConfig().Kad -} - -func GetInstanceByID(id string) (config.KadInstance, *errors.ServerError) { - instances := ListInstances() - for _, i := range instances { - if i.ID == id { - return i, nil - } - } - return config.KadInstance{}, errors.OfType(errors.OkdpServer). - NotFoundError("kad instance with id %s not found", id) -} - -func DoGet[T any](request *resty.Request) (*T, *errors.ServerError) { - request.Method = resty.MethodGet - return doExecute[T](request) -} - -func DoPut[T any](request *resty.Request) (*T, *errors.ServerError) { - request.Method = resty.MethodPut - return doExecute[T](request) -} - -func (c *KadClient) NewRequest(url string) *resty.Request { - req := c.R() - req.URL = url - return req -} - -func doExecute[T any](request *resty.Request) (*T, *errors.ServerError) { - log.Info("Sending %s request to KAD at the endpoint %s:", request.Method, request.URL) - var object T - // request.SetError(&KadError{}) - resp, err := request.Send() - - if err != nil { - return nil, errors.OfType(errors.Kad).Forbidden(err) - } - - if resp.IsError() { - // KAD errors response are plain text - return nil, errors.OfType(errors.Kad). - GenericError(resp.StatusCode(), "Kad rejected the request, reason: %s", resp.String()) - } - - err = json.Unmarshal([]byte(resp.String()), &object) - - if err != nil { - return &object, errors.OfType(errors.OkdpServer). - GenericError(http.StatusUnprocessableEntity, "Unable to process kad response, reason: %+v", err) - } - - return &object, nil -} - -func invalidInstanceError(provided string) *errors.ServerError { - instances := utils.Map(ListInstances(), func(k config.KadInstance) string { return k.ID }) - return errors.OfType(errors.OkdpServer). - NotFoundError("kad instance with id %s not found, valid ones: %+v", provided, instances) -} diff --git a/internal/kad/component_client.go b/internal/kad/component_client.go deleted file mode 100644 index ca08e67..0000000 --- a/internal/kad/component_client.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kad - -import ( - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad/client" - "github.com/okdp/okdp-server/internal/model" -) - -type ComponentClient struct { - KAD *client.KadClients -} - -func NewComponentClient() *ComponentClient { - return &ComponentClient{ - KAD: client.GetClients(), - } -} - -func (c ComponentClient) Get(kadInstanceID string, name string, catalog *string) (*model.Component, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.ComponentURL + "/" + name) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.Component](req) -} - -func (c ComponentClient) List(kadInstanceID string, catalog *string) (*model.Components, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.ComponentURL) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.Components](req) -} diff --git a/internal/kad/component_release_client.go b/internal/kad/component_release_client.go deleted file mode 100644 index b33db6d..0000000 --- a/internal/kad/component_release_client.go +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kad - -import ( - "bytes" - "net/http" - - "github.com/go-resty/resty/v2" - "github.com/goccy/go-yaml" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad/client" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/model" -) - -type ComponentReleaseClient struct { - KAD *client.KadClients -} - -func NewComponentReleaseClient() *ComponentReleaseClient { - return &ComponentReleaseClient{ - KAD: client.GetClients(), - } -} - -func (c ComponentReleaseClient) Get(kadInstanceID string, name string, catalog *string) (*model.ComponentReleaseResponse, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.ComponentReleaseURL + "/" + name) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.ComponentReleaseResponse](req) -} - -func (c ComponentReleaseClient) List(kadInstanceID string, catalog *string) (*model.ComponentReleasesResponse, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.ComponentReleaseURL) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.ComponentReleasesResponse](req) -} - -func (c ComponentReleaseClient) UploadAsYaml(kadInstanceID string, name string, - componentReleaseRequest model.ComponentReleaseRequest, - commitData map[string]string) (*model.GitCommit, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - - // Convert the ComponentReleases into YAML - result := map[string]interface{}{ - "componentReleases": componentReleaseRequest.ComponentReleases, - } - componentReleasesYAML, err2 := yaml.Marshal(result) - if err2 != nil { - log.Error("Error marshaling ComponentReleases to YAML: %v", err) - return nil, errors.OfType(errors.OkdpServer). - GenericError(http.StatusBadRequest, "Unable to parse json to yaml: %+v", err2) - } - - log.Info("Uploading Component release (Name: %s, Git Path: %s): \n%s, \n Author Info: %s", name, componentReleaseRequest.GitRepoFolder, - string(componentReleasesYAML), commitData) - - req := kadClient.NewRequest(constants.GitURL + "/" + componentReleaseRequest.GitRepoFolder + "/" + name + ".yaml"). - SetMultipartFields( - &resty.MultipartField{ - Param: "kadfile", - FileName: name + ".yaml", - ContentType: "application/x-yaml", - Reader: bytes.NewReader(componentReleasesYAML), - }, - ). - SetFormData(commitData) - - return client.DoPut[model.GitCommit](req) -} diff --git a/internal/kad/template_release_client.go b/internal/kad/template_release_client.go deleted file mode 100644 index da8e7e3..0000000 --- a/internal/kad/template_release_client.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kad - -import ( - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad/client" - "github.com/okdp/okdp-server/internal/model" -) - -type TemplateReleaseClient struct { - KAD *client.KadClients -} - -func NewTemplateReleaseClient() *TemplateReleaseClient { - return &TemplateReleaseClient{ - KAD: client.GetClients(), - } -} - -func (c TemplateReleaseClient) Get(kadInstanceID string, name string, catalog *string) (*model.TemplateRelease, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.TemplateReleaseURL + "/" + name) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.TemplateRelease](req) -} - -func (c TemplateReleaseClient) List(kadInstanceID string, catalog *string) (*model.TemplateReleases, *errors.ServerError) { - kadClient, err := c.KAD.ID(kadInstanceID) - if err != nil { - return nil, err - } - req := kadClient.NewRequest(constants.TemplateReleaseURL) - if catalog != nil { - req = req.SetQueryParam("catalog", *catalog) - } - return client.DoGet[model.TemplateReleases](req) -} diff --git a/internal/model/catalog.go b/internal/model/catalog.go index ef9ef5a..12a9d87 100644 --- a/internal/model/catalog.go +++ b/internal/model/catalog.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,35 @@ package model import ( + "strings" + "github.com/okdp/okdp-server/api/openapi/v3/_api" ) -type Catalog = _api.Catalog -type Catalogs = []*Catalog +type Catalog struct { + _api.Catalog `mapstructure:",squash"` +} + +type Package = _api.Package + +func (c Catalog) RepoHost() string { + parts := strings.SplitN(c.RepoURL, "/", 2) + if len(parts) > 0 { + return parts[0] + } + return "" +} + +func (c Catalog) IsAuthenticated() bool { + return c.Credentials != nil +} + +func CatalogNotFoundError(catalogID string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("The catalog with id %s not found.", catalogID) +} + +func CatalogPackageNotFoundError(catalogID string, packageName string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("The package %s not found in the catalog ID %s.", packageName, catalogID) +} diff --git a/internal/controllers/kad_contoller.go b/internal/model/cluster.go similarity index 50% rename from internal/controllers/kad_contoller.go rename to internal/model/cluster.go index b643235..126656d 100644 --- a/internal/controllers/kad_contoller.go +++ b/internal/model/cluster.go @@ -14,36 +14,36 @@ * limitations under the License. */ -package controllers +package model import ( - "net/http" - - "github.com/gin-gonic/gin" - "github.com/okdp/okdp-server/internal/kad/client" + "github.com/okdp/okdp-server/api/openapi/v3/_api" + "github.com/okdp/okdp-server/internal/common/constants" ) -type IKadController struct { - clients *client.KadClients +type Cluster _api.Cluster + +func ClusterNotFoundError(clusterID string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("The cluster with id %s not found.", clusterID) } -func KadController() *IKadController { - clients := client.GetClients() - return &IKadController{ - clients: clients, +func (m Cluster) AuthType() string { + if m.Auth.Kubeconfig != nil { + return constants.K8SAuthKubeConfig } -} -func (r IKadController) GetKadInstance(c *gin.Context, kadInstanceID string) { - instance, err := client.GetInstanceByID(kadInstanceID) - if err != nil { - c.JSON(err.Status, err) - } else { - c.JSON(http.StatusOK, instance) + if m.Auth.Certificate != nil { + return constants.K8SAuthCertificate + } + + if m.Auth.Bearer != nil { + return constants.K8SAuthBeaer + } + + if *m.Auth.InCluster { + return constants.K8SInCluster } -} -func (r IKadController) ListKadInstances(c *gin.Context) { - instances := client.ListInstances() - c.JSON(http.StatusOK, instances) + return "" } diff --git a/internal/model/component_release.go b/internal/model/component_release.go deleted file mode 100644 index d93bd8e..0000000 --- a/internal/model/component_release.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package model - -import ( - "github.com/okdp/okdp-server/api/openapi/v3/_api" - "github.com/okdp/okdp-server/internal/utils" -) - -type ComponentReleaseRequest _api.ComponentReleaseRequest -type ComponentReleaseResponse _api.ComponentReleaseResponse -type ComponentReleasesResponse []*ComponentReleaseResponse -type FlatComponent _api.FlatComponent -type FlatComponents []*FlatComponent - -func (r *ComponentReleasesResponse) Flatten() *FlatComponents { - var flatComponents = make(FlatComponents, 0, 100) - for _, c := range *r { - extC := &FlatComponent{ - ComponentName: c.Spec.Component.Ref.Name, - ComponentVersion: c.Spec.Component.Ref.Version, - PackageName: c.Spec.HelmReleaseName, - PackageVersion: c.Spec.Component.Source.Version, - ComponentReleaseName: c.Spec.Name, - Enabled: c.Spec.Enabled, - Suspended: c.Spec.Component.Suspended, - Protected: c.Spec.Component.Protected, - Catalogs: utils.ArrayNullToEmpty(c.Status.Catalogs), - Usage: c.Status.Usage, - } - flatComponents = append(flatComponents, extC) - } - return &flatComponents -} - -func (f *FlatComponents) AddTemplateReleaseInfo(tri *TemplateReleaseInfo) *FlatComponents { - for _, c := range *f { - summary, found := tri.GetByComponentReleaseName(c.ComponentReleaseName) - if found { - c.TemplateName = summary.TemplateName - c.TemplateVersion = summary.TemplateVersion - c.TemplateReleaseName = summary.TemplateReleaseName - c.Catalogs = append(c.Catalogs, summary.Catalogs...) - } - } - return f -} - -func (f *FlatComponents) ConvertToService() *Services { - var services Services - - componentsByServiceName := make(map[string][]FlatComponent) - for _, c := range *f { - var serviceName string - if c.TemplateReleaseName != "" { - serviceName = c.TemplateReleaseName - } else { - serviceName = c.ComponentReleaseName - } - componentsByServiceName[serviceName] = append(componentsByServiceName[serviceName], *c) - } - - for serviceName, components := range componentsByServiceName { - services = append(services, &Service{ - Name: serviceName, - IsComposition: len(components) > 1, - FlatComponents: components, - }) - } - - return &services - -} diff --git a/internal/model/git.go b/internal/model/git.go new file mode 100644 index 0000000..e36529b --- /dev/null +++ b/internal/model/git.go @@ -0,0 +1,78 @@ +/* + * Copyright 2024 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package model + +import ( + "time" + + git "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" + + "github.com/okdp/okdp-server/api/openapi/v3/_api" + "sigs.k8s.io/yaml" +) + +type GitRepository _api.GitRepository +type GitCommit struct { + Message string + git.CommitOptions +} +type GitContent struct { + Content *[]byte + Path string + URL string +} + +func (c GitContent) ToRelease() (*Release, *ServerResponse) { + var release Release + if err := yaml.Unmarshal(*c.Content, &release); err != nil { + return nil, NewServerResponse(GitRepoResponse). + UnprocessableEntity("Failed to convert yaml file content '%s' into KuboCD Release: %v", c.Path, err) + } + return &release, nil +} + +func RepoNotFoundError(clusterID string, namespace string, fluxrepo string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("The git repo %s not found on namespace %s with cluster id %s.", fluxrepo, namespace, clusterID) +} + +func KuboCDGitReleaseNotFoundError(clusterID string, namespace string, fluxrepo string, releaseName string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("Unable to find KuboCD release '%s' in the git repo referenced by fluxcd repo %s/%s (clusterID: %s).", releaseName, namespace, fluxrepo, clusterID) +} + +func NewGitCommitOptions(message string) *GitCommit { + commit := &GitCommit{ + Message: "[okdp-server] " + message, + CommitOptions: git.CommitOptions{ + Author: &object.Signature{}, + }, + } + commit.CommitOptions.Author.When = time.Now() + return commit +} + +func (c *GitCommit) Author(name string) *GitCommit { + c.CommitOptions.Author.Name = name + return c +} + +func (c *GitCommit) Email(email string) *GitCommit { + c.CommitOptions.Author.Email = email + return c +} diff --git a/internal/model/kubocd.go b/internal/model/kubocd.go new file mode 100644 index 0000000..8daec5d --- /dev/null +++ b/internal/model/kubocd.go @@ -0,0 +1,74 @@ +/* + * Copyright 2024 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package model + +import ( + "sigs.k8s.io/yaml" + + kubocdv1alpha1 "kubocd/api/v1alpha1" + + "github.com/okdp/okdp-server/api/openapi/v3/_api" +) + +type Release kubocdv1alpha1.Release +type ReleaseList kubocdv1alpha1.ReleaseList +type ReleaseStatus kubocdv1alpha1.ReleaseStatus + +type ReleaseInfo _api.ReleaseInfo + +func (r *ReleaseList) ToReleases() []*Release { + converted := make([]*Release, len(r.Items)) + for i, release := range r.Items { + c := Release(release) + c.SanitizeMetadata() + converted[i] = &c + } + return converted +} + +func (r *Release) SanitizeMetadata() *Release { + r.ObjectMeta.ManagedFields = nil + r.ObjectMeta.Finalizers = nil + r.ObjectMeta.UID = "" + r.ObjectMeta.Generation = 0 + // r.ObjectMeta.CreationTimestamp = metav1.Time{} + return r +} + +func (r *Release) SanitizeStatus() *Release { + r.ObjectMeta.ResourceVersion = "" + // r.Status = kubocdv1alpha1.ReleaseStatus{} + return r +} + +func (r *Release) ToYAML() (string, error) { + data, err := yaml.Marshal(r) + if err != nil { + return "", err + } + return string(data), nil +} + +func KuboCDReleaseNotFoundError(clusterID string, namespace string, releaseName string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("Unable to find KuboCD release '%s' in the kubernetes cluster '%s' on the namespace '%s'.", releaseName, clusterID, namespace) +} + +func KuboCDReleaseCreated(clusterID string, namespace string, releaseName string) *ServerResponse { + return NewServerResponse(OkdpServerResponse). + NotFoundError("Unable to find KuboCD release '%s' in the kubernetes cluster '%s' on the namespace '%s'.", releaseName, clusterID, namespace) +} diff --git a/internal/model/server_response.go b/internal/model/server_response.go new file mode 100644 index 0000000..05faa10 --- /dev/null +++ b/internal/model/server_response.go @@ -0,0 +1,118 @@ +/* + * Copyright 2024 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package model + +import ( + "fmt" + "net/http" + + "github.com/okdp/okdp-server/api/openapi/v3/_api" +) + +type ServerResponse _api.ServerResponse +type ServerResponseType _api.ServerResponseType + +const ( + OkdpServerResponse ServerResponseType = "okdp_server" + RegistryResponse ServerResponseType = "registry" + GitRepoResponse ServerResponseType = "git_repo" + K8sClusterResponse ServerResponseType = "k8s_cluster" +) + +func NewServerResponse(errorType ServerResponseType) *ServerResponse { + return &ServerResponse{ + Type: _api.ServerResponseType(errorType), + } +} + +func (s *ServerResponse) NotFoundError(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusNotFound + return s +} + +func (s *ServerResponse) BadRequest(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusBadRequest + return s +} + +func (s *ServerResponse) Unauthorized(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusUnauthorized + return s +} + +func (s *ServerResponse) Forbidden(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusForbidden + return s +} + +func (s *ServerResponse) ConflictError(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusConflict + return s +} + +func (s *ServerResponse) UnprocessableEntity(messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = http.StatusUnprocessableEntity + return s +} + +func (s *ServerResponse) GenericError(statusCode int, messages ...interface{}) *ServerResponse { + s.Message = toError(messages...) + s.Status = statusCode + return s +} + +func (s *ServerResponse) Created(messages ...interface{}) *ServerResponse { + s.Message = toSuccess(messages...) + s.Status = http.StatusCreated + return s +} + +func (s *ServerResponse) Updated(messages ...interface{}) *ServerResponse { + s.Message = toSuccess(messages...) + s.Status = http.StatusOK + return s +} + +func (s *ServerResponse) Deleted(messages ...interface{}) *ServerResponse { + s.Message = toSuccess(messages...) + s.Status = http.StatusOK + return s +} + +func (s *ServerResponse) IsNotfound() bool { + return s.Status == http.StatusNotFound +} + +func toError(messages ...interface{}) string { + if len(messages) == 1 { + return fmt.Errorf("%+v", messages...).Error() + } + return fmt.Errorf(messages[0].(string), messages[1:]...).Error() +} + +func toSuccess(messages ...interface{}) string { + if len(messages) == 1 { + return messages[0].(string) + } + return fmt.Sprintf(messages[0].(string), messages[1:]...) +} diff --git a/internal/model/template_release.go b/internal/model/template_release.go deleted file mode 100644 index c9ed61e..0000000 --- a/internal/model/template_release.go +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package model - -import ( - "github.com/okdp/okdp-server/api/openapi/v3/_api" -) - -type TemplateRelease _api.TemplateRelease -type TemplateReleases []TemplateRelease - -type TemplateReleaseSummary struct { - TemplateName string - TemplateVersion string - TemplateReleaseName string - Catalogs []string -} - -type TemplateReleaseInfo struct { - mapping map[string]TemplateReleaseSummary -} - -func (r *TemplateReleases) GroupTemplateReleaseInfoByComponentRelease() *TemplateReleaseInfo { - m := &TemplateReleaseInfo{ - mapping: make(map[string]TemplateReleaseSummary), - } - - for _, t := range *r { - for _, c := range t.Status.Children { - m.mapping[c] = TemplateReleaseSummary{ - TemplateName: t.Spec.Template.Ref.Name, - TemplateVersion: t.Spec.Template.Ref.Version, - TemplateReleaseName: t.Spec.Name, - Catalogs: t.Status.Catalogs, - } - } - } - - return m -} - -func (r *TemplateReleaseInfo) GetByComponentReleaseName(name string) (*TemplateReleaseSummary, bool) { - s, found := r.mapping[name] - if !found { - return nil, false - } - return &s, true -} diff --git a/internal/schema/parameters/schematic.go b/internal/schema/parameters/schematic.go new file mode 100644 index 0000000..0bbab52 --- /dev/null +++ b/internal/schema/parameters/schematic.go @@ -0,0 +1,31 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package schema + +type KuboSchema struct { + ParametersSchema *KuboSchemaItem `json:"parametersSchema"` + ContextSchema *KuboSchemaItem `json:"contextSchema"` +} + +type KuboSchemaItem struct { + Description string `json:"description,omitempty"` + Type string `json:"type,omitempty"` + Properties map[string]*KuboSchemaItem `json:"properties,omitempty"` + Items *KuboSchemaItem `json:"items,omitempty"` + Required bool `json:"required,omitempty"` + Default interface{} `json:"default,omitempty"` +} diff --git a/internal/schema/parameters/schematic_test.go b/internal/schema/parameters/schematic_test.go new file mode 100644 index 0000000..0fed1b3 --- /dev/null +++ b/internal/schema/parameters/schematic_test.go @@ -0,0 +1,249 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package schema + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParametersSchemaSimple(t *testing.T) { + // Given + jsonData := []byte(`{ + "parametersSchema": { + "properties": { + "hostname": { + "type": "string", + "required": false + }, + "tls": { + "type": "boolean", + "default": false + } + } + } + }`) + + // When + var s KuboSchema + err := json.Unmarshal(jsonData, &s) + + // Then + assert.NoError(t, err) + + assert.NotNil(t, s.ParametersSchema) + props := s.ParametersSchema.Properties + + assert.Contains(t, props, "hostname") + assert.Equal(t, "string", props["hostname"].Type) + assert.Equal(t, false, props["hostname"].Required) + + assert.Contains(t, props, "tls") + assert.Equal(t, "boolean", props["tls"].Type) + assert.Equal(t, false, props["tls"].Default) +} + +func TestParametersSchemaNested(t *testing.T) { + // Given + jsonData := []byte(`{ + "parametersSchema": { + "properties": { + "trust": { + "properties": { + "enabled": { + "type": "boolean", + "default": false + } + } + }, + "issuers": { + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "caClusterIssuers": { + "items": { + "properties": { + "name": { + "type": "string", + "required": true + }, + "ca_crt": { + "type": "string", + "required": true + }, + "ca_key": { + "type": "string", + "required": true + } + } + } + }, + "selfSignedClusterIssuers": { + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "required": true + } + } + } + } + } + } + } + } + }`) + + // When + var s KuboSchema + err := json.Unmarshal(jsonData, &s) + + // Then + assert.NoError(t, err) + + // Validate top-level keys + assert.NotNil(t, s.ParametersSchema) + assert.Contains(t, s.ParametersSchema.Properties, "trust") + assert.Contains(t, s.ParametersSchema.Properties, "issuers") + + // Validate nested fields + trust := s.ParametersSchema.Properties["trust"] + assert.Contains(t, trust.Properties, "enabled") + assert.Equal(t, "boolean", trust.Properties["enabled"].Type) + assert.Equal(t, false, trust.Properties["enabled"].Default) + + issuers := s.ParametersSchema.Properties["issuers"] + assert.Contains(t, issuers.Properties, "enabled") + assert.Equal(t, true, issuers.Properties["enabled"].Default) + + caClusterIssuers := issuers.Properties["caClusterIssuers"] + assert.NotNil(t, caClusterIssuers.Items) + assert.Contains(t, caClusterIssuers.Items.Properties, "name") + assert.Equal(t, "string", caClusterIssuers.Items.Properties["name"].Type) +} + +func TestParametersSchemaExtended(t *testing.T) { + // Given + jsonData := []byte(`{ + "parametersSchema": { + "description": "Redis stack", + "properties": { + "redis": { + "required": false, + "properties": { + "password": { + "type": "string", + "default": "redis123" + }, + "replicaCount": { + "type": "integer", + "default": 1, + "description": "The number of replicas" + } + } + }, + "commander": { + "required": true, + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "tls": { + "type": "boolean", + "default": false + }, + "hostname": { + "type": "string", + "required": false + } + } + } + } + } + }`) + + // When + var s KuboSchema + err := json.Unmarshal(jsonData, &s) + + // Then + assert.NoError(t, err) + + ps := s.ParametersSchema + assert.Equal(t, "Redis stack", ps.Description) + + redis := ps.Properties["redis"] + assert.NotNil(t, redis) + assert.False(t, redis.Required) + assert.Equal(t, "redis123", redis.Properties["password"].Default) + assert.Equal(t, float64(1), redis.Properties["replicaCount"].Default) + + commander := ps.Properties["commander"] + assert.NotNil(t, commander) + assert.True(t, commander.Required) + assert.Equal(t, true, commander.Properties["enabled"].Default) + assert.Equal(t, false, commander.Properties["tls"].Default) +} + +func TestContextSchema(t *testing.T) { + // Given + jsonData := []byte(`{ + "contextSchema": { + "properties": { + "ingress": { + "required": true, + "properties": { + "className": { + "type": "string", + "default": "nginx" + }, + "hostPostfix": { + "type": "string", + "required": true + } + } + } + } + } + }`) + + // When + var s KuboSchema + err := json.Unmarshal(jsonData, &s) + + // Then + assert.NoError(t, err) + + ingress := s.ContextSchema.Properties["ingress"] + assert.NotNil(t, ingress) + assert.True(t, ingress.Required) + + className := ingress.Properties["className"] + assert.NotNil(t, className) + assert.Equal(t, "string", className.Type) + assert.Equal(t, "nginx", className.Default) + + hostPostfix := ingress.Properties["hostPostfix"] + assert.NotNil(t, hostPostfix) + assert.True(t, hostPostfix.Required) +} diff --git a/internal/schema/release/release.go b/internal/schema/release/release.go new file mode 100644 index 0000000..2bb5fef --- /dev/null +++ b/internal/schema/release/release.go @@ -0,0 +1,51 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package schema + +// Release section +type Release struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Metadata Metadata `json:"metadata"` + Spec Spec `json:"spec"` +} + +// Metadata section +type Metadata struct { + Name string `json:"name"` +} + +// Spec section +type Spec struct { + Protected bool `json:"protected"` + TargetNamespace string `json:"targetNamespace"` + CreateNamespace bool `json:"createNamespace"` + Debug Debug `json:"debug"` + Parameters map[string]interface{} `yaml:"parameters"` + Application Application `json:"application"` +} + +type Debug struct { + DumpContext bool `json:"dumpContext"` +} + +// Application section +type Application struct { + Repository string `json:"repository"` + Tag string `json:"tag"` + Interval string `json:"interval"` +} diff --git a/internal/security/authc/auth.go b/internal/security/authc/auth.go index ded4c4f..8056a33 100644 --- a/internal/security/authc/auth.go +++ b/internal/security/authc/auth.go @@ -20,10 +20,10 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - log "github.com/okdp/okdp-server/internal/logging" + "github.com/okdp/okdp-server/internal/model" "github.com/okdp/okdp-server/internal/security/authc/provider/basic" "github.com/okdp/okdp-server/internal/security/authc/provider/bearer" "github.com/okdp/okdp-server/internal/security/authc/provider/oidc" @@ -64,7 +64,8 @@ func ensureUserAuthenticated() gin.HandlerFunc { _, found := c.Get(constants.OAuth2UserInfo) if !found { log.Warn("Failed to authenticate user") - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Authentication failed")) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Authentication failed")) return } } diff --git a/internal/security/authc/provider/basic/basic_auth.go b/internal/security/authc/provider/basic/basic_auth.go index 9cd41da..14495c7 100644 --- a/internal/security/authc/provider/basic/basic_auth.go +++ b/internal/security/authc/provider/basic/basic_auth.go @@ -18,8 +18,8 @@ package basic import ( "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" "github.com/okdp/okdp-server/internal/security/authc/model" ) diff --git a/internal/security/authc/provider/basic/basic_auth_test.go b/internal/security/authc/provider/basic/basic_auth_test.go index d1b6d49..87e5567 100644 --- a/internal/security/authc/provider/basic/basic_auth_test.go +++ b/internal/security/authc/provider/basic/basic_auth_test.go @@ -23,8 +23,8 @@ import ( "testing" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" "github.com/okdp/okdp-server/internal/security/authc/model" "github.com/stretchr/testify/assert" ) diff --git a/internal/security/authc/provider/bearer/bearer.go b/internal/security/authc/provider/bearer/bearer.go index 40fb9fb..6ff43f3 100644 --- a/internal/security/authc/provider/bearer/bearer.go +++ b/internal/security/authc/provider/bearer/bearer.go @@ -23,11 +23,11 @@ import ( "github.com/coreos/go-oidc/v3/oidc" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/security/authc/model" + "github.com/okdp/okdp-server/internal/model" + authc "github.com/okdp/okdp-server/internal/security/authc/model" "golang.org/x/net/context" ) @@ -65,7 +65,7 @@ func (p *Provider) Auth() []gin.HandlerFunc { func (p *Provider) authenticate() gin.HandlerFunc { return func(c *gin.Context) { var ( - userInfo model.UserInfo + userInfo authc.UserInfo ) authorization := c.Request.Header.Get("Authorization") @@ -73,14 +73,16 @@ func (p *Provider) authenticate() gin.HandlerFunc { err := p.verifyAccessToken(accessToken) if err != nil { log.Warn("Failed to verify access Token: %w", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Failed to verify access Token: "+err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Failed to verify access Token: "+err.Error())) return } userInfo, err = p.getUserInfo(accessToken) if err != nil { log.Warn("Unable to get user roles/groups from access token: %w", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Unable to get user roles/groups from access token: "+err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Unable to get user roles/groups from access token: "+err.Error())) return } log.Debug("Successfully authenticated user : %s", userInfo.AsJSONString()) @@ -101,7 +103,7 @@ func (p *Provider) verifyAccessToken(accessToken string) error { return nil } -func (p *Provider) getUserInfo(accessToken string) (model.UserInfo, error) { - token := &model.Token{AccessToken: accessToken} +func (p *Provider) getUserInfo(accessToken string) (authc.UserInfo, error) { + token := &authc.Token{AccessToken: accessToken} return token.GetUserInfo(rolesAttributePath, groupsAttributePath) } diff --git a/internal/security/authc/provider/oidc/oidc.go b/internal/security/authc/provider/oidc/oidc.go index c27c0d4..05cabc1 100644 --- a/internal/security/authc/provider/oidc/oidc.go +++ b/internal/security/authc/provider/oidc/oidc.go @@ -25,11 +25,11 @@ import ( "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/security/authc/model" + "github.com/okdp/okdp-server/internal/model" + authc "github.com/okdp/okdp-server/internal/security/authc/model" "github.com/okdp/okdp-server/internal/utils" "golang.org/x/net/context" "golang.org/x/oauth2" @@ -49,7 +49,7 @@ var ( ) func init() { - gob.Register(model.UserInfo{}) + gob.Register(authc.UserInfo{}) } func NewProvider(oidcConf config.OpenIDAuth) (*Provider, error) { @@ -81,12 +81,14 @@ func NewProvider(oidcConf config.OpenIDAuth) (*Provider, error) { func (p *Provider) AuthLogin(c *gin.Context) { state, err := utils.RandomString() if err != nil { - c.JSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Failed to to create OAuth2 state")) + c.JSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Failed to to create OAuth2 state")) return } nonce, err := utils.RandomString() if err != nil { - c.JSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Failed to to create OAuth2 nonce")) + c.JSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Failed to to create OAuth2 nonce")) return } url := p.Config.AuthCodeURL(state, oidc.Nonce(nonce)) @@ -94,7 +96,8 @@ func (p *Provider) AuthLogin(c *gin.Context) { session.Set(constants.OAuth2State, state) session.Set(constants.OAuth2Nonce, nonce) if err = session.Save(); err != nil { - c.JSON(http.StatusInternalServerError, errors.OfType(errors.OkdpServer).GenericError(http.StatusInternalServerError, "Failed to save user session in cookie")) + c.JSON(http.StatusInternalServerError, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusInternalServerError, "Failed to save user session in cookie")) } c.Redirect(http.StatusTemporaryRedirect, url) } @@ -111,12 +114,12 @@ func (p *Provider) authenticate() gin.HandlerFunc { var ( ok bool - userInfo model.UserInfo + userInfo authc.UserInfo ) session := sessions.Default(c) maybeUserInfo := session.Get(constants.OAuth2UserInfo) - if userInfo, ok = maybeUserInfo.(model.UserInfo); ok { + if userInfo, ok = maybeUserInfo.(authc.UserInfo); ok { c.Set(constants.OAuth2UserInfo, userInfo) log.Debug("The user (Email: %s, Subject: %s) was already authenticated", userInfo.Email, userInfo.Subject) c.Next() @@ -126,40 +129,46 @@ func (p *Provider) authenticate() gin.HandlerFunc { state := session.Get(constants.OAuth2State) if c.Query("state") != state { log.Warn("Invalid authentication OAuth2 state") - c.AbortWithStatusJSON(http.StatusBadRequest, errors.OfType(errors.OkdpServer).GenericError(http.StatusBadRequest, "Invalid authentication OAuth2 'state': "+state.(string))) + c.AbortWithStatusJSON(http.StatusBadRequest, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusBadRequest, "Invalid authentication OAuth2 'state': "+state.(string))) return } // Exchange the authorization code for an access token token, err := p.Config.Exchange(p.Context, c.Query("code")) if err != nil { log.Warn("Failed to exchange the authorization code with an access token: %w", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Failed to exchange authorization code with an access token: "+err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Failed to exchange authorization code with an access token: "+err.Error())) return } rawIDToken, ok := token.Extra("id_token").(string) if !ok { log.Warn("No id_token field found in the OAuth2 token") - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "No id_token field found in the OAuth2 token")) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "No id_token field found in the OAuth2 token")) return } idToken, err := p.Verify(p.Context, rawIDToken) if err != nil { log.Warn("Failed to verify the ID Token: %w", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Failed to verify the ID Token: "+err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Failed to verify the ID Token: "+err.Error())) return } nonce := session.Get(constants.OAuth2Nonce) if idToken.Nonce != nonce { log.Warn("Invalid authentication OAuth2 'nonce': %s", nonce.(string)) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Invalid authentication OAuth2 'nonce': "+nonce.(string))) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Invalid authentication OAuth2 'nonce': "+nonce.(string))) return } userInfo, err = p.getUserInfo(token.AccessToken) if err != nil { log.Warn("Unable to get user roles/groups from the access token: %w", err) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Unable to get user roles/groups from access token: "+err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Unable to get user roles/groups from access token: "+err.Error())) return } // Retrieve the user information from the access token @@ -185,8 +194,8 @@ func (p *Provider) authenticate() gin.HandlerFunc { } } -func (p *Provider) getUserInfo(accessToken string) (model.UserInfo, error) { - token := &model.Token{AccessToken: accessToken} +func (p *Provider) getUserInfo(accessToken string) (authc.UserInfo, error) { + token := &authc.Token{AccessToken: accessToken} return token.GetUserInfo(rolesAttributePath, groupsAttributePath) } diff --git a/internal/security/authz/authz.go b/internal/security/authz/authz.go index bb3ad7a..7094bb1 100644 --- a/internal/security/authz/authz.go +++ b/internal/security/authz/authz.go @@ -26,11 +26,11 @@ import ( "github.com/casbin/casbin/v2" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - "github.com/okdp/okdp-server/internal/errors" - log "github.com/okdp/okdp-server/internal/logging" - "github.com/okdp/okdp-server/internal/security/authc/model" + "github.com/okdp/okdp-server/internal/model" + authc "github.com/okdp/okdp-server/internal/security/authc/model" "github.com/okdp/okdp-server/internal/utils" ) @@ -80,13 +80,14 @@ func (e *Enforcer) authorize() gin.HandlerFunc { userInfo, ok := c.Get(constants.OAuth2UserInfo) if !ok { log.Warn("Unable to authorize user, no user informtaion found in context") - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Unable to authorize user, no user informtaion found in context")) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Unable to authorize user, no user informtaion found in context")) return } - email := userInfo.(*model.UserInfo).Email - sub := userInfo.(*model.UserInfo).Subject + email := userInfo.(*authc.UserInfo).Email + sub := userInfo.(*authc.UserInfo).Subject - rSub := userInfo.(*model.UserInfo).Roles + rSub := userInfo.(*authc.UserInfo).Roles rObj := c.Request.URL.Path rAct := c.Request.Method @@ -106,12 +107,14 @@ func (e *Enforcer) authorize() gin.HandlerFunc { if err != nil { log.Warn("Unable to authorize user (%s/%s): %s", email, sub, err.Error()) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, err.Error())) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, err.Error())) return } if !allowed { log.Warn("User (%s/%s) not allowed to execute the action", email, sub) - c.AbortWithStatusJSON(http.StatusUnauthorized, errors.OfType(errors.OkdpServer).GenericError(http.StatusUnauthorized, "Unauthorized action")) + c.AbortWithStatusJSON(http.StatusUnauthorized, model. + NewServerResponse(model.OkdpServerResponse).GenericError(http.StatusUnauthorized, "Unauthorized action")) return } diff --git a/internal/security/authz/authz_test.go b/internal/security/authz/authz_test.go index 4f76699..81c3f98 100644 --- a/internal/security/authz/authz_test.go +++ b/internal/security/authz/authz_test.go @@ -22,9 +22,9 @@ import ( "testing" "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" - log "github.com/okdp/okdp-server/internal/logging" "github.com/okdp/okdp-server/internal/security/authc/model" "github.com/stretchr/testify/assert" ) diff --git a/internal/server/server.go b/internal/server/server.go index c6d5f1c..a9fff08 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -22,10 +22,10 @@ import ( "github.com/gin-gonic/gin" + "github.com/okdp/okdp-server/internal/common/constants" + log "github.com/okdp/okdp-server/internal/common/logging" "github.com/okdp/okdp-server/internal/config" - "github.com/okdp/okdp-server/internal/constants" "github.com/okdp/okdp-server/internal/controllers" - log "github.com/okdp/okdp-server/internal/logging" "github.com/okdp/okdp-server/internal/security" "github.com/okdp/okdp-server/internal/security/authc" "github.com/okdp/okdp-server/internal/security/authz" diff --git a/internal/services/catalog.go b/internal/services/catalog.go index 95eaab1..bc4f419 100644 --- a/internal/services/catalog.go +++ b/internal/services/catalog.go @@ -1,5 +1,5 @@ /* - * Copyright 2024 okdp.io + * Copyright 2025 okdp.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,25 +17,36 @@ package services import ( - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad" + "github.com/okdp/okdp-server/internal/integrations/oci" "github.com/okdp/okdp-server/internal/model" ) type CatalogService struct { - catalog *kad.CatalogClient + catalog *oci.RepoCatalog } func NewCatalogService() *CatalogService { return &CatalogService{ - catalog: kad.NewCatalogClient(), + catalog: oci.NewRepoCatalog(), } } -func (s CatalogService) Get(kadInstanceID string, name string) (*model.Catalog, *errors.ServerError) { - return s.catalog.Get(kadInstanceID, name) +func (s CatalogService) ListCatalogs() []*model.Catalog { + return s.catalog.ListCatalogs() } -func (s CatalogService) List(kadInstanceID string) (*model.Catalogs, *errors.ServerError) { - return s.catalog.List(kadInstanceID) +func (s CatalogService) GetCatalog(catalogID string) (*model.Catalog, *model.ServerResponse) { + return s.catalog.GetCatalog(catalogID) +} + +func (s CatalogService) GetPackages(catalogID string) ([]*model.Package, *model.ServerResponse) { + return s.catalog.GetPackages(catalogID) +} + +func (s CatalogService) GetPackage(catalogID string, name string) (*model.Package, *model.ServerResponse) { + return s.catalog.GetPackage(catalogID, name) +} + +func (s CatalogService) GetPackageDefinition(catalogID string, name string, version string) (map[string]interface{}, *model.ServerResponse) { + return s.catalog.GetPackageDefinition(catalogID, name, version) } diff --git a/internal/services/cluster.go b/internal/services/cluster.go new file mode 100644 index 0000000..0603797 --- /dev/null +++ b/internal/services/cluster.go @@ -0,0 +1,48 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package services + +import ( + "github.com/okdp/okdp-server/internal/integrations/k8s" + "github.com/okdp/okdp-server/internal/model" +) + +type ClusterService struct { + cluster *k8s.K8S +} + +func NewClusterService() *ClusterService { + return &ClusterService{ + cluster: k8s.NewK8S(), + } +} + +func (s ClusterService) ListClusters() []*model.Cluster { + return s.cluster.ListClusters() +} + +func (s ClusterService) GetCluster(clusterID string) (*model.Cluster, *model.ServerResponse) { + return s.cluster.GetCluster(clusterID) +} + +func (s ClusterService) ListNamespaces(clusterID string) ([]string, *model.ServerResponse) { + return s.cluster.ListNamespaces(clusterID) +} + +func (s ClusterService) GetNamespaceByName(clusterID string, namespace string) (string, *model.ServerResponse) { + return "Not Implemented: " + clusterID + "/" + namespace, nil +} diff --git a/internal/services/component_releases.go b/internal/services/component_releases.go deleted file mode 100644 index 943aa04..0000000 --- a/internal/services/component_releases.go +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package services - -import ( - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad" - "github.com/okdp/okdp-server/internal/model" -) - -type ComponentReleaseService struct { - componentRelease *kad.ComponentReleaseClient -} - -func NewComponentReleaseService() *ComponentReleaseService { - return &ComponentReleaseService{ - componentRelease: kad.NewComponentReleaseClient(), - } -} - -func (s ComponentReleaseService) Get(kadInstanceID string, name string, catalog *string) (*model.ComponentReleaseResponse, *errors.ServerError) { - return s.componentRelease.Get(kadInstanceID, name, catalog) -} - -func (s ComponentReleaseService) List(kadInstanceID string, catalog *string) (*model.ComponentReleasesResponse, *errors.ServerError) { - return s.componentRelease.List(kadInstanceID, catalog) -} - -func (s ComponentReleaseService) CreateOrUpdateComponentRelease(kadInstanceID string, name string, componentReleaseRequest model.ComponentReleaseRequest, commitData map[string]string) (*model.GitCommit, *errors.ServerError) { - return s.componentRelease.UploadAsYaml(kadInstanceID, name, componentReleaseRequest, commitData) -} diff --git a/internal/services/git.go b/internal/services/git.go new file mode 100644 index 0000000..e5c0068 --- /dev/null +++ b/internal/services/git.go @@ -0,0 +1,157 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package services + +import ( + "github.com/okdp/okdp-server/internal/integrations/git" + "github.com/okdp/okdp-server/internal/model" +) + +type GitRepoService struct { + git *git.Repository +} + +func NewGitRepoService() *GitRepoService { + return &GitRepoService{ + git: git.NewRepository(), + } +} + +func (s GitRepoService) ListGitRepos(clusterID string, namespace string) ([]*model.GitRepository, *model.ServerResponse) { + return s.git.ListGitRepos(clusterID, namespace) +} + +func (s GitRepoService) GetGitRepo(clusterID string, namespace string, kustomizationName string) (*model.GitRepository, *model.ServerResponse) { + return s.git.GetGitRepo(clusterID, namespace, kustomizationName) +} + +func (s GitRepoService) ListReleases(clusterID string, namespace string, kustomizationName string) ([]*model.ReleaseInfo, *model.ServerResponse) { + contents, err := s.git.GetContents(clusterID, namespace, kustomizationName) + if err != nil { + return nil, err + } + return s.toReleaseInfo(contents) +} + +func (s GitRepoService) GetRelease(clusterID string, namespace string, kustomizationName string, releaseName string) (*model.Release, *model.ServerResponse) { + contents, err := s.git.GetContents(clusterID, namespace, kustomizationName) + if err != nil { + return nil, err + } + + for _, content := range contents { + release, err := content.ToRelease() + if err != nil { + return nil, err + } + + if release.ObjectMeta.Name == releaseName { + return release, nil + } + } + + return nil, model.KuboCDGitReleaseNotFoundError(clusterID, namespace, kustomizationName, releaseName) +} + +func (s GitRepoService) CreateGitRelease(clusterID string, namespace string, kustomizationName string, release *model.Release, commitOpts *model.GitCommit) (*model.Release, *model.ServerResponse) { + releaseInfo, er := s.getReleaseInfo(clusterID, namespace, kustomizationName, release.Namespace, release.Name) + if er != nil { + return nil, er + } + if releaseInfo == nil { + content, err := release.SanitizeMetadata().SanitizeStatus().ToYAML() + if err != nil { + return nil, model. + NewServerResponse(model.OkdpServerResponse). + UnprocessableEntity("Unable to convert KuboCD release %s/%s into yaml", release.Namespace, release.Name) + } + return release, s.git.Write(clusterID, namespace, kustomizationName, content, commitOpts, release.Name+".yaml") + } + + return nil, model.NewServerResponse(model.OkdpServerResponse).ConflictError("Release '%s' already exists in the git repo %s (%s)", release.Name, releaseInfo.Git.Path, releaseInfo.Git.URL) +} + +func (s GitRepoService) UpdateGitRelease(clusterID string, namespace string, kustomizationName string, release *model.Release, commitOpts *model.GitCommit) (*model.Release, *model.ServerResponse) { + releaseInfo, er := s.getReleaseInfo(clusterID, namespace, kustomizationName, release.Namespace, release.Name) + if er != nil { + return nil, er + } + if releaseInfo == nil { + return nil, model.NewServerResponse(model.OkdpServerResponse).NotFoundError("Release '%s' does not exist in the git repo", release.Name) + } + + content, err := release.SanitizeMetadata().SanitizeStatus().ToYAML() + if err != nil { + return nil, model. + NewServerResponse(model.OkdpServerResponse). + UnprocessableEntity("Unable to convert KuboCD release %s/%s into yaml", release.Namespace, release.Name) + } + + return release, s.git.Write(clusterID, namespace, kustomizationName, content, commitOpts, releaseInfo.Git.Path) +} + +func (s GitRepoService) DeleteGitRelease(clusterID string, namespace string, kustomizationName string, releaseName string, commitOpts *model.GitCommit) *model.ServerResponse { + releaseInfo, er := s.getReleaseInfo(clusterID, namespace, kustomizationName, "default", releaseName) + if er != nil { + return er + } + if *releaseInfo == (model.ReleaseInfo{}) { + return model.NewServerResponse(model.OkdpServerResponse).NotFoundError("Release '%s' does not exist in the git repo", releaseName) + } + + return s.git.DeleteFile(clusterID, namespace, kustomizationName, commitOpts, releaseInfo.Git.Path) +} + +func (s GitRepoService) toReleaseInfo(contents []*model.GitContent) ([]*model.ReleaseInfo, *model.ServerResponse) { + releasesInfo := []*model.ReleaseInfo{} + for _, content := range contents { + release, err := content.ToRelease() + if err != nil { + return nil, err + } + + name := release.ObjectMeta.Name + namespace := release.ObjectMeta.Namespace + releaseInfo := &model.ReleaseInfo{ + Name: name, + Namespace: &namespace, + Description: &release.Spec.Description, + } + releaseInfo.Package.Repository = release.Spec.Package.Repository + releaseInfo.Package.Tag = release.Spec.Package.Tag + releaseInfo.Git.Path = content.Path + releaseInfo.Git.URL = content.URL + + releasesInfo = append(releasesInfo, releaseInfo) + } + return releasesInfo, nil +} + +func (s GitRepoService) getReleaseInfo(clusterID, namespace, kustomizationName, releaseNamespace, releaseName string) (*model.ReleaseInfo, *model.ServerResponse) { + releases, err := s.ListReleases(clusterID, namespace, kustomizationName) + if err != nil { + return nil, err + } + + for _, rel := range releases { + if rel.Name == releaseName && rel.Namespace != nil && *rel.Namespace == releaseNamespace { + return rel, nil + } + } + + return nil, nil +} diff --git a/internal/services/kubocd.go b/internal/services/kubocd.go new file mode 100644 index 0000000..c0311f5 --- /dev/null +++ b/internal/services/kubocd.go @@ -0,0 +1,57 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package services + +import ( + "github.com/okdp/okdp-server/internal/integrations/k8s" + "github.com/okdp/okdp-server/internal/model" +) + +type KuboCDService struct { + kubocd *k8s.K8S +} + +func NewKuboCDService() *KuboCDService { + return &KuboCDService{ + kubocd: k8s.NewK8S(), + } +} + +func (s KuboCDService) ListReleases(clusterID string, namespaces ...string) ([]*model.Release, *model.ServerResponse) { + return s.kubocd.ListReleases(clusterID, namespaces...) + +} + +func (s KuboCDService) GetRelease(clusterID string, namespace string, releaseName string) (*model.Release, *model.ServerResponse) { + return s.kubocd.GetRelease(clusterID, namespace, releaseName) +} + +func (s KuboCDService) GetReleaseStatus(clusterID string, namespace string, releaseName string) (*model.ReleaseStatus, *model.ServerResponse) { + return s.kubocd.GetReleaseStatus(clusterID, namespace, releaseName) +} + +func (s KuboCDService) CreateRelease(clusterID string, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + return s.kubocd.CreateRelease(clusterID, namespace, release, dryRun) +} + +func (s KuboCDService) UpdateRelease(clusterID string, namespace string, release *model.Release, dryRun bool) *model.ServerResponse { + return s.kubocd.UpdateRelease(clusterID, namespace, release, dryRun) +} + +func (s KuboCDService) DeleteRelease(clusterID string, namespace string, releaseName string) *model.ServerResponse { + return s.kubocd.DeleteRelease(clusterID, namespace, releaseName) +} diff --git a/internal/services/service.go b/internal/services/service.go deleted file mode 100644 index abeb608..0000000 --- a/internal/services/service.go +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package services - -import ( - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/model" -) - -type Service struct { - componentReleaseService *ComponentReleaseService - templateReleaseService *TemplateReleaseService -} - -func NewService() (*Service, error) { - return &Service{ - componentReleaseService: NewComponentReleaseService(), - templateReleaseService: NewTemplateReleaseService(), - }, nil -} - -func (s Service) List(kadInstanceID string, catalog *string) (*model.Services, *errors.ServerError) { - componentReleases, err := s.componentReleaseService.List(kadInstanceID, catalog) - if err != nil { - return nil, err - } - temmplateReleases, err := s.templateReleaseService.List(kadInstanceID, catalog) - if err != nil { - return nil, err - } - tri := temmplateReleases.GroupTemplateReleaseInfoByComponentRelease() - return componentReleases.Flatten().AddTemplateReleaseInfo(tri).ConvertToService(), nil -} diff --git a/internal/services/template_release.go b/internal/services/template_release.go deleted file mode 100644 index d2dd31d..0000000 --- a/internal/services/template_release.go +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2024 okdp.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package services - -import ( - "github.com/okdp/okdp-server/internal/errors" - "github.com/okdp/okdp-server/internal/kad" - "github.com/okdp/okdp-server/internal/model" -) - -type TemplateReleaseService struct { - templateRelease *kad.TemplateReleaseClient -} - -func NewTemplateReleaseService() *TemplateReleaseService { - return &TemplateReleaseService{ - templateRelease: kad.NewTemplateReleaseClient(), - } -} - -func (s TemplateReleaseService) Get(kadInstanceID string, name string, catalog *string) (*model.TemplateRelease, *errors.ServerError) { - return s.templateRelease.Get(kadInstanceID, name, catalog) -} - -func (s TemplateReleaseService) List(kadInstanceID string, catalog *string) (*model.TemplateReleases, *errors.ServerError) { - return s.templateRelease.List(kadInstanceID, catalog) -} diff --git a/internal/utils/auth_utils.go b/internal/utils/auth_utils.go index 6accc6e..659844a 100644 --- a/internal/utils/auth_utils.go +++ b/internal/utils/auth_utils.go @@ -19,7 +19,11 @@ package utils import ( "crypto/rand" "encoding/base64" + "encoding/json" + "errors" + "fmt" "io" + "strings" ) func RandomString() (string, error) { @@ -29,3 +33,50 @@ func RandomString() (string, error) { } return base64.RawURLEncoding.EncodeToString(b), nil } + +type dockerConfig struct { + Auths map[string]dockerAuthEntry `json:"auths"` +} + +type dockerAuthEntry struct { + Auth string `json:"auth"` // base64("username:password") +} + +// ToLoginPassword decodes a base64-encoded .dockerconfigjson value and extracts the first +// username and password found in the `auths` section. +// It returns the username, password, and an error if decoding or parsing fails. +func ToLoginPassword(encodedDockerJSON string) (string, string, error) { + jsonBytes, err := base64.StdEncoding.DecodeString(encodedDockerJSON) + if err != nil { + return "", "", fmt.Errorf("failed to base64-decode dockerjson: %w", err) + } + + var config dockerConfig + if err := json.Unmarshal(jsonBytes, &config); err != nil { + return "", "", fmt.Errorf("failed to unmarshal docker config json: %w", err) + } + + if len(config.Auths) == 0 { + return "", "", errors.New("no auth entries found in docker config") + } + + for registry, entry := range config.Auths { + if entry.Auth == "" { + continue + } + + decodedAuth, err := base64.StdEncoding.DecodeString(entry.Auth) + if err != nil { + return "", "", fmt.Errorf("failed to decode auth for registry '%s': %w", registry, err) + } + + parts := strings.SplitN(string(decodedAuth), ":", 2) + if len(parts) != 2 { + return "", "", fmt.Errorf("invalid auth format for registry '%s'", registry) + } + + return parts[0], parts[1], nil + } + + return "", "", errors.New("no valid auth credentials found") +} diff --git a/internal/utils/auth_utils_test.go b/internal/utils/auth_utils_test.go new file mode 100644 index 0000000..681b82a --- /dev/null +++ b/internal/utils/auth_utils_test.go @@ -0,0 +1,75 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "encoding/base64" + "testing" +) + +func TestToLoginPassword(t *testing.T) { + // Setup test values + username := "myuser" + password := "mypassword" + auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) + + dockerJSON := `{ + "auths": { + "https://index.docker.io/v1/": { + "auth": "` + auth + `" + } + } + }` + + encodedDockerJSON := base64.StdEncoding.EncodeToString([]byte(dockerJSON)) + + user, pass, err := ToLoginPassword(encodedDockerJSON) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if user != username { + t.Errorf("expected username '%s', got '%s'", username, user) + } + if pass != password { + t.Errorf("expected password '%s', got '%s'", password, pass) + } +} + +func TestToLoginPassword_InvalidBase64(t *testing.T) { + _, _, err := ToLoginPassword("not-base64!") + if err == nil { + t.Fatal("expected error for invalid base64, got none") + } +} + +func TestToLoginPassword_InvalidJSON(t *testing.T) { + encoded := base64.StdEncoding.EncodeToString([]byte("not json")) + _, _, err := ToLoginPassword(encoded) + if err == nil { + t.Fatal("expected error for invalid JSON, got none") + } +} + +func TestToLoginPassword_MissingAuth(t *testing.T) { + dockerJSON := `{"auths": {}}` + encoded := base64.StdEncoding.EncodeToString([]byte(dockerJSON)) + _, _, err := ToLoginPassword(encoded) + if err == nil { + t.Fatal("expected error for missing auths, got none") + } +} diff --git a/internal/utils/collection_utils.go b/internal/utils/collection_utils.go index a357212..20f3b62 100644 --- a/internal/utils/collection_utils.go +++ b/internal/utils/collection_utils.go @@ -30,3 +30,45 @@ func ArrayNullToEmpty[T any](a []T) []T { } return []T{} } + +func MapKey(keys ...string) string { + var result string + for _, key := range keys { + result += key + } + return result +} + +// Filter filters a slice of objects based on a predicate function. +// It returns a new slice containing only the elements that satisfy the predicate. +func Filter[T any](objects []T, predicate func(T) bool) []*T { + filtered := make([]*T, 0, len(objects)) + for i := range objects { + if predicate(objects[i]) { + filtered = append(filtered, &objects[i]) + } + } + return filtered +} + +// Filter filters a slice of objects based on a predicate function. +// It returns a new slice containing only the elements that satisfy the predicate. +func Filter2[T any](objects []*T, predicate func(T) bool) []*T { + filtered := make([]*T, 0, len(objects)) + for _, obj := range objects { + if predicate(*obj) { + filtered = append(filtered, obj) + } + } + return filtered +} + +// Contains checks if a given string is in the namespaces slice. +func Contains(values []string, value string) bool { + for _, ns := range values { + if ns == value { + return true + } + } + return false +} diff --git a/internal/utils/collection_utils_test.go b/internal/utils/collection_utils_test.go index f9c8f76..6a6222f 100644 --- a/internal/utils/collection_utils_test.go +++ b/internal/utils/collection_utils_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_Map_function(t *testing.T) { +func TestMapfunction(t *testing.T) { // Given numbers := []int{1, 2, 3} @@ -32,3 +32,82 @@ func Test_Map_function(t *testing.T) { // Then assert.Equal(t, []int{2, 4, 6}, result) } + +func TestFilter(t *testing.T) { + type MyObject struct { + Name string + Value int + } + // Test case 1: Filtering even numbers + objects := []MyObject{ + {Name: "Object 1", Value: 10}, + {Name: "Object 2", Value: 15}, + {Name: "Object 3", Value: 20}, + } + isEven := func(obj MyObject) bool { + return obj.Value%2 == 0 + } + + filtered := Filter(objects, isEven) + if len(filtered) != 2 { + t.Errorf("Expected 2 objects, but got %d", len(filtered)) + } + if filtered[0].Value != 10 || filtered[1].Value != 20 { + t.Errorf("Expected filtered objects to be [10, 20], but got %v", filtered) + } + + // Test case 2: Filtering objects with value greater than 15 + isGreaterThan15 := func(obj MyObject) bool { + return obj.Value > 15 + } + + filtered = Filter(objects, isGreaterThan15) + if len(filtered) != 1 { + t.Errorf("Expected 1 object, but got %d", len(filtered)) + } + if filtered[0].Value != 20 { + t.Errorf("Expected filtered object to be 20, but got %v", filtered[0]) + } + + // Test case 3: Empty list + filtered = Filter([]MyObject{}, isEven) + if len(filtered) != 0 { + t.Errorf("Expected 0 objects, but got %d", len(filtered)) + } +} + +func TestContains(t *testing.T) { + // Test case 1: Value exists in the slice + namespaces := []string{"flux-system", "kube-system", "default"} + value := "flux-system" + if !Contains(namespaces, "flux-system") { + t.Errorf("Expected '%s' to be in the namespaces slice", value) + } + + // Test case 2: Value does not exist in the slice + value = "dev-namespace" + if Contains(namespaces, value) { + t.Errorf("Expected '%s' to NOT be in the namespaces slice", value) + } + + // Test case 3: Empty slice + namespaces = []string{} + value = "release-system" + if Contains(namespaces, value) { + t.Errorf("Expected '%s' to NOT be in the namespaces slice", value) + } + + // Test case 4: Single element slice, value exists + namespaces = []string{"default"} + value = "default" + if !Contains(namespaces, value) { + t.Errorf("Expected '%s' to be in the namespaces slice", value) + } + + // Test case 5: Single element slice, value does not exist + namespaces = []string{"default"} + value = "dev1" + if Contains(namespaces, value) { + t.Errorf("Expected '%s' to NOT be in the namespaces slice", value) + } +} diff --git a/internal/utils/env_utils.go b/internal/utils/env_utils.go new file mode 100644 index 0000000..055cd9d --- /dev/null +++ b/internal/utils/env_utils.go @@ -0,0 +1,37 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "os" + "strings" +) + +// ResolveEnv reads an environment variable. If the value is a placeholder like $(VAR_NAME), +// it will replace it with the actual value from the environment variable. +// If the value is not a placeholder, it returns the value as is. +func ResolveEnv(key string) string { + if strings.HasPrefix(key, "$(") && strings.HasSuffix(key, ")") { + varName := strings.TrimPrefix(key, "$(") + varName = strings.TrimSuffix(varName, ")") + if value, exists := os.LookupEnv(varName); exists { + return value + } + return "" + } + return key +} diff --git a/internal/utils/env_utils_test.go b/internal/utils/env_utils_test.go new file mode 100644 index 0000000..f00a688 --- /dev/null +++ b/internal/utils/env_utils_test.go @@ -0,0 +1,42 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "os" + "testing" +) + +func TestResolveEnv(t *testing.T) { + // Test the behavior when the environment variable is set + os.Setenv("OCI_USERNAME", "myusername") + defer os.Unsetenv("OCI_USERNAME") + + if got := ResolveEnv("$(OCI_USERNAME)"); got != "myusername" { + t.Errorf("expected 'myusername', got %s", got) + } + + // Test when the environment variable does not exist + if got := ResolveEnv("$(NON_EXISTENT_VAR)"); got != "" { + t.Errorf("expected '', got %s", got) + } + + // Test non-placeholder value + if got := ResolveEnv("JustSomeOtherValue"); got != "JustSomeOtherValue" { + t.Errorf("expected 'JustSomeOtherValue', got %s", got) + } +} diff --git a/internal/utils/file_utils.go b/internal/utils/file_utils.go new file mode 100644 index 0000000..7a73775 --- /dev/null +++ b/internal/utils/file_utils.go @@ -0,0 +1,42 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "path/filepath" + "strings" +) + +// IsYaml checks if the given filename has a .yaml or .yml extension (case-insensitive). +func IsYaml(filePath string) bool { + ext := strings.ToLower(filepath.Ext(filePath)) + return ext == ".yaml" || ext == ".yml" +} + +// PathOrFallback returns the given `path` if it contains a slash ("/"), +// indicating it is a likely full or relative path. +// Otherwise, it returns the provided `fallback` value. +// +// This is useful in cases where you want to prefer a user-supplied +// file or directory path, but fall back to a default if not provided. +func PathOrFallback(path string, fallback string) string { + if strings.Contains(path, "/") { + return path + } + return fallback + +} diff --git a/internal/utils/file_utils_test.go b/internal/utils/file_utils_test.go new file mode 100644 index 0000000..ace15cc --- /dev/null +++ b/internal/utils/file_utils_test.go @@ -0,0 +1,86 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import "testing" + +func TestIsYaml(t *testing.T) { + tests := []struct { + name string + filename string + expected bool + }{ + {"Valid .yaml file", "config.yaml", true}, + {"Valid .yml file", "config.yml", true}, + {"Uppercase .YAML", "CONFIG.YAML", true}, + {"Uppercase .YML", "CONFIG.YML", true}, + {"Not a YAML file (.json)", "data.json", false}, + {"No extension", "README", false}, + {"Empty string", "", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if result := IsYaml(tt.filename); result != tt.expected { + t.Errorf("IsYaml(%q) = %v; want %v", tt.filename, result, tt.expected) + } + }) + } +} + +func TestPathOrFallback(t *testing.T) { + tests := []struct { + name string + path string + fallback string + want string + }{ + { + name: "Path contains slash", + path: "./config/file.yaml", + fallback: "default.yaml", + want: "./config/file.yaml", + }, + { + name: "Path does not contain slash", + path: "file.yaml", + fallback: "default.yaml", + want: "default.yaml", + }, + { + name: "Empty path returns fallback", + path: "", + fallback: "default.yaml", + want: "default.yaml", + }, + { + name: "Path is slash only", + path: "/", + fallback: "default.yaml", + want: "/", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := PathOrFallback(tt.path, tt.fallback) + if got != tt.want { + t.Errorf("PathOrFallback() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/model/git_commit.go b/internal/utils/hash_utils.go similarity index 67% rename from internal/model/git_commit.go rename to internal/utils/hash_utils.go index 4aea671..fef7080 100644 --- a/internal/model/git_commit.go +++ b/internal/utils/hash_utils.go @@ -14,10 +14,17 @@ * limitations under the License. */ -package model +package utils import ( - "github.com/okdp/okdp-server/api/openapi/v3/_api" + "crypto/sha1" + "encoding/hex" + "strings" ) -type GitCommit _api.GitCommit +// FromString generates a short deterministic ID from a string +func FromString(input string) string { + normalized := strings.TrimSpace(input) + hash := sha1.Sum([]byte(normalized)) + return hex.EncodeToString(hash[:6]) // 6 bytes -> 12 hex chars +} diff --git a/internal/utils/hash_utils_tests.go b/internal/utils/hash_utils_tests.go new file mode 100644 index 0000000..3a2c552 --- /dev/null +++ b/internal/utils/hash_utils_tests.go @@ -0,0 +1,59 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "testing" +) + +func TestFromString(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "Basic Git URL", + input: "ssh://git@github.com/kubocd/kubocd-infra-ii", + expected: "ff7b5b726d45", + }, + { + name: "Leading and trailing spaces", + input: " ssh://git@github.com/kubocd/kubocd-infra-ii ", + expected: "ff7b5b726d45", + }, + { + name: "Empty string", + input: "", + expected: "da39a3ee5e6b", + }, + { + name: "Different strings produce different IDs", + input: "ssh://git@github.com/kubocd/another-repo", + expected: "c79dc88f5600", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := FromString(tt.input) + if got != tt.expected { + t.Errorf("FromString(%q) = %v; want %v", tt.input, got, tt.expected) + } + }) + } +} diff --git a/internal/model/service.go b/internal/utils/parameter_utils.go similarity index 56% rename from internal/model/service.go rename to internal/utils/parameter_utils.go index 6fc5199..39b6a4a 100644 --- a/internal/model/service.go +++ b/internal/utils/parameter_utils.go @@ -14,13 +14,26 @@ * limitations under the License. */ -package model +package utils -// https://github.com/oapi-codegen/oapi-codegen/issues/1139 -type Service struct { - Name string `json:"name"` - IsComposition bool `json:"isComposition"` - FlatComponents []FlatComponent `json:"flatComponents"` +func OrFalse(b *bool) bool { + if b != nil { + return *b + } + return false } -type Services []*Service +// DefaultIfEmpty returns `value` if it is not an empty string, +// otherwise it returns `defaultValue`. +// Useful for setting defaults in configurations. +// +// Example: +// +// DefaultIfEmpty("", "default") // returns "default" +// DefaultIfEmpty("foo", "default") // returns "foo" +func DefaultIfEmpty(value, defaultValue string) string { + if value != "" { + return value + } + return defaultValue +} diff --git a/internal/utils/parameter_utils_test.go b/internal/utils/parameter_utils_test.go new file mode 100644 index 0000000..52d28d3 --- /dev/null +++ b/internal/utils/parameter_utils_test.go @@ -0,0 +1,80 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "testing" +) + +func TestOrFalse(t *testing.T) { + trueVal := true + falseVal := false + + tests := []struct { + name string + input *bool + expected bool + }{ + { + name: "nil input returns false", + input: nil, + expected: false, + }, + { + name: "true input returns true", + input: &trueVal, + expected: true, + }, + { + name: "false input returns false", + input: &falseVal, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := OrFalse(tt.input) + if result != tt.expected { + t.Errorf("OrFalse(%v) = %v; want %v", tt.input, result, tt.expected) + } + }) + } +} + +func TestDefaultIfEmpty(t *testing.T) { + tests := []struct { + name string + value string + defaultValue string + expected string + }{ + {"Empty value", "", "default", "default"}, + {"Non-empty value", "foo", "default", "foo"}, + {"Both empty", "", "", ""}, + {"Default value ignored", "bar", "ignored", "bar"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := DefaultIfEmpty(tt.value, tt.defaultValue) + if result != tt.expected { + t.Errorf("Expected %q, got %q", tt.expected, result) + } + }) + } +} diff --git a/internal/utils/versioning_utils.go b/internal/utils/versioning_utils.go new file mode 100644 index 0000000..bef2755 --- /dev/null +++ b/internal/utils/versioning_utils.go @@ -0,0 +1,68 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "sort" + "strings" + + "github.com/Masterminds/semver/v3" +) + +// SortVersions sorts a list of version strings in descending order. +// +// - Versions are expected to follow semantic versioning (SemVer). +// - Versions that begin with a 'v' (e.g. "v1.2.3") are supported and normalized for sorting. +// - Invalid SemVer strings are placed at the end of the result list in the original order. +// +// Example: +// +// input: []string{"v2.0.0", "v1.0.0", "invalid"} +// output: []string{"v2.0.0", "v1.0.0", "invalid"} +func SortVersions(versions []string) []string { + type versionWithOriginal struct { + Original string + Version *semver.Version + } + + validVersions := make([]versionWithOriginal, 0, len(versions)) + var invalidVersions []string + + for _, v := range versions { + parsed := strings.TrimPrefix(v, "v") + sv, err := semver.NewVersion(parsed) + if err != nil { + invalidVersions = append(invalidVersions, v) + continue + } + validVersions = append(validVersions, versionWithOriginal{ + Original: v, + Version: sv, + }) + } + + sort.Slice(validVersions, func(i, j int) bool { + return validVersions[i].Version.GreaterThan(validVersions[j].Version) + }) + + sorted := make([]string, 0, len(versions)) + for _, v := range validVersions { + sorted = append(sorted, v.Original) + } + + return append(sorted, invalidVersions...) +} diff --git a/internal/utils/versioning_utils_test.go b/internal/utils/versioning_utils_test.go new file mode 100644 index 0000000..9324586 --- /dev/null +++ b/internal/utils/versioning_utils_test.go @@ -0,0 +1,55 @@ +/* + * Copyright 2025 okdp.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package utils + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSortVersions(t *testing.T) { + tests := []struct { + versions []string + expected []string + }{ + { + versions: []string{"1.0.0", "1.2.0", "2.0.0", "1.1.1", "invalid", "v2.1.0"}, + expected: []string{"v2.1.0", "2.0.0", "1.2.0", "1.1.1", "1.0.0", "invalid"}, + }, + { + versions: []string{"v2.1.0", "1.0.0", "v1.1.0", "v3.0.0", "1.1.1", "v2.0.0"}, + expected: []string{"v3.0.0", "v2.1.0", "v2.0.0", "1.1.1", "v1.1.0", "1.0.0"}, + }, + { + versions: []string{"v1.0.0", "invalid", "v2.2.0"}, + expected: []string{"v2.2.0", "v1.0.0", "invalid"}, + }, + { + versions: []string{"invalid", "v1.0.0", "v2.0.0"}, + expected: []string{"v2.0.0", "v1.0.0", "invalid"}, + }, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("Sorting %v", test.versions), func(t *testing.T) { + result := SortVersions(test.versions) + assert.Equal(t, test.expected, result) + }) + } +} diff --git a/package.json b/package.json index 4fd7203..2a630ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "okdp-server", - "version": "0.1.0", + "version": "0.2.0", "description": "okdp-server docker image", "repository": { "type": "git",