Compare commits

..

1 Commits

Author SHA1 Message Date
Ahmad Murzahmatov
c5ead0c48b [feat] end-user environment setup
Add script to automatically install all required
packages on end-user system
Linux distro independent, MacOS ready

Signed-off-by: Ahmad Murzahmatov <gwynbleidd2106@yandex.com>
2025-07-09 20:10:58 +06:00
24 changed files with 268 additions and 280 deletions

View File

@@ -118,7 +118,6 @@ jobs:
git config user.name "cozystack-bot"
git config user.email "217169706+cozystack-bot@users.noreply.github.com"
git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY}
git config --unset-all http.https://github.com/.extraheader || true
git add .
git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit"
git push origin HEAD || true

View File

@@ -6,6 +6,7 @@ build-deps:
@tar --version | grep -q GNU || (echo "GNU tar is required" && exit 1)
@sed --version | grep -q GNU || (echo "GNU sed is required" && exit 1)
@awk --version | grep -q GNU || (echo "GNU awk is required" && exit 1)
@./hack/user_setup_env.sh
build: build-deps
make -C packages/apps/http-cache image

129
hack/user_setup_env.sh Normal file
View File

@@ -0,0 +1,129 @@
#!/bin/bash
#### variables list
cozypkg_version="v1.1.0"
talm_version="v0.13.0"
kubectl_version="v1.33.1"
krew_version="v0.4.5"
helm_version="v3.18.2"
virtctl_version="v1.4.0"
fluxcd_version="2.6.1"
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
echo $ARCH
OS="$(uname | tr '[:upper:]' '[:lower:]')"
function user_setup_env() {
log "Start setuping user environment"
install_cozypkg
install_talm
install_kubectl
install_krew
install_krew_plugins
install_virtctl
install_helm
install_helm_plugins
install_fluxcd
}
function log() {
echo "$(date '+%d-%m-%Y %H:%M:%S') - $1"
}
function install_cozypkg() {
log "Installing cozypkg"
curl -sSL https://github.com/cozystack/cozypkg/releases/download/${cozypkg_version}/cozypkg-${OS}-${ARCH}.tar.gz | \
tar xzvf - cozypkg
sudo mv /tmp/cozypkg /usr/local/bin/cozypkg
sudo chown 0:0 /usr/local/bin/cozypkg
sudo chmod 0755 /usr/local/bin/cozypkg
}
function install_talm() {
log "Installing talm"
curl -o /tmp/talm -fsL "https://github.com/cozystack/talm/releases/download/${talm_version}/talm-${OS}-${ARCH}"
sudo mv /tmp/talm /usr/local/bin/talm
sudo chown 0:0 /usr/local/bin/talm
sudo chmod 0755 /usr/local/bin/talm
}
function install_kubectl() {
log "Installing kubectl"
curl -o /tmp/kubectl -fsLO "https://dl.k8s.io/release/${kubectl_version}/bin/${OS}/${ARCH}/kubectl"
sudo mv /tmp/kubectl /usr/local/bin/kubectl
sudo chown 0:0 /usr/local/bin/kubectl
sudo chmod 0755 /usr/local/bin/kubectl
}
install_krew() {
log "Installing krew"
KREW="krew-${OS}_${ARCH}"
curl -o "/tmp/${KREW}.tar.gz" -fsLO "https://github.com/kubernetes-sigs/krew/releases/download/${krew_version}/${KREW}.tar.gz"
mkdir /tmp/krew && tar -xzf "/tmp/${KREW}.tar.gz" -C /tmp/krew/
"/tmp/krew/${KREW}" install krew
log "configure .bashrc for krew"
printf '# krew\nexport PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"\n' >> ~/.bashrc
source ~/.bashrc
}
function install_krew_plugins() {
log "Installing krew plugins..."
if [[ ! $(kubectl krew version) ]]; then
log "krew is not installed, install it first!"
return 1
fi
log "Installing krew plugin: node-shell"
kubectl krew install node-shell
log "Installing krew plugin: virt"
kubectl krew install virt
log "Installing krew plugin: oidc-login"
kubectl krew install oidc-login
}
function install_virtctl() {
log "Installing virtctl"
curl -o /tmp/virtctl -fsL "https://github.com/kubevirt/kubevirt/releases/download/${virtctl_version}/virtctl-${virtctl_version}-${OS}-${ARCH}"
sudo mv /tmp/virtctl /usr/local/bin/virtctl
sudo chown 0:0 /usr/local/bin/virtctl
sudo chmod 0755 /usr/local/bin/virtctl
}
function install_helm() {
log "Installing Helm"
curl -o /tmp/helm.tar.gz -fsL "https://get.helm.sh/helm-${helm_version}-${OS}-${ARCH}.tar.gz"
mkdir /tmp/helm && tar -xzf /tmp/helm.tar.gz -C /tmp/helm/
sudo mv "/tmp/helm/${OS}-${ARCH}/helm" /usr/local/bin/helm
sudo chown 0:0 /usr/local/bin/helm
sudo chmod 0755 /usr/local/bin/helm
}
function install_helm_plugins() {
log "Installing Helm plugins..."
log "Installing Helm plugin: diff"
helm plugin install https://github.com/databus23/helm-diff
}
function install_fluxcd() {
log "Installing FluxCD"
curl -o /tmp/flux.tar.gz -fsL "https://github.com/fluxcd/flux2/releases/download/v${fluxcd_version}/flux_${fluxcd_version}_${OS}_${ARCH}.tar.gz"
mkdir /tmp/flux && tar -xzf /tmp/flux.tar.gz -C /tmp/flux/
sudo mv /tmp/flux/flux /usr/local/bin/flux
sudo chown 0:0 /usr/local/bin/flux
sudo chmod 0755 /usr/local/bin/flux
}
user_setup_env

View File

@@ -3,7 +3,6 @@ package controller
import (
"context"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -16,10 +15,6 @@ import (
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
)
const (
deletionRequeueDelay = 30 * time.Second
)
// WorkloadMonitorReconciler reconciles a WorkloadMonitor object
type WorkloadReconciler struct {
client.Client
@@ -57,9 +52,6 @@ func (r *WorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
// found object, nothing to do
if err == nil {
if !t.GetDeletionTimestamp().IsZero() {
return ctrl.Result{RequeueAfter: deletionRequeueDelay}, nil
}
return ctrl.Result{}, nil
}

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/nginx-cache:0.6.0@sha256:50ac1581e3100bd6c477a71161cb455a341ffaf9e5e2f6086802e4e25271e8af
ghcr.io/cozystack/cozystack/nginx-cache:0.6.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.25.2@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.25.1@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.25.2@sha256:71f9afa218693a890f827cb5cda98ba327302bd9f58afde767740557538e07d9
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.25.1@sha256:412ed2b3c77249bd1b973e6dc9c87976d31863717fb66ba74ccda573af737eb1

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.25.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.25.1@sha256:445c2727b04ac68595b43c988ff17b3d69a7b22b0644fde3b10c65b47a7bc036

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/mariadb-backup:0.9.0@sha256:a3789db9e9e065ff60cbac70771b4a8aa1460db3194307cf5ca5d4fe1b412b6b
ghcr.io/cozystack/cozystack/mariadb-backup:0.9.0@sha256:cfd1c37d8ad24e10681d82d6e6ce8a641b4602c1b0ffa8516ae15b4958bb12d4

View File

@@ -1,2 +1,2 @@
cozystack:
image: ghcr.io/cozystack/cozystack/installer:v0.33.3@sha256:cee50a80af792af7427c5e1e32d6841f62b9eed1a857b41729372ba79bd18e68
image: ghcr.io/cozystack/cozystack/installer:v0.33.1@sha256:03a0002be9cf5926643c295bbf05c3e250401b0f0595b9fcd147d53534f368f5

View File

@@ -1,2 +1,2 @@
e2e:
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.33.3@sha256:9baa3c1465133b968e775f29f74c8b569fea29c7e5b490551f0a5baf8b6f1270
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.33.1@sha256:eed183a4104b1c142f6c4a358338749efe73baefddd53d7fe4c7149ecb892ce1

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/matchbox:v0.33.3@sha256:2e71760570c40d18b29f74f989f120563acefc77c25c477a1d6722f50794a588
ghcr.io/cozystack/cozystack/matchbox:v0.33.1@sha256:ca3638c620215ace26ace3f7e8b27391847ab2158b5a67f070f43dcbea071532

View File

@@ -1 +1 @@
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:208d8ea43b4b493ee0bea80606f6b3041a02460be79c52ed12aecccd35ec2a02
ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:b748d9add5fc4080b143d8690ca1ad851d911948ac8eb296dd9005d53d153c05

View File

@@ -1,2 +1,2 @@
cozystackAPI:
image: ghcr.io/cozystack/cozystack/cozystack-api:v0.33.3@sha256:c9d123823e2cfd8900d485401f8ac7b805be248a1a40715e746495739165787b
image: ghcr.io/cozystack/cozystack/cozystack-api:v0.33.1@sha256:ee6b71d3ab1c1484490ff1dc57a7df82813c4f18d6393f149d32acf656aa779d

View File

@@ -1,5 +1,5 @@
cozystackController:
image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.33.3@sha256:3b589fc8a102344d66407d814bdcc807a1a97a42163336bc3b5d0c44b086c128
image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.33.1@sha256:4777488e14f0313b153b153388c78ab89e3a39582c30266f2321704df1976922
debug: false
disableTelemetry: false
cozystackVersion: "v0.33.3"
cozystackVersion: "v0.33.1"

View File

@@ -76,7 +76,7 @@ data:
"kubeappsNamespace": {{ .Release.Namespace | quote }},
"helmGlobalNamespace": {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }},
"carvelGlobalNamespace": {{ .Values.kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace | quote }},
"appVersion": "v0.33.3",
"appVersion": "v0.33.1",
"authProxyEnabled": {{ .Values.authProxy.enabled }},
"oauthLoginURI": {{ .Values.authProxy.oauthLoginURI | quote }},
"oauthLogoutURI": {{ .Values.authProxy.oauthLogoutURI | quote }},

View File

@@ -19,8 +19,8 @@ kubeapps:
image:
registry: ghcr.io/cozystack/cozystack
repository: dashboard
tag: v0.33.3
digest: "sha256:ac2b5348d85fe37ad70a4cc159881c4eaded9175a4b586cfa09a52b0fbe5e1e5"
tag: v0.33.1
digest: "sha256:5e514516bd3dc0c693bb346ddeb9740e0439a59deb2a56b87317286e3ce79ac9"
redis:
master:
resourcesPreset: "none"
@@ -37,8 +37,8 @@ kubeapps:
image:
registry: ghcr.io/cozystack/cozystack
repository: kubeapps-apis
tag: v0.33.3
digest: "sha256:be25afff8d0f8ae8d2e42a824856e9776db0cee285f6f41514803a4e85e17371"
tag: v0.33.1
digest: "sha256:ea5b21a27c97b14880042d2a642670e3461e7d946c65b5b557d2eb8df9f03a87"
pluginConfig:
flux:
packages:

View File

@@ -3,7 +3,7 @@ kamaji:
deploy: false
image:
pullPolicy: IfNotPresent
tag: v0.33.3@sha256:09465ae8285b4ae43203581e443409cd4e1e119dde62a5c14d63ce064fb840b0
tag: v0.33.1@sha256:09fc5c9aeb97880780abfc6d82c216725d6f79e13494bf2399766c882b88f66b
repository: ghcr.io/cozystack/cozystack/kamaji
resources:
limits:

View File

@@ -1,3 +1,3 @@
portSecurity: true
routes: ""
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.33.3@sha256:c7f42022280a565da8b3091ed2f4fe2768fcd392327d23172a532c24794787c6
image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.33.1@sha256:595851560856e3ba7f408f259acf84599494984a9f0252de289bcb1a7fc5b9da

View File

@@ -64,4 +64,4 @@ global:
images:
kubeovn:
repository: kubeovn
tag: v1.13.13@sha256:f8edb9f98fe64daf5e3634b8844cea7747e197f3a345d6fe8be6f1d336154cfb
tag: v1.13.13@sha256:c0ffc9a0498b6f8fc392f8fc6ea43d0c7eedeeabda8ef96bca004ec4466a6bf2

View File

@@ -1,3 +1,3 @@
storageClass: replicated
csiDriver:
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.25.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0
image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.25.1@sha256:445c2727b04ac68595b43c988ff17b3d69a7b22b0644fde3b10c65b47a7bc036

View File

@@ -1,221 +0,0 @@
package server
import (
"encoding/json"
"fmt"
"strings"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
)
// -----------------------------------------------------------------------------
// shared helpers
// -----------------------------------------------------------------------------
const (
baseRef = "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.Application"
baseListRef = baseRef + "List"
smp = "application/strategic-merge-patch+json"
)
func deepCopySchema(in *spec.Schema) *spec.Schema {
if in == nil {
return nil
}
b, err := json.Marshal(in)
if err != nil {
// Log error or panic since this is unexpected
panic(fmt.Sprintf("failed to marshal schema: %v", err))
}
var out spec.Schema
if err := json.Unmarshal(b, &out); err != nil {
panic(fmt.Sprintf("failed to unmarshal schema: %v", err))
}
return &out
}
// find the object that already owns ".spec"
func findSpecContainer(s *spec.Schema) *spec.Schema {
if s == nil {
return nil
}
if len(s.Type) > 0 && s.Type.Contains("object") && s.Properties != nil {
if _, ok := s.Properties["spec"]; ok {
return s
}
}
for _, branch := range [][]spec.Schema{s.AllOf, s.OneOf, s.AnyOf} {
for i := range branch {
if res := findSpecContainer(&branch[i]); res != nil {
return res
}
}
}
return nil
}
// apply user-supplied schema; when raw == "" turn the field into a schemaless object
func patchSpec(target *spec.Schema, raw string) error {
// ------------------------------------------------------------------
// 1) schema not provided → make ".spec" a fully open object
// ------------------------------------------------------------------
if strings.TrimSpace(raw) == "" {
if target.Properties == nil {
target.Properties = map[string]spec.Schema{}
}
prop := target.Properties["spec"]
prop.AdditionalProperties = &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{},
}
target.Properties["spec"] = prop
return nil
}
// ------------------------------------------------------------------
// 2) custom schema provided → keep / inject additionalProperties
// ------------------------------------------------------------------
var custom spec.Schema
if err := json.Unmarshal([]byte(raw), &custom); err != nil {
return err
}
// if user didn't specify additionalProperties, add a permissive one
if custom.AdditionalProperties == nil {
custom.AdditionalProperties = &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{},
}
}
if target.Properties == nil {
target.Properties = map[string]spec.Schema{}
}
target.Properties["spec"] = custom
return nil
}
// -----------------------------------------------------------------------------
// OpenAPI **v3** post-processor
// -----------------------------------------------------------------------------
func buildPostProcessV3(kindSchemas map[string]string) func(*spec3.OpenAPI) (*spec3.OpenAPI, error) {
return func(doc *spec3.OpenAPI) (*spec3.OpenAPI, error) {
// Replace the basic "Application" schema with the user-supplied kinds.
if doc.Components == nil {
doc.Components = &spec3.Components{}
}
if doc.Components.Schemas == nil {
doc.Components.Schemas = map[string]*spec.Schema{}
}
base, ok := doc.Components.Schemas[baseRef]
if !ok {
return doc, fmt.Errorf("base schema %q not found", baseRef)
}
for kind, raw := range kindSchemas {
ref := fmt.Sprintf("%s.%s", "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1", kind)
s := doc.Components.Schemas[ref]
if s == nil { // first time clone "Application"
s = deepCopySchema(base)
s.Extensions = map[string]interface{}{
"x-kubernetes-group-version-kind": []interface{}{
map[string]interface{}{
"group": "apps.cozystack.io", "version": "v1alpha1", "kind": kind,
},
},
}
doc.Components.Schemas[ref] = s
}
container := findSpecContainer(s)
if container == nil { // fallback: use the root
container = s
}
if err := patchSpec(container, raw); err != nil {
return nil, fmt.Errorf("kind %s: %w", kind, err)
}
}
delete(doc.Components.Schemas, baseRef)
delete(doc.Components.Schemas, baseListRef)
// Disable strategic-merge-patch+json support in all PATCH operations
for p, pi := range doc.Paths.Paths {
if pi == nil || pi.Patch == nil || pi.Patch.RequestBody == nil {
continue
}
delete(pi.Patch.RequestBody.Content, smp)
doc.Paths.Paths[p] = pi
}
return doc, nil
}
}
// -----------------------------------------------------------------------------
// OpenAPI **v2** (swagger) post-processor
// -----------------------------------------------------------------------------
func buildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spec.Swagger, error) {
return func(sw *spec.Swagger) (*spec.Swagger, error) {
// Replace the basic "Application" schema with the user-supplied kinds.
defs := sw.Definitions
base, ok := defs[baseRef]
if !ok {
return sw, fmt.Errorf("base schema %q not found", baseRef)
}
for kind, raw := range kindSchemas {
ref := fmt.Sprintf("%s.%s", "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1", kind)
s := deepCopySchema(&base)
s.Extensions = map[string]interface{}{
"x-kubernetes-group-version-kind": []interface{}{
map[string]interface{}{
"group": "apps.cozystack.io", "version": "v1alpha1", "kind": kind,
},
},
}
if err := patchSpec(s, raw); err != nil {
return nil, fmt.Errorf("kind %s: %w", kind, err)
}
defs[ref] = *s
// clone the List variant
listName := ref + "List"
listSrc := defs[baseListRef]
listCopy := deepCopySchema(&listSrc)
listCopy.Extensions = map[string]interface{}{
"x-kubernetes-group-version-kind": []interface{}{
map[string]interface{}{
"group": "apps.cozystack.io",
"version": "v1alpha1",
"kind": kind + "List",
},
},
}
if items := listCopy.Properties["items"]; items.Items != nil && items.Items.Schema != nil {
items.Items.Schema.Ref = spec.MustCreateRef("#/definitions/" + ref)
listCopy.Properties["items"] = items
}
defs[listName] = *listCopy
}
delete(defs, baseRef)
delete(defs, baseListRef)
// Disable strategic-merge-patch+json support in all PATCH operations
for p, op := range sw.Paths.Paths {
if op.Patch != nil && len(op.Patch.Consumes) > 0 {
var out []string
for _, c := range op.Patch.Consumes {
if c != smp {
out = append(out, c)
}
}
op.Patch.Consumes = out
sw.Paths.Paths[p] = op
}
}
return sw, nil
}
}

View File

@@ -18,8 +18,6 @@ package server
import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
@@ -40,6 +38,8 @@ import (
utilversionpkg "k8s.io/apiserver/pkg/util/version"
"k8s.io/component-base/featuregate"
baseversion "k8s.io/component-base/version"
"k8s.io/klog/v2"
"k8s.io/kube-openapi/pkg/validation/spec"
netutils "k8s.io/utils/net"
)
@@ -159,6 +159,22 @@ func (o AppsServerOptions) Validate(args []string) error {
return utilerrors.NewAggregate(allErrors)
}
// DeepCopySchema делает глубокую копию структуры spec.Schema
func DeepCopySchema(schema *spec.Schema) (*spec.Schema, error) {
data, err := json.Marshal(schema)
if err != nil {
return nil, fmt.Errorf("failed to marshal schema: %w", err)
}
var newSchema spec.Schema
err = json.Unmarshal(data, &newSchema)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal schema: %w", err)
}
return &newSchema, nil
}
// Config returns the configuration for the API server based on AppsServerOptions
func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
// TODO: set the "real" external address
@@ -179,34 +195,107 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) {
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme),
)
version := "0.1"
if o.ResourceConfig != nil {
raw, err := json.Marshal(o.ResourceConfig)
if err != nil {
return nil, fmt.Errorf("failed to marshal resource config: %v", err)
}
sum := sha256.Sum256(raw)
version = "0.1-" + hex.EncodeToString(sum[:8])
}
// capture schemas from config once for fast lookup inside the closure
kindSchemas := map[string]string{}
for _, r := range o.ResourceConfig.Resources {
kindSchemas[r.Application.Kind] = r.Application.OpenAPISchema
}
serverConfig.OpenAPIConfig.Info.Title = "Apps"
serverConfig.OpenAPIConfig.Info.Version = version
serverConfig.OpenAPIConfig.PostProcessSpec = buildPostProcessV2(kindSchemas)
serverConfig.OpenAPIConfig.Info.Version = "0.1"
serverConfig.OpenAPIConfig.PostProcessSpec = func(swagger *spec.Swagger) (*spec.Swagger, error) {
defs := swagger.Definitions
// Verify the presence of the base Application/ApplicationList definitions
appDef, exists := defs["com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.Application"]
if !exists {
return swagger, fmt.Errorf("Application definition not found")
}
listDef, exists := defs["com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.ApplicationList"]
if !exists {
return swagger, fmt.Errorf("ApplicationList definition not found")
}
// Iterate over all registered GVKs (e.g., Bucket, Database, etc.)
for _, gvk := range v1alpha1.RegisteredGVKs {
// This will be something like:
// "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.Bucket"
resourceName := fmt.Sprintf("com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.%s", gvk.Kind)
// 1. Create a copy of the base Application definition for the new resource
newDef, err := DeepCopySchema(&appDef)
if err != nil {
return nil, fmt.Errorf("failed to deepcopy schema for %s: %w", gvk.Kind, err)
}
// 2. Update x-kubernetes-group-version-kind to match the new resource
if newDef.Extensions == nil {
newDef.Extensions = map[string]interface{}{}
}
newDef.Extensions["x-kubernetes-group-version-kind"] = []map[string]interface{}{
{
"group": gvk.Group,
"version": gvk.Version,
"kind": gvk.Kind,
},
}
// make `.spec` schemaless so any keys are accepted
if specProp, ok := newDef.Properties["spec"]; ok {
specProp.AdditionalProperties = &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{},
}
newDef.Properties["spec"] = specProp
}
// 3. Save the new resource definition under the correct name
defs[resourceName] = *newDef
klog.V(6).Infof("PostProcessSpec: Added OpenAPI definition for %s\n", resourceName)
// 4. Now handle the corresponding List type (e.g., BucketList).
// We'll start by copying the ApplicationList definition.
listResourceName := fmt.Sprintf("com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.%sList", gvk.Kind)
newListDef, err := DeepCopySchema(&listDef)
if err != nil {
return nil, fmt.Errorf("failed to deepcopy schema for %sList: %w", gvk.Kind, err)
}
// 5. Update x-kubernetes-group-version-kind for the List definition
if newListDef.Extensions == nil {
newListDef.Extensions = map[string]interface{}{}
}
newListDef.Extensions["x-kubernetes-group-version-kind"] = []map[string]interface{}{
{
"group": gvk.Group,
"version": gvk.Version,
"kind": fmt.Sprintf("%sList", gvk.Kind),
},
}
// 6. IMPORTANT: Fix the "items" reference so it points to the new resource
// rather than to "Application".
if itemsProp, found := newListDef.Properties["items"]; found {
if itemsProp.Items != nil && itemsProp.Items.Schema != nil {
itemsProp.Items.Schema.Ref = spec.MustCreateRef("#/definitions/" + resourceName)
newListDef.Properties["items"] = itemsProp
}
}
// 7. Finally, save the new List definition
defs[listResourceName] = *newListDef
klog.V(6).Infof("PostProcessSpec: Added OpenAPI definition for %s\n", listResourceName)
}
// Remove the original Application/ApplicationList from the definitions
delete(defs, "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.Application")
delete(defs, "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.ApplicationList")
swagger.Definitions = defs
return swagger, nil
}
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme),
)
serverConfig.OpenAPIV3Config.Info.Title = "Apps"
serverConfig.OpenAPIV3Config.Info.Version = version
serverConfig.OpenAPIV3Config.PostProcessSpec = buildPostProcessV3(kindSchemas)
serverConfig.OpenAPIV3Config.Info.Version = "0.1"
serverConfig.FeatureGate = utilversionpkg.DefaultComponentGlobalsRegistry.FeatureGateFor(
utilversionpkg.DefaultKubeComponent,

View File

@@ -36,11 +36,10 @@ type Resource struct {
// ApplicationConfig contains the application settings.
type ApplicationConfig struct {
Kind string `yaml:"kind"`
Singular string `yaml:"singular"`
Plural string `yaml:"plural"`
ShortNames []string `yaml:"shortNames"`
OpenAPISchema string `yaml:"openAPISchema"`
Kind string `yaml:"kind"`
Singular string `yaml:"singular"`
Plural string `yaml:"plural"`
ShortNames []string `yaml:"shortNames"`
}
// ReleaseConfig contains the release settings.