mirror of
https://github.com/outbackdingo/cozystack.git
synced 2026-01-27 10:18:39 +00:00
New dashboard based on OpenAPI schema (#1269)
A new dashboard based on https://github.com/PRO-Robotech/openapi-ui project <img width="1720" height="1373" alt="Screenshot 2025-08-01 at 09-01-00 OpenAPI UI" src="https://github.com/user-attachments/assets/7ae04789-24ec-4e4b-830b-6f16e96513eb" /> <img width="1720" height="1373" alt="Screenshot 2025-08-01 at 09-01-14 OpenAPI UI" src="https://github.com/user-attachments/assets/ca5aa85d-43f0-4b5b-b87a-3bc237834f10" /> <img width="1720" height="1373" alt="Screenshot 2025-08-01 at 09-02-05 OpenAPI UI" src="https://github.com/user-attachments/assets/ebee7bfa-c3ac-4fe6-b5e1-43e9e7042c6a" /> <!-- Thank you for making a contribution! Here are some tips for you: - Start the PR title with the [label] of Cozystack component: - For system components: [platform], [system], [linstor], [cilium], [kube-ovn], [dashboard], [cluster-api], etc. - For managed apps: [apps], [tenant], [kubernetes], [postgres], [virtual-machine] etc. - For development and maintenance: [tests], [ci], [docs], [maintenance]. - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same [label] as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note [cozystack-api] Implement TenantNamespace, TenantModules, TenantSecret and TenantSecretsTable resources [cozystack-controller] Introduce new dashboard-controller [dashboard] Introduce new dashboard based on openapi-ui ```
This commit is contained in:
@@ -5,7 +5,7 @@ repos:
|
||||
name: Run 'make generate' in all app directories
|
||||
entry: |
|
||||
flock -x .git/pre-commit.lock sh -c '
|
||||
for dir in ./packages/apps/*/ ./packages/extra/*/ ./packages/system/cozystack-api/; do
|
||||
for dir in ./packages/apps/*/ ./packages/extra/*/; do
|
||||
if [ -d "$dir" ]; then
|
||||
echo "Running make generate in $dir"
|
||||
make generate -C "$dir" || exit $?
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
API rule violation: list_type_missing,github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1,ApplicationStatus,Conditions
|
||||
API rule violation: list_type_missing,github.com/cozystack/cozystack/pkg/apis/core/v1alpha1,TenantModuleStatus,Conditions
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Ref
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Schema
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,XEmbeddedResource
|
||||
|
||||
255
api/dashboard/v1alpha1/dashboard_resources.go
Normal file
255
api/dashboard/v1alpha1/dashboard_resources.go
Normal file
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Package v1alpha1 defines front.in-cloud.io API types.
|
||||
//
|
||||
// Group: dashboard.cozystack.io
|
||||
// Version: v1alpha1
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shared shapes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// CommonStatus is a generic Status block with Kubernetes conditions.
|
||||
type CommonStatus struct {
|
||||
// ObservedGeneration reflects the most recent generation observed by the controller.
|
||||
// +optional
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// Conditions represent the latest available observations of an object's state.
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// ArbitrarySpec holds schemaless user data and preserves unknown fields.
|
||||
// We map the entire .spec to a single JSON payload to mirror the CRDs you provided.
|
||||
// NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips.
|
||||
type ArbitrarySpec struct {
|
||||
// +kubebuilder:validation:XPreserveUnknownFields
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
v1.JSON `json:",inline"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Sidebar
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=sidebars,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type Sidebar struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type SidebarList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Sidebar `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CustomFormsPrefill (shortName: cfp)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=customformsprefills,scope=Cluster,shortName=cfp
|
||||
// +kubebuilder:subresource:status
|
||||
type CustomFormsPrefill struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type CustomFormsPrefillList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []CustomFormsPrefill `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BreadcrumbInside
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=breadcrumbsinside,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type BreadcrumbInside struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type BreadcrumbInsideList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []BreadcrumbInside `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CustomFormsOverride (shortName: cfo)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=customformsoverrides,scope=Cluster,shortName=cfo
|
||||
// +kubebuilder:subresource:status
|
||||
type CustomFormsOverride struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type CustomFormsOverrideList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []CustomFormsOverride `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// TableUriMapping
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=tableurimappings,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type TableUriMapping struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type TableUriMappingList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []TableUriMapping `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Breadcrumb
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=breadcrumbs,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type Breadcrumb struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type BreadcrumbList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Breadcrumb `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MarketplacePanel
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=marketplacepanels,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type MarketplacePanel struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type MarketplacePanelList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []MarketplacePanel `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Navigation
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=navigations,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type Navigation struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type NavigationList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Navigation `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CustomColumnsOverride
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=customcolumnsoverrides,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type CustomColumnsOverride struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type CustomColumnsOverrideList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []CustomColumnsOverride `json:"items"`
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Factory
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=factories,scope=Cluster
|
||||
// +kubebuilder:subresource:status
|
||||
type Factory struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ArbitrarySpec `json:"spec"`
|
||||
Status CommonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
type FactoryList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Factory `json:"items"`
|
||||
}
|
||||
75
api/dashboard/v1alpha1/groupversion_info.go
Normal file
75
api/dashboard/v1alpha1/groupversion_info.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2025.
|
||||
|
||||
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 v1alpha1 contains API Schema definitions for the v1alpha1 API group.
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=dashboard.cozystack.io
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects.
|
||||
GroupVersion = schema.GroupVersion{Group: "dashboard.cozystack.io", Version: "v1alpha1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(
|
||||
GroupVersion,
|
||||
|
||||
&Sidebar{},
|
||||
&SidebarList{},
|
||||
|
||||
&CustomFormsPrefill{},
|
||||
&CustomFormsPrefillList{},
|
||||
|
||||
&BreadcrumbInside{},
|
||||
&BreadcrumbInsideList{},
|
||||
|
||||
&CustomFormsOverride{},
|
||||
&CustomFormsOverrideList{},
|
||||
|
||||
&TableUriMapping{},
|
||||
&TableUriMappingList{},
|
||||
|
||||
&Breadcrumb{},
|
||||
&BreadcrumbList{},
|
||||
|
||||
&MarketplacePanel{},
|
||||
&MarketplacePanelList{},
|
||||
|
||||
&Navigation{},
|
||||
&NavigationList{},
|
||||
|
||||
&CustomColumnsOverride{},
|
||||
&CustomColumnsOverrideList{},
|
||||
|
||||
&Factory{},
|
||||
&FactoryList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, GroupVersion)
|
||||
return nil
|
||||
}
|
||||
654
api/dashboard/v1alpha1/zz_generated.deepcopy.go
Normal file
654
api/dashboard/v1alpha1/zz_generated.deepcopy.go
Normal file
@@ -0,0 +1,654 @@
|
||||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2025 The Cozystack Authors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ArbitrarySpec) DeepCopyInto(out *ArbitrarySpec) {
|
||||
*out = *in
|
||||
in.JSON.DeepCopyInto(&out.JSON)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArbitrarySpec.
|
||||
func (in *ArbitrarySpec) DeepCopy() *ArbitrarySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ArbitrarySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Breadcrumb) DeepCopyInto(out *Breadcrumb) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Breadcrumb.
|
||||
func (in *Breadcrumb) DeepCopy() *Breadcrumb {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Breadcrumb)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Breadcrumb) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BreadcrumbInside) DeepCopyInto(out *BreadcrumbInside) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbInside.
|
||||
func (in *BreadcrumbInside) DeepCopy() *BreadcrumbInside {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BreadcrumbInside)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *BreadcrumbInside) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BreadcrumbInsideList) DeepCopyInto(out *BreadcrumbInsideList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]BreadcrumbInside, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbInsideList.
|
||||
func (in *BreadcrumbInsideList) DeepCopy() *BreadcrumbInsideList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BreadcrumbInsideList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *BreadcrumbInsideList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BreadcrumbList) DeepCopyInto(out *BreadcrumbList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Breadcrumb, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbList.
|
||||
func (in *BreadcrumbList) DeepCopy() *BreadcrumbList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BreadcrumbList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *BreadcrumbList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CommonStatus) DeepCopyInto(out *CommonStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonStatus.
|
||||
func (in *CommonStatus) DeepCopy() *CommonStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CommonStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomColumnsOverride) DeepCopyInto(out *CustomColumnsOverride) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomColumnsOverride.
|
||||
func (in *CustomColumnsOverride) DeepCopy() *CustomColumnsOverride {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomColumnsOverride)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomColumnsOverride) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomColumnsOverrideList) DeepCopyInto(out *CustomColumnsOverrideList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CustomColumnsOverride, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomColumnsOverrideList.
|
||||
func (in *CustomColumnsOverrideList) DeepCopy() *CustomColumnsOverrideList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomColumnsOverrideList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomColumnsOverrideList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomFormsOverride) DeepCopyInto(out *CustomFormsOverride) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsOverride.
|
||||
func (in *CustomFormsOverride) DeepCopy() *CustomFormsOverride {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomFormsOverride)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomFormsOverride) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomFormsOverrideList) DeepCopyInto(out *CustomFormsOverrideList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CustomFormsOverride, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsOverrideList.
|
||||
func (in *CustomFormsOverrideList) DeepCopy() *CustomFormsOverrideList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomFormsOverrideList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomFormsOverrideList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomFormsPrefill) DeepCopyInto(out *CustomFormsPrefill) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsPrefill.
|
||||
func (in *CustomFormsPrefill) DeepCopy() *CustomFormsPrefill {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomFormsPrefill)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomFormsPrefill) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomFormsPrefillList) DeepCopyInto(out *CustomFormsPrefillList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CustomFormsPrefill, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsPrefillList.
|
||||
func (in *CustomFormsPrefillList) DeepCopy() *CustomFormsPrefillList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomFormsPrefillList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomFormsPrefillList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Factory) DeepCopyInto(out *Factory) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Factory.
|
||||
func (in *Factory) DeepCopy() *Factory {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Factory)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Factory) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *FactoryList) DeepCopyInto(out *FactoryList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Factory, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FactoryList.
|
||||
func (in *FactoryList) DeepCopy() *FactoryList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FactoryList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FactoryList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MarketplacePanel) DeepCopyInto(out *MarketplacePanel) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MarketplacePanel.
|
||||
func (in *MarketplacePanel) DeepCopy() *MarketplacePanel {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MarketplacePanel)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *MarketplacePanel) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MarketplacePanelList) DeepCopyInto(out *MarketplacePanelList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]MarketplacePanel, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MarketplacePanelList.
|
||||
func (in *MarketplacePanelList) DeepCopy() *MarketplacePanelList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MarketplacePanelList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *MarketplacePanelList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Navigation) DeepCopyInto(out *Navigation) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Navigation.
|
||||
func (in *Navigation) DeepCopy() *Navigation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Navigation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Navigation) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NavigationList) DeepCopyInto(out *NavigationList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Navigation, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NavigationList.
|
||||
func (in *NavigationList) DeepCopy() *NavigationList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NavigationList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *NavigationList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Sidebar) DeepCopyInto(out *Sidebar) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sidebar.
|
||||
func (in *Sidebar) DeepCopy() *Sidebar {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Sidebar)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Sidebar) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SidebarList) DeepCopyInto(out *SidebarList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Sidebar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SidebarList.
|
||||
func (in *SidebarList) DeepCopy() *SidebarList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SidebarList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SidebarList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TableUriMapping) DeepCopyInto(out *TableUriMapping) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TableUriMapping.
|
||||
func (in *TableUriMapping) DeepCopy() *TableUriMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TableUriMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *TableUriMapping) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TableUriMappingList) DeepCopyInto(out *TableUriMappingList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]TableUriMapping, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TableUriMappingList.
|
||||
func (in *TableUriMappingList) DeepCopy() *TableUriMappingList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TableUriMappingList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *TableUriMappingList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
)
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:scope=Cluster
|
||||
|
||||
// CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API
|
||||
type CozystackResourceDefinition struct {
|
||||
@@ -48,8 +49,12 @@ type CozystackResourceDefinitionSpec struct {
|
||||
Application CozystackResourceDefinitionApplication `json:"application"`
|
||||
// Release configuration
|
||||
Release CozystackResourceDefinitionRelease `json:"release"`
|
||||
|
||||
// Secret selectors
|
||||
Secrets CozystackResourceDefinitionSecrets `json:"secrets,omitempty"`
|
||||
|
||||
// Dashboard configuration for this resource
|
||||
Dashboard *CozystackResourceDefinitionDashboard `json:"dashboard,omitempty"`
|
||||
}
|
||||
|
||||
type CozystackResourceDefinitionChart struct {
|
||||
@@ -101,3 +106,51 @@ type CozystackResourceDefinitionSecrets struct {
|
||||
// as a tenant secret and is visible to users.
|
||||
Include []*metav1.LabelSelector `json:"include,omitempty"`
|
||||
}
|
||||
|
||||
// ---- Dashboard types ----
|
||||
|
||||
// DashboardTab enumerates allowed UI tabs.
|
||||
// +kubebuilder:validation:Enum=workloads;ingresses;services;secrets;yaml
|
||||
type DashboardTab string
|
||||
|
||||
const (
|
||||
DashboardTabWorkloads DashboardTab = "workloads"
|
||||
DashboardTabIngresses DashboardTab = "ingresses"
|
||||
DashboardTabServices DashboardTab = "services"
|
||||
DashboardTabSecrets DashboardTab = "secrets"
|
||||
DashboardTabYAML DashboardTab = "yaml"
|
||||
)
|
||||
|
||||
// CozystackResourceDefinitionDashboard describes how this resource appears in the UI.
|
||||
type CozystackResourceDefinitionDashboard struct {
|
||||
// Human-readable name shown in the UI (e.g., "Bucket")
|
||||
Singular string `json:"singular"`
|
||||
// Plural human-readable name (e.g., "Buckets")
|
||||
Plural string `json:"plural"`
|
||||
// Hard-coded name used in the UI (e.g., "bucket")
|
||||
// +optional
|
||||
Name string `json:"name,omitempty"`
|
||||
// Whether this resource is singular (not a collection) in the UI
|
||||
// +optional
|
||||
SingularResource bool `json:"singularResource,omitempty"`
|
||||
// Order weight for sorting resources in the UI (lower first)
|
||||
// +optional
|
||||
Weight int `json:"weight,omitempty"`
|
||||
// Short description shown in catalogs or headers (e.g., "S3 compatible storage")
|
||||
// +optional
|
||||
Description string `json:"description,omitempty"`
|
||||
// Icon encoded as a string (e.g., inline SVG, base64, or data URI)
|
||||
// +optional
|
||||
Icon string `json:"icon,omitempty"`
|
||||
// Category used to group resources in the UI (e.g., "Storage", "Networking")
|
||||
Category string `json:"category"`
|
||||
// Free-form tags for search and filtering
|
||||
// +optional
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Which tabs to show for this resource
|
||||
// +optional
|
||||
Tabs []DashboardTab `json:"tabs,omitempty"`
|
||||
// Order of keys in the YAML view
|
||||
// +optional
|
||||
KeysOrder [][]string `json:"keysOrder,omitempty"`
|
||||
}
|
||||
|
||||
@@ -83,6 +83,42 @@ func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinit
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) {
|
||||
*out = *in
|
||||
if in.Tags != nil {
|
||||
in, out := &in.Tags, &out.Tags
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Tabs != nil {
|
||||
in, out := &in.Tabs, &out.Tabs
|
||||
*out = make([]DashboardTab, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.KeysOrder != nil {
|
||||
in, out := &in.KeysOrder, &out.KeysOrder
|
||||
*out = make([][]string, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionDashboard.
|
||||
func (in *CozystackResourceDefinitionDashboard) DeepCopy() *CozystackResourceDefinitionDashboard {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CozystackResourceDefinitionDashboard)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CozystackResourceDefinitionList) DeepCopyInto(out *CozystackResourceDefinitionList) {
|
||||
*out = *in
|
||||
@@ -181,6 +217,11 @@ func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDe
|
||||
out.Application = in.Application
|
||||
in.Release.DeepCopyInto(&out.Release)
|
||||
in.Secrets.DeepCopyInto(&out.Secrets)
|
||||
if in.Dashboard != nil {
|
||||
in, out := &in.Dashboard, &out.Dashboard
|
||||
*out = new(CozystackResourceDefinitionDashboard)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionSpec.
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx := genericapiserver.SetupSignalContext()
|
||||
options := server.NewAppsServerOptions(os.Stdout, os.Stderr)
|
||||
cmd := server.NewCommandStartAppsServer(ctx, options)
|
||||
options := server.NewCozyServerOptions(os.Stdout, os.Stderr)
|
||||
cmd := server.NewCommandStartCozyServer(ctx, options)
|
||||
code := cli.Run(cmd)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
|
||||
cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
"github.com/cozystack/cozystack/internal/controller"
|
||||
"github.com/cozystack/cozystack/internal/controller/dashboard"
|
||||
lcw "github.com/cozystack/cozystack/internal/lineagecontrollerwebhook"
|
||||
"github.com/cozystack/cozystack/internal/telemetry"
|
||||
|
||||
@@ -54,6 +55,7 @@ func init() {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
|
||||
utilruntime.Must(cozystackiov1alpha1.AddToScheme(scheme))
|
||||
utilruntime.Must(dashboard.AddToScheme(scheme))
|
||||
utilruntime.Must(helmv2.AddToScheme(scheme))
|
||||
// +kubebuilder:scaffold:scheme
|
||||
}
|
||||
|
||||
139
hack/update-crd.sh
Executable file
139
hack/update-crd.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Requirements: yq (v4), jq, base64
|
||||
need() { command -v "$1" >/dev/null 2>&1 || { echo "need $1"; exit 1; }; }
|
||||
need yq; need jq; need base64
|
||||
|
||||
CHART_YAML="${CHART_YAML:-Chart.yaml}"
|
||||
VALUES_YAML="${VALUES_YAML:-values.yaml}"
|
||||
SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}"
|
||||
CRD_DIR="../../system/cozystack-api/templates/cozystack-resource-definitions"
|
||||
|
||||
[[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; }
|
||||
[[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; }
|
||||
|
||||
# Read basics from Chart.yaml
|
||||
NAME="$(yq -r '.name // ""' "$CHART_YAML")"
|
||||
DESC="$(yq -r '.description // ""' "$CHART_YAML")"
|
||||
ICON_PATH_RAW="$(yq -r '.icon // ""' "$CHART_YAML")"
|
||||
|
||||
if [[ -z "$NAME" ]]; then
|
||||
echo "Chart.yaml: .name is empty"; exit 1
|
||||
fi
|
||||
|
||||
# Resolve icon path
|
||||
# Accepts:
|
||||
# /logos/foo.svg -> ./logos/foo.svg
|
||||
# logos/foo.svg -> logos/foo.svg
|
||||
# ./logos/foo.svg -> ./logos/foo.svg
|
||||
# Fallback: ./logos/${NAME}.svg
|
||||
resolve_icon_path() {
|
||||
local p="$1"
|
||||
if [[ -z "$p" || "$p" == "null" ]]; then
|
||||
echo "./logos/${NAME}.svg"; return
|
||||
fi
|
||||
if [[ "$p" == /* ]]; then
|
||||
echo ".${p}"
|
||||
else
|
||||
echo "$p"
|
||||
fi
|
||||
}
|
||||
ICON_PATH="$(resolve_icon_path "$ICON_PATH_RAW")"
|
||||
|
||||
if [[ ! -f "$ICON_PATH" ]]; then
|
||||
# try fallback
|
||||
ALT="./logos/${NAME}.svg"
|
||||
if [[ -f "$ALT" ]]; then
|
||||
ICON_PATH="$ALT"
|
||||
else
|
||||
echo "Icon not found: $ICON_PATH"; exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Base64 (portable: no -w / -b options)
|
||||
ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')"
|
||||
|
||||
# Decide which HelmRepository name to use based on path
|
||||
# .../apps/... -> cozystack-apps
|
||||
# .../extra/... -> cozystack-extra
|
||||
# default: cozystack-apps
|
||||
SOURCE_NAME="cozystack-apps"
|
||||
case "$PWD" in
|
||||
*"/apps/"*) SOURCE_NAME="cozystack-apps" ;;
|
||||
*"/extra/"*) SOURCE_NAME="cozystack-extra" ;;
|
||||
esac
|
||||
|
||||
# If file doesn't exist, create a minimal skeleton
|
||||
OUT="${OUT:-$CRD_DIR/$NAME.yaml}"
|
||||
if [[ ! -f "$OUT" ]]; then
|
||||
cat >"$OUT" <<EOF
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: ${NAME}
|
||||
spec: {}
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Export vars for yq env()
|
||||
export RES_NAME="$NAME"
|
||||
export PREFIX="$NAME-"
|
||||
if [ "$SOURCE_NAME" == "cozystack-extra" ]; then
|
||||
export PREFIX=""
|
||||
fi
|
||||
export DESCRIPTION="$DESC"
|
||||
export ICON_B64="$ICON_B64"
|
||||
export SOURCE_NAME="$SOURCE_NAME"
|
||||
export SCHEMA_JSON_MIN="$(jq -c . "$SCHEMA_JSON")"
|
||||
|
||||
# Generate keysOrder from values.yaml
|
||||
export KEYS_ORDER="$(
|
||||
yq -o=json '.' "$VALUES_YAML" | jq -c '
|
||||
def get_paths_recursive(obj; path):
|
||||
obj | to_entries | map(
|
||||
.key as $key |
|
||||
.value as $value |
|
||||
if $value | type == "object" then
|
||||
[path + [$key]] + get_paths_recursive($value; path + [$key])
|
||||
else
|
||||
[path + [$key]]
|
||||
end
|
||||
) | flatten(1)
|
||||
;
|
||||
(
|
||||
[ ["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata","name"] ]
|
||||
)
|
||||
+
|
||||
(
|
||||
get_paths_recursive(.; []) # get all paths in order
|
||||
| map(select(length>0)) # drop root
|
||||
| map(map(select(type != "number"))) # drop array indices
|
||||
| map(["spec"] + .) # prepend "spec"
|
||||
)
|
||||
'
|
||||
)"
|
||||
|
||||
# Update only necessary fields in-place
|
||||
# - openAPISchema is loaded from file as a multi-line string (block scalar)
|
||||
# - labels ensure cozystack.io/ui: "true"
|
||||
# - prefix = "<name>-"
|
||||
# - sourceRef derived from directory (apps|extra)
|
||||
yq -i '
|
||||
.apiVersion = (.apiVersion // "cozystack.io/v1alpha1") |
|
||||
.kind = (.kind // "CozystackResourceDefinition") |
|
||||
.metadata.name = strenv(RES_NAME) |
|
||||
.spec.application.openAPISchema = strenv(SCHEMA_JSON_MIN) |
|
||||
(.spec.application.openAPISchema style="literal") |
|
||||
.spec.release.prefix = (strenv(PREFIX)) |
|
||||
.spec.release.labels."cozystack.io/ui" = "true" |
|
||||
.spec.release.chart.name = strenv(RES_NAME) |
|
||||
.spec.release.chart.sourceRef.kind = "HelmRepository" |
|
||||
.spec.release.chart.sourceRef.name = strenv(SOURCE_NAME) |
|
||||
.spec.release.chart.sourceRef.namespace = "cozy-public" |
|
||||
.spec.dashboard.description = strenv(DESCRIPTION) |
|
||||
.spec.dashboard.icon = strenv(ICON_B64) |
|
||||
.spec.dashboard.keysOrder = env(KEYS_ORDER)
|
||||
' "$OUT"
|
||||
|
||||
echo "Updated $OUT"
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cozystack/cozystack/internal/controller/dashboard"
|
||||
"github.com/cozystack/cozystack/internal/shared/crdmem"
|
||||
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
@@ -50,6 +51,25 @@ func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, r
|
||||
r.mem.Upsert(crd)
|
||||
}
|
||||
|
||||
mgr := dashboard.NewManager(
|
||||
r.Client,
|
||||
r.Scheme,
|
||||
dashboard.WithCRDListFunc(func(c context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error) {
|
||||
if r.mem != nil {
|
||||
return r.mem.ListFromCacheOrAPI(c, r.Client)
|
||||
}
|
||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
||||
if err := r.Client.List(c, &list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list.Items, nil
|
||||
}),
|
||||
)
|
||||
|
||||
if res, derr := mgr.EnsureForCRD(ctx, crd); derr != nil || res.Requeue || res.RequeueAfter > 0 {
|
||||
return res, derr
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
r.lastEvent = time.Now()
|
||||
r.mu.Unlock()
|
||||
@@ -102,17 +122,23 @@ type crdHashView struct {
|
||||
Spec cozyv1alpha1.CozystackResourceDefinitionSpec `json:"spec"`
|
||||
}
|
||||
|
||||
func (r *CozystackResourceDefinitionReconciler) computeConfigHash() (string, error) {
|
||||
if r.mem == nil {
|
||||
return "", nil
|
||||
func (r *CozystackResourceDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) {
|
||||
var items []cozyv1alpha1.CozystackResourceDefinition
|
||||
if r.mem != nil {
|
||||
list, err := r.mem.ListFromCacheOrAPI(ctx, r.Client)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
items = list
|
||||
}
|
||||
snapshot := r.mem.Snapshot()
|
||||
sort.Slice(snapshot, func(i, j int) bool { return snapshot[i].Name < snapshot[j].Name })
|
||||
views := make([]crdHashView, 0, len(snapshot))
|
||||
for i := range snapshot {
|
||||
|
||||
sort.Slice(items, func(i, j int) bool { return items[i].Name < items[j].Name })
|
||||
|
||||
views := make([]crdHashView, 0, len(items))
|
||||
for i := range items {
|
||||
views = append(views, crdHashView{
|
||||
Name: snapshot[i].Name,
|
||||
Spec: snapshot[i].Spec,
|
||||
Name: items[i].Name,
|
||||
Spec: items[i].Spec,
|
||||
})
|
||||
}
|
||||
b, err := json.Marshal(views)
|
||||
@@ -143,7 +169,7 @@ func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Con
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
newHash, err := r.computeConfigHash()
|
||||
newHash, err := r.computeConfigHash(ctx)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
298
internal/controller/dashboard/customcolumns.go
Normal file
298
internal/controller/dashboard/customcolumns.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1"
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
)
|
||||
|
||||
// ensureCustomColumnsOverride creates or updates a CustomColumnsOverride that
|
||||
// renders a header row with a colored badge and resource name link, plus a few
|
||||
// useful columns (Ready, Created, Version).
|
||||
//
|
||||
// Naming convention mirrors your example:
|
||||
//
|
||||
// metadata.name: stock-namespace-<group>.<version>.<plural>
|
||||
// spec.id: stock-namespace-/<group>/<version>/<plural>
|
||||
func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (controllerutil.OperationResult, error) {
|
||||
g, v, kind := pickGVK(crd)
|
||||
plural := pickPlural(kind, crd)
|
||||
// Details page segment uses lowercase kind, mirroring your example
|
||||
detailsSegment := strings.ToLower(kind) + "-details"
|
||||
|
||||
name := fmt.Sprintf("stock-namespace-%s.%s.%s", g, v, plural)
|
||||
id := fmt.Sprintf("stock-namespace-/%s/%s/%s", g, v, plural)
|
||||
|
||||
// Badge content & color derived from kind
|
||||
badgeText := initialsFromKind(kind) // e.g., "VirtualMachine" -> "VM", "Bucket" -> "B"
|
||||
badgeColor := hexColorForKind(kind) // deterministic, dark enough for white text
|
||||
|
||||
obj := &dashv1alpha1.CustomColumnsOverride{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "dashboard.cozystack.io",
|
||||
Version: "v1alpha1",
|
||||
Kind: "CustomColumnsOverride",
|
||||
})
|
||||
obj.SetName(name)
|
||||
|
||||
href := fmt.Sprintf("/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/%s/{reqsJsonPath[0]['.metadata.name']['-']}", detailsSegment)
|
||||
if g == "apps.cozystack.io" && kind == "Tenant" && plural == "tenants" {
|
||||
href = "/openapi-ui/{2}/{reqsJsonPath[0]['.status.namespace']['-']}/api-table/core.cozystack.io/v1alpha1/tenantmodules"
|
||||
}
|
||||
|
||||
desired := map[string]any{
|
||||
"spec": map[string]any{
|
||||
"id": id,
|
||||
"additionalPrinterColumns": []any{
|
||||
map[string]any{
|
||||
"name": "Name",
|
||||
"type": "factory",
|
||||
"jsonPath": ".metadata.name",
|
||||
"customProps": map[string]any{
|
||||
"disableEventBubbling": true,
|
||||
"items": []any{
|
||||
map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": "header-row",
|
||||
"align": "center",
|
||||
"gap": 6,
|
||||
},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "header-badge",
|
||||
"text": badgeText,
|
||||
"title": strings.ToLower(kind), // optional tooltip
|
||||
"style": map[string]any{
|
||||
"backgroundColor": badgeColor,
|
||||
"borderRadius": "20px",
|
||||
"color": "#fff",
|
||||
"display": "inline-block",
|
||||
"fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif",
|
||||
"fontSize": "15px",
|
||||
"fontWeight": 400,
|
||||
"lineHeight": "24px",
|
||||
"minWidth": 24,
|
||||
"padding": "0 9px",
|
||||
"textAlign": "center",
|
||||
"whiteSpace": "nowrap",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "antdLink",
|
||||
"data": map[string]any{
|
||||
"id": "name-link",
|
||||
"text": "{reqsJsonPath[0]['.metadata.name']['-']}",
|
||||
"href": href,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"name": "Ready",
|
||||
"type": "Boolean",
|
||||
"jsonPath": `.status.conditions[?(@.type=="Ready")].status`,
|
||||
},
|
||||
map[string]any{
|
||||
"name": "Created",
|
||||
"type": "factory",
|
||||
"jsonPath": ".metadata.creationTimestamp",
|
||||
"customProps": map[string]any{
|
||||
"disableEventBubbling": true,
|
||||
"items": []any{
|
||||
map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": "time-block",
|
||||
"align": "center",
|
||||
"gap": 6,
|
||||
},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "time-icon",
|
||||
"text": "🌐",
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"id": "time-value",
|
||||
"text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}",
|
||||
"formatter": "timestamp",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"name": "Version",
|
||||
"type": "string",
|
||||
"jsonPath": ".status.version",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// CreateOrUpdate using typed resource
|
||||
_, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(desired["spec"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj.Spec = dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}}
|
||||
return nil
|
||||
})
|
||||
// Return OperationResultCreated/Updated is not available here with unstructured; we can mimic Updated when no error.
|
||||
return controllerutil.OperationResultNone, err
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
// pickGVK tries to read group/version/kind from the CRD. We prefer the "application" section,
|
||||
// falling back to other likely fields if your schema differs.
|
||||
func pickGVK(crd *cozyv1alpha1.CozystackResourceDefinition) (group, version, kind string) {
|
||||
// Best guess based on your examples:
|
||||
if crd.Spec.Application.Kind != "" {
|
||||
kind = crd.Spec.Application.Kind
|
||||
}
|
||||
|
||||
// Reasonable fallbacks if any are empty:
|
||||
if group == "" {
|
||||
group = "apps.cozystack.io"
|
||||
}
|
||||
if version == "" {
|
||||
version = "v1alpha1"
|
||||
}
|
||||
if kind == "" {
|
||||
kind = "Resource"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// pickPlural prefers a field on the CRD if you have it; otherwise do a simple lowercase + "s".
|
||||
func pickPlural(kind string, crd *cozyv1alpha1.CozystackResourceDefinition) string {
|
||||
// If you have crd.Spec.Application.Plural, prefer it. Example:
|
||||
if crd.Spec.Application.Plural != "" {
|
||||
return crd.Spec.Application.Plural
|
||||
}
|
||||
// naive pluralization
|
||||
k := strings.ToLower(kind)
|
||||
if strings.HasSuffix(k, "s") {
|
||||
return k
|
||||
}
|
||||
return k + "s"
|
||||
}
|
||||
|
||||
// initialsFromKind splits CamelCase and returns the first letters in upper case.
|
||||
// "VirtualMachine" -> "VM"; "Bucket" -> "B".
|
||||
func initialsFromKind(kind string) string {
|
||||
parts := splitCamel(kind)
|
||||
if len(parts) == 0 {
|
||||
return strings.ToUpper(kind)
|
||||
}
|
||||
var b strings.Builder
|
||||
for _, p := range parts {
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
b.WriteString(strings.ToUpper(string(p[0])))
|
||||
// Limit to 3 chars to keep the badge compact (VM, PVC, etc.)
|
||||
if b.Len() >= 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// hexColorForKind returns a dark, saturated color (hex) derived from a stable hash of the kind.
|
||||
// We map the hash to an HSL hue; fix S/L for consistent readability with white text.
|
||||
func hexColorForKind(kind string) string {
|
||||
// Stable short hash (sha1 → bytes → hue)
|
||||
sum := sha1.Sum([]byte(kind))
|
||||
// Use first two bytes for hue [0..359]
|
||||
hue := int(sum[0])<<8 | int(sum[1])
|
||||
hue = hue % 360
|
||||
|
||||
// Fixed S/L chosen to contrast with white text:
|
||||
// S = 80%, L = 35% (dark enough so #fff is readable)
|
||||
r, g, b := hslToRGB(float64(hue), 0.80, 0.35)
|
||||
|
||||
return fmt.Sprintf("#%02x%02x%02x", r, g, b)
|
||||
}
|
||||
|
||||
// hslToRGB converts HSL (0..360, 0..1, 0..1) to sRGB (0..255).
|
||||
func hslToRGB(h float64, s float64, l float64) (uint8, uint8, uint8) {
|
||||
c := (1 - absFloat(2*l-1)) * s
|
||||
hp := h / 60.0
|
||||
x := c * (1 - absFloat(modFloat(hp, 2)-1))
|
||||
var r1, g1, b1 float64
|
||||
switch {
|
||||
case 0 <= hp && hp < 1:
|
||||
r1, g1, b1 = c, x, 0
|
||||
case 1 <= hp && hp < 2:
|
||||
r1, g1, b1 = x, c, 0
|
||||
case 2 <= hp && hp < 3:
|
||||
r1, g1, b1 = 0, c, x
|
||||
case 3 <= hp && hp < 4:
|
||||
r1, g1, b1 = 0, x, c
|
||||
case 4 <= hp && hp < 5:
|
||||
r1, g1, b1 = x, 0, c
|
||||
default:
|
||||
r1, g1, b1 = c, 0, x
|
||||
}
|
||||
m := l - c/2
|
||||
r := uint8(clamp01(r1+m) * 255.0)
|
||||
g := uint8(clamp01(g1+m) * 255.0)
|
||||
b := uint8(clamp01(b1+m) * 255.0)
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
func absFloat(v float64) float64 {
|
||||
if v < 0 {
|
||||
return -v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func modFloat(a, b float64) float64 {
|
||||
return a - b*float64(int(a/b))
|
||||
}
|
||||
|
||||
func clamp01(v float64) float64 {
|
||||
if v < 0 {
|
||||
return 0
|
||||
}
|
||||
if v > 1 {
|
||||
return 1
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// optional: tiny helper to expose the compact color hash (useful for debugging)
|
||||
func shortHashHex(s string) string {
|
||||
sum := sha1.Sum([]byte(s))
|
||||
return hex.EncodeToString(sum[:4])
|
||||
}
|
||||
784
internal/controller/dashboard/factory.go
Normal file
784
internal/controller/dashboard/factory.go
Normal file
@@ -0,0 +1,784 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1"
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
)
|
||||
|
||||
// ---------------- Types used by OpenAPI parsing ----------------
|
||||
|
||||
type fieldInfo struct {
|
||||
JSONPathSpec string // dotted path under .spec (e.g., "systemDisk.image")
|
||||
Label string // "System Disk / Image" or "systemDisk.image"
|
||||
Description string
|
||||
}
|
||||
|
||||
// ---------------- Public entry: ensure Factory ------------------
|
||||
|
||||
func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
||||
g, v, kind := pickGVK(crd)
|
||||
plural := pickPlural(kind, crd)
|
||||
|
||||
lowerKind := strings.ToLower(kind)
|
||||
factoryName := fmt.Sprintf("%s-details", lowerKind)
|
||||
resourceFetch := fmt.Sprintf("/api/clusters/{2}/k8s/apis/%s/%s/namespaces/{3}/%s/{6}", g, v, plural)
|
||||
|
||||
flags := factoryFeatureFlags(crd)
|
||||
|
||||
var keysOrder [][]string
|
||||
if crd.Spec.Dashboard != nil {
|
||||
keysOrder = crd.Spec.Dashboard.KeysOrder
|
||||
}
|
||||
tabs := []any{
|
||||
detailsTab(kind, resourceFetch, crd.Spec.Application.OpenAPISchema, keysOrder),
|
||||
}
|
||||
if flags.Workloads {
|
||||
tabs = append(tabs, workloadsTab(kind))
|
||||
}
|
||||
if flags.Ingresses {
|
||||
tabs = append(tabs, ingressesTab(kind))
|
||||
}
|
||||
if flags.Services {
|
||||
tabs = append(tabs, servicesTab(kind))
|
||||
}
|
||||
if flags.Secrets {
|
||||
tabs = append(tabs, secretsTab(kind))
|
||||
}
|
||||
tabs = append(tabs, yamlTab(plural))
|
||||
|
||||
badgeText := initialsFromKind(kind)
|
||||
badgeColor := hexColorForKind(kind)
|
||||
header := map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": "header-row",
|
||||
"align": "center",
|
||||
"gap": float64(6),
|
||||
"style": map[string]any{"marginBottom": float64(24)},
|
||||
},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "badge-" + lowerKind,
|
||||
"text": badgeText,
|
||||
"title": strings.ToLower(plural),
|
||||
"style": map[string]any{
|
||||
"backgroundColor": badgeColor,
|
||||
"borderRadius": "20px",
|
||||
"color": "#fff",
|
||||
"display": "inline-block",
|
||||
"fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif",
|
||||
"fontSize": float64(20),
|
||||
"fontWeight": float64(400),
|
||||
"lineHeight": "24px",
|
||||
"minWidth": float64(24),
|
||||
"padding": "0 9px",
|
||||
"textAlign": "center",
|
||||
"whiteSpace": "nowrap",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"id": lowerKind + "-name",
|
||||
"text": "{reqsJsonPath[0]['.metadata.name']['-']}",
|
||||
"style": map[string]any{
|
||||
"fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif",
|
||||
"fontSize": float64(20),
|
||||
"lineHeight": "24px",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
spec := map[string]any{
|
||||
"key": factoryName,
|
||||
"sidebarTags": []any{fmt.Sprintf("%s-sidebar", lowerKind)},
|
||||
"withScrollableMainContentCard": true,
|
||||
"urlsToFetch": []any{resourceFetch},
|
||||
"data": []any{
|
||||
header,
|
||||
map[string]any{
|
||||
"type": "antdTabs",
|
||||
"data": map[string]any{
|
||||
"id": lowerKind + "-tabs",
|
||||
"defaultActiveKey": "details",
|
||||
"items": tabs,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
obj := &dashv1alpha1.Factory{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "dashboard.cozystack.io", Version: "v1alpha1", Kind: "Factory"})
|
||||
obj.SetName(factoryName)
|
||||
|
||||
_, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj.Spec = dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ---------------- Tabs builders ----------------
|
||||
|
||||
func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[string]any {
|
||||
paramsBlocks := buildOpenAPIParamsBlocks(schemaJSON, keysOrder)
|
||||
paramsList := map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": "params-list",
|
||||
"vertical": true,
|
||||
"gap": float64(24),
|
||||
},
|
||||
"children": paramsBlocks,
|
||||
}
|
||||
|
||||
leftColStack := []any{
|
||||
antdText("details-title", true, kind, map[string]any{
|
||||
"fontSize": float64(20),
|
||||
"marginBottom": float64(12),
|
||||
}),
|
||||
antdFlexVertical("meta-name-block", 4, []any{
|
||||
antdText("meta-name-label", true, "Name", nil),
|
||||
parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("meta-namespace-block", 8, []any{
|
||||
antdText("meta-namespace-label", true, "Namespace", nil),
|
||||
map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": "namespace-row",
|
||||
"align": "center",
|
||||
"gap": float64(6),
|
||||
},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "ns-badge",
|
||||
"text": "NS",
|
||||
"style": map[string]any{
|
||||
"backgroundColor": "#a25792ff",
|
||||
"borderRadius": "20px",
|
||||
"color": "#fff",
|
||||
"display": "inline-block",
|
||||
"fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif",
|
||||
"fontSize": float64(15),
|
||||
"fontWeight": float64(400),
|
||||
"lineHeight": "24px",
|
||||
"minWidth": float64(24),
|
||||
"padding": "0 9px",
|
||||
"textAlign": "center",
|
||||
"whiteSpace": "nowrap",
|
||||
},
|
||||
},
|
||||
},
|
||||
antdLink("namespace-link",
|
||||
"{reqsJsonPath[0]['.metadata.namespace']['-']}",
|
||||
"/openapi-ui/{2}/factory/namespace-details/{reqsJsonPath[0]['.metadata.namespace']['-']}",
|
||||
),
|
||||
},
|
||||
},
|
||||
}),
|
||||
antdFlexVertical("meta-created-block", 4, []any{
|
||||
antdText("time-label", true, "Created", nil),
|
||||
antdFlex("time-block", 6, []any{
|
||||
antdText("time-icon", false, "🌐", nil),
|
||||
parsedTextWithFormatter("time-value", "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", "timestamp"),
|
||||
}),
|
||||
}),
|
||||
antdFlexVertical("meta-version-block", 4, []any{
|
||||
antdText("version-label", true, "Version", nil),
|
||||
parsedText("version-value", "{reqsJsonPath[0]['.status.version']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("meta-released-block", 4, []any{
|
||||
antdText("released-label", true, "Released", nil),
|
||||
parsedText("released-value", "{reqsJsonPath[0]['.status.conditions[?(@.type==\"Released\")].status']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("meta-ready-block", 4, []any{
|
||||
antdText("ready-label", true, "Ready", nil),
|
||||
parsedText("ready-value", "{reqsJsonPath[0]['.status.conditions[?(@.type==\"Ready\")].status']['-']}", nil),
|
||||
}),
|
||||
}
|
||||
|
||||
rightColStack := []any{
|
||||
antdText("params-title", true, "Parameters", map[string]any{
|
||||
"fontSize": float64(20),
|
||||
"marginBottom": float64(12),
|
||||
}),
|
||||
paramsList,
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"key": "details",
|
||||
"label": "Details",
|
||||
"children": []any{
|
||||
contentCard("details-card", map[string]any{"marginBottom": float64(24)}, []any{
|
||||
map[string]any{
|
||||
"type": "antdRow",
|
||||
"data": map[string]any{
|
||||
"id": "details-grid",
|
||||
"gutter": []any{float64(48), float64(12)},
|
||||
},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdCol",
|
||||
"data": map[string]any{"id": "col-left", "span": float64(12)},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{"id": "col-left-stack", "vertical": true, "gap": float64(24)},
|
||||
"children": leftColStack,
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "antdCol",
|
||||
"data": map[string]any{"id": "col-right", "span": float64(12)},
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{"id": "col-right-stack", "vertical": true, "gap": float64(24)},
|
||||
"children": rightColStack,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
spacer("conditions-top-spacer", float64(16)),
|
||||
antdText("conditions-title", true, "Conditions", map[string]any{"fontSize": float64(20)}),
|
||||
spacer("conditions-spacer", float64(8)),
|
||||
map[string]any{
|
||||
"type": "EnrichedTable",
|
||||
"data": map[string]any{
|
||||
"id": "conditions-table",
|
||||
"fetchUrl": endpoint,
|
||||
"clusterNamePartOfUrl": "{2}",
|
||||
"customizationId": "factory-status-conditions",
|
||||
"baseprefix": "/openapi-ui",
|
||||
"withoutControls": true,
|
||||
"pathToItems": []any{"status", "conditions"},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func workloadsTab(kind string) map[string]any {
|
||||
return map[string]any{
|
||||
"key": "workloads",
|
||||
"label": "Workloads",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "EnrichedTable",
|
||||
"data": map[string]any{
|
||||
"id": "workloads-table",
|
||||
"fetchUrl": "/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloadmonitors",
|
||||
"clusterNamePartOfUrl": "{2}",
|
||||
"baseprefix": "/openapi-ui",
|
||||
"customizationId": "factory-details-v1alpha1.cozystack.io.workloadmonitors",
|
||||
"pathToItems": []any{"items"},
|
||||
"labelsSelector": map[string]any{
|
||||
"apps.cozystack.io/application.group": "apps.cozystack.io",
|
||||
"apps.cozystack.io/application.kind": kind,
|
||||
"apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func servicesTab(kind string) map[string]any {
|
||||
return map[string]any{
|
||||
"key": "services",
|
||||
"label": "Services",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "EnrichedTable",
|
||||
"data": map[string]any{
|
||||
"id": "services-table",
|
||||
"fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services",
|
||||
"clusterNamePartOfUrl": "{2}",
|
||||
"baseprefix": "/openapi-ui",
|
||||
"customizationId": "factory-details-v1.services",
|
||||
"pathToItems": []any{"items"},
|
||||
"labelsSelector": map[string]any{
|
||||
"apps.cozystack.io/application.group": "apps.cozystack.io",
|
||||
"apps.cozystack.io/application.kind": kind,
|
||||
"apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ingressesTab(kind string) map[string]any {
|
||||
return map[string]any{
|
||||
"key": "ingresses",
|
||||
"label": "Ingresses",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "EnrichedTable",
|
||||
"data": map[string]any{
|
||||
"id": "ingresses-table",
|
||||
"fetchUrl": "/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses",
|
||||
"clusterNamePartOfUrl": "{2}",
|
||||
"baseprefix": "/openapi-ui",
|
||||
"customizationId": "factory-details-networking.k8s.io.v1.ingresses",
|
||||
"pathToItems": []any{"items"},
|
||||
"labelsSelector": map[string]any{
|
||||
"apps.cozystack.io/application.group": "apps.cozystack.io",
|
||||
"apps.cozystack.io/application.kind": kind,
|
||||
"apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func secretsTab(kind string) map[string]any {
|
||||
return map[string]any{
|
||||
"key": "secrets",
|
||||
"label": "Secrets",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "EnrichedTable",
|
||||
"data": map[string]any{
|
||||
"id": "secrets-table",
|
||||
"fetchUrl": "/api/clusters/{2}/k8s/apis/core.cozystack.io/v1alpha1/namespaces/{3}/tenantsecretstables",
|
||||
"clusterNamePartOfUrl": "{2}",
|
||||
"baseprefix": "/openapi-ui",
|
||||
"customizationId": "factory-details-v1alpha1.core.cozystack.io.tenantsecretstables",
|
||||
"pathToItems": []any{"items"},
|
||||
"labelsSelector": map[string]any{
|
||||
"apps.cozystack.io/application.group": "apps.cozystack.io",
|
||||
"apps.cozystack.io/application.kind": kind,
|
||||
"apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func yamlTab(plural string) map[string]any {
|
||||
return map[string]any{
|
||||
"key": "yaml",
|
||||
"label": "YAML",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"type": "YamlEditorSingleton",
|
||||
"data": map[string]any{
|
||||
"id": "yaml-editor",
|
||||
"cluster": "{2}",
|
||||
"isNameSpaced": true,
|
||||
"type": "builtin",
|
||||
"typeName": plural,
|
||||
"prefillValuesRequestIndex": float64(0),
|
||||
"substractHeight": float64(400),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- UI helpers (use float64 for numeric fields) ----------------
|
||||
|
||||
func contentCard(id string, style map[string]any, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "ContentCard",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"style": style,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdText(id string, strong bool, text string, style map[string]any) map[string]any {
|
||||
data := map[string]any{
|
||||
"id": id,
|
||||
"text": text,
|
||||
"strong": strong,
|
||||
}
|
||||
if style != nil {
|
||||
data["style"] = style
|
||||
}
|
||||
return map[string]any{"type": "antdText", "data": data}
|
||||
}
|
||||
|
||||
func parsedText(id, text string, style map[string]any) map[string]any {
|
||||
data := map[string]any{
|
||||
"id": id,
|
||||
"text": text,
|
||||
}
|
||||
if style != nil {
|
||||
data["style"] = style
|
||||
}
|
||||
return map[string]any{"type": "parsedText", "data": data}
|
||||
}
|
||||
|
||||
func parsedTextWithFormatter(id, text, formatter string) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"text": text,
|
||||
"formatter": formatter,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func spacer(id string, space float64) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "Spacer",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"$space": space,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func antdFlex(id string, gap float64, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"align": "center",
|
||||
"gap": gap,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdFlexVertical(id string, gap float64, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdFlex",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"vertical": true,
|
||||
"gap": gap,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdRow(id string, gutter []any, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdRow",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"gutter": gutter,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdCol(id string, span float64, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdCol",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"span": span,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdColWithStyle(id string, style map[string]any, children []any) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdCol",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"style": style,
|
||||
},
|
||||
"children": children,
|
||||
}
|
||||
}
|
||||
|
||||
func antdLink(id, text, href string) map[string]any {
|
||||
return map[string]any{
|
||||
"type": "antdLink",
|
||||
"data": map[string]any{
|
||||
"id": id,
|
||||
"text": text,
|
||||
"href": href,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- OpenAPI → Right column ----------------
|
||||
|
||||
func buildOpenAPIParamsBlocks(schemaJSON string, keysOrder [][]string) []any {
|
||||
var blocks []any
|
||||
fields := collectOpenAPILeafFields(schemaJSON, 2, 20)
|
||||
|
||||
// Sort fields according to keysOrder if provided
|
||||
if len(keysOrder) > 0 {
|
||||
fields = sortFieldsByKeysOrder(fields, keysOrder)
|
||||
}
|
||||
|
||||
for idx, f := range fields {
|
||||
id := fmt.Sprintf("param-%d", idx)
|
||||
blocks = append(blocks,
|
||||
antdFlexVertical(id, 4, []any{
|
||||
antdText(id+"-label", true, f.Label, nil),
|
||||
parsedText(id+"-value", fmt.Sprintf("{reqsJsonPath[0]['.spec.%s']['-']}", f.JSONPathSpec), nil),
|
||||
}),
|
||||
)
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
blocks = append(blocks,
|
||||
antdText("params-empty", false, "No scalar parameters detected in schema (see YAML tab for full spec).", map[string]any{"opacity": float64(0.7)}),
|
||||
)
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
// sortFieldsByKeysOrder sorts fields according to the provided keysOrder
|
||||
func sortFieldsByKeysOrder(fields []fieldInfo, keysOrder [][]string) []fieldInfo {
|
||||
// Create a map for quick lookup of field positions
|
||||
orderMap := make(map[string]int)
|
||||
for i, path := range keysOrder {
|
||||
// Convert path to dot notation (e.g., ["spec", "systemDisk", "image"] -> "systemDisk.image")
|
||||
if len(path) > 1 && path[0] == "spec" {
|
||||
dotPath := strings.Join(path[1:], ".")
|
||||
orderMap[dotPath] = i
|
||||
}
|
||||
}
|
||||
|
||||
// Sort fields based on their position in keysOrder
|
||||
sort.Slice(fields, func(i, j int) bool {
|
||||
posI, existsI := orderMap[fields[i].JSONPathSpec]
|
||||
posJ, existsJ := orderMap[fields[j].JSONPathSpec]
|
||||
|
||||
// If both exist in orderMap, sort by position
|
||||
if existsI && existsJ {
|
||||
return posI < posJ
|
||||
}
|
||||
// If only one exists, prioritize the one that exists
|
||||
if existsI {
|
||||
return true
|
||||
}
|
||||
if existsJ {
|
||||
return false
|
||||
}
|
||||
// If neither exists, maintain original order (stable sort)
|
||||
return i < j
|
||||
})
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func collectOpenAPILeafFields(schemaJSON string, maxDepth, maxFields int) []fieldInfo {
|
||||
type node = map[string]any
|
||||
|
||||
if strings.TrimSpace(schemaJSON) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var root any
|
||||
if err := json.Unmarshal([]byte(schemaJSON), &root); err != nil {
|
||||
// invalid JSON — skip
|
||||
return nil
|
||||
}
|
||||
|
||||
props := map[string]any{}
|
||||
if m, ok := root.(node); ok {
|
||||
if p, ok := m["properties"].(node); ok {
|
||||
props = p
|
||||
}
|
||||
}
|
||||
if len(props) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out []fieldInfo
|
||||
var visit func(prefix []string, n node, depth int)
|
||||
|
||||
addField := func(path []string, schema node) {
|
||||
// Skip excluded paths (backup/bootstrap/password)
|
||||
if shouldExcludeParamPath(path) {
|
||||
return
|
||||
}
|
||||
// build label "Foo Bar / Baz"
|
||||
label := humanizePath(path)
|
||||
desc := getString(schema, "description")
|
||||
out = append(out, fieldInfo{
|
||||
JSONPathSpec: strings.Join(path, "."),
|
||||
Label: label,
|
||||
Description: desc,
|
||||
})
|
||||
}
|
||||
|
||||
visit = func(prefix []string, n node, depth int) {
|
||||
if len(out) >= maxFields {
|
||||
return
|
||||
}
|
||||
// Scalar?
|
||||
if isScalarType(n) || isIntOrString(n) || hasEnum(n) {
|
||||
addField(prefix, n)
|
||||
return
|
||||
}
|
||||
// Object with properties
|
||||
if props, ok := n["properties"].(node); ok {
|
||||
if depth >= maxDepth {
|
||||
// too deep — stop
|
||||
return
|
||||
}
|
||||
// deterministic ordering
|
||||
keys := make([]string, 0, len(props))
|
||||
for k := range props {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
child, _ := props[k].(node)
|
||||
visit(append(prefix, k), child, depth+1)
|
||||
if len(out) >= maxFields {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Arrays: try to render item if it’s scalar and depth limit allows
|
||||
if n["type"] == "array" {
|
||||
if items, ok := n["items"].(node); ok && (isScalarType(items) || isIntOrString(items) || hasEnum(items)) {
|
||||
addField(prefix, items)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Otherwise skip (unknown/complex)
|
||||
}
|
||||
|
||||
// top-level: iterate properties
|
||||
keys := make([]string, 0, len(props))
|
||||
for k := range props {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
if child, ok := props[k].(node); ok {
|
||||
visit([]string{k}, child, 1)
|
||||
if len(out) >= maxFields {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// --- helpers for schema inspection ---
|
||||
|
||||
func isScalarType(n map[string]any) bool {
|
||||
switch getString(n, "type") {
|
||||
case "string", "integer", "number", "boolean":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isIntOrString(n map[string]any) bool {
|
||||
// Kubernetes extension: x-kubernetes-int-or-string: true
|
||||
if v, ok := n["x-kubernetes-int-or-string"]; ok {
|
||||
if b, ok := v.(bool); ok && b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// anyOf: integer|string
|
||||
if anyOf, ok := n["anyOf"].([]any); ok {
|
||||
hasInt := false
|
||||
hasStr := false
|
||||
for _, it := range anyOf {
|
||||
if m, ok := it.(map[string]any); ok {
|
||||
switch getString(m, "type") {
|
||||
case "integer":
|
||||
hasInt = true
|
||||
case "string":
|
||||
hasStr = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasInt && hasStr
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasEnum(n map[string]any) bool {
|
||||
_, ok := n["enum"]
|
||||
return ok
|
||||
}
|
||||
|
||||
func getString(n map[string]any, key string) string {
|
||||
if v, ok := n[key]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// shouldExcludeParamPath returns true if any part of the path contains
|
||||
// backup / bootstrap / password (case-insensitive)
|
||||
func shouldExcludeParamPath(parts []string) bool {
|
||||
for _, p := range parts {
|
||||
lp := strings.ToLower(p)
|
||||
if strings.Contains(lp, "backup") || strings.Contains(lp, "bootstrap") || strings.Contains(lp, "password") || strings.Contains(lp, "cloudInit") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func humanizePath(parts []string) string {
|
||||
// "systemDisk.image" -> "System Disk / Image"
|
||||
return strings.Join(parts, " / ")
|
||||
}
|
||||
|
||||
// ---------------- Feature flags ----------------
|
||||
|
||||
type factoryFlags struct {
|
||||
Workloads bool
|
||||
Ingresses bool
|
||||
Services bool
|
||||
Secrets bool
|
||||
}
|
||||
|
||||
// factoryFeatureFlags tries several conventional locations so you can evolve the API
|
||||
// without breaking the controller. Defaults are false (hidden).
|
||||
func factoryFeatureFlags(crd *cozyv1alpha1.CozystackResourceDefinition) factoryFlags {
|
||||
var f factoryFlags
|
||||
|
||||
f.Workloads = true
|
||||
f.Ingresses = true
|
||||
f.Services = true
|
||||
f.Secrets = true
|
||||
|
||||
return f
|
||||
}
|
||||
343
internal/controller/dashboard/manager.go
Normal file
343
internal/controller/dashboard/manager.go
Normal file
@@ -0,0 +1,343 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1"
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
// AddToScheme exposes dashboard types registration for controller setup.
|
||||
func AddToScheme(s *runtime.Scheme) error {
|
||||
return dashv1alpha1.AddToScheme(s)
|
||||
}
|
||||
|
||||
// Manager owns logic for creating/updating dashboard resources derived from CRDs.
|
||||
// It’s easy to extend: add new ensure* methods and wire them into EnsureForCRD.
|
||||
type Manager struct {
|
||||
client client.Client
|
||||
scheme *runtime.Scheme
|
||||
crdListFn func(context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error)
|
||||
}
|
||||
|
||||
// Option pattern so callers can inject a custom lister.
|
||||
type Option func(*Manager)
|
||||
|
||||
// WithCRDListFunc overrides how Manager lists all CozystackResourceDefinitions.
|
||||
func WithCRDListFunc(fn func(context.Context) ([]cozyv1alpha1.CozystackResourceDefinition, error)) Option {
|
||||
return func(m *Manager) { m.crdListFn = fn }
|
||||
}
|
||||
|
||||
// NewManager constructs a dashboard Manager.
|
||||
func NewManager(c client.Client, scheme *runtime.Scheme, opts ...Option) *Manager {
|
||||
m := &Manager{client: c, scheme: scheme}
|
||||
for _, o := range opts {
|
||||
o(m)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// EnsureForCRD is the single entry-point used by the controller.
|
||||
// Add more ensure* calls here as you implement support for other resources:
|
||||
//
|
||||
// - ensureBreadcrumb (implemented)
|
||||
// - ensureCustomColumnsOverride (implemented)
|
||||
// - ensureCustomFormsOverride (implemented)
|
||||
// - ensureCustomFormsPrefill (implemented)
|
||||
// - ensureFactory
|
||||
// - ensureMarketplacePanel (implemented)
|
||||
// - ensureSidebar (implemented)
|
||||
// - ensureTableUriMapping (implemented)
|
||||
func (m *Manager) EnsureForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
||||
// MarketplacePanel
|
||||
if res, err := m.ensureMarketplacePanel(ctx, crd); err != nil || res.Requeue || res.RequeueAfter > 0 {
|
||||
return res, err
|
||||
}
|
||||
// CustomFormsPrefill
|
||||
if res, err := m.ensureCustomFormsPrefill(ctx, crd); err != nil || res.Requeue || res.RequeueAfter > 0 {
|
||||
return res, err
|
||||
}
|
||||
// CustomColumnsOverride
|
||||
if _, err := m.ensureCustomColumnsOverride(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.ensureTableUriMapping(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.ensureBreadcrumb(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.ensureCustomFormsOverride(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.ensureSidebar(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.ensureFactory(ctx, crd); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
// ----------------------- MarketplacePanel -----------------------
|
||||
|
||||
func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
mp := &dashv1alpha1.MarketplacePanel{}
|
||||
mp.Name = crd.Name // cluster-scoped resource, name mirrors CRD name
|
||||
|
||||
// If dashboard is not set, delete the panel if it exists.
|
||||
if crd.Spec.Dashboard == nil {
|
||||
err := m.client.Get(ctx, client.ObjectKey{Name: mp.Name}, mp)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.client.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
logger.Info("Deleted MarketplacePanel because dashboard is not set", "name", mp.Name)
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
// Skip resources with non-empty spec.dashboard.name
|
||||
if strings.TrimSpace(crd.Spec.Dashboard.Name) != "" {
|
||||
err := m.client.Get(ctx, client.ObjectKey{Name: mp.Name}, mp)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := m.client.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
logger.Info("Deleted MarketplacePanel because spec.dashboard.name is set", "name", mp.Name)
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
// Build desired spec from CRD fields
|
||||
d := crd.Spec.Dashboard
|
||||
app := crd.Spec.Application
|
||||
|
||||
displayName := d.Singular
|
||||
if displayName == "" {
|
||||
displayName = app.Kind
|
||||
}
|
||||
|
||||
tags := make([]any, len(d.Tags))
|
||||
for i, t := range d.Tags {
|
||||
tags[i] = t
|
||||
}
|
||||
|
||||
specMap := map[string]any{
|
||||
"description": d.Description,
|
||||
"name": displayName,
|
||||
"type": "nonCrd",
|
||||
"apiGroup": "apps.cozystack.io",
|
||||
"apiVersion": "v1alpha1",
|
||||
"typeName": app.Plural, // e.g., "buckets"
|
||||
"disabled": false,
|
||||
"hidden": false,
|
||||
"tags": tags,
|
||||
"icon": d.Icon,
|
||||
}
|
||||
|
||||
specBytes, err := json.Marshal(specMap)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
mutate := func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, mp, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
// Inline JSON payload (the ArbitrarySpec type inlines apiextv1.JSON)
|
||||
mp.Spec = dashv1alpha1.ArbitrarySpec{
|
||||
JSON: apiextv1.JSON{Raw: specBytes},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
op, err := controllerutil.CreateOrUpdate(ctx, m.client, mp, mutate)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
switch op {
|
||||
case controllerutil.OperationResultCreated:
|
||||
logger.Info("Created MarketplacePanel", "name", mp.Name)
|
||||
case controllerutil.OperationResultUpdated:
|
||||
logger.Info("Updated MarketplacePanel", "name", mp.Name)
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
// ----------------------- Helpers (OpenAPI → values) -----------------------
|
||||
|
||||
// defaultOrZero returns the schema default if present; otherwise a reasonable zero value.
|
||||
func defaultOrZero(sub map[string]interface{}) interface{} {
|
||||
if v, ok := sub["default"]; ok {
|
||||
return v
|
||||
}
|
||||
typ, _ := sub["type"].(string)
|
||||
switch typ {
|
||||
case "string":
|
||||
return ""
|
||||
case "boolean":
|
||||
return false
|
||||
case "array":
|
||||
return []interface{}{}
|
||||
case "integer", "number":
|
||||
return 0
|
||||
case "object":
|
||||
return map[string]interface{}{}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// toIfaceSlice converts []string -> []interface{}.
|
||||
func toIfaceSlice(ss []string) []interface{} {
|
||||
out := make([]interface{}, len(ss))
|
||||
for i, s := range ss {
|
||||
out[i] = s
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// buildPrefillValues converts an OpenAPI schema (JSON string) into a []interface{} "values" list
|
||||
// suitable for CustomFormsPrefill.spec.values.
|
||||
// Rules:
|
||||
// - For top-level primitive/array fields: emit an entry, using default if present, otherwise zero.
|
||||
// - For top-level objects: recursively process nested objects and emit entries for all default values
|
||||
// found at any nesting level.
|
||||
func buildPrefillValues(openAPISchema string) ([]interface{}, error) {
|
||||
var root map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(openAPISchema), &root); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse openAPISchema: %w", err)
|
||||
}
|
||||
props, _ := root["properties"].(map[string]interface{})
|
||||
if props == nil {
|
||||
return []interface{}{}, nil
|
||||
}
|
||||
|
||||
var values []interface{}
|
||||
processSchemaProperties(props, []string{"spec"}, &values)
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// processSchemaProperties recursively processes OpenAPI schema properties and extracts default values
|
||||
func processSchemaProperties(props map[string]interface{}, path []string, values *[]interface{}) {
|
||||
for pname, raw := range props {
|
||||
sub, _ := raw.(map[string]interface{})
|
||||
if sub == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
typ, _ := sub["type"].(string)
|
||||
currentPath := append(path, pname)
|
||||
|
||||
switch typ {
|
||||
case "object":
|
||||
// Check if this object has a default value
|
||||
if objDefault, ok := sub["default"].(map[string]interface{}); ok {
|
||||
// Process the default object recursively
|
||||
processDefaultObject(objDefault, currentPath, values)
|
||||
}
|
||||
|
||||
// Also process child properties for their individual defaults
|
||||
if childProps, ok := sub["properties"].(map[string]interface{}); ok {
|
||||
processSchemaProperties(childProps, currentPath, values)
|
||||
}
|
||||
default:
|
||||
// For primitive types, use default if present, otherwise zero value
|
||||
val := defaultOrZero(sub)
|
||||
if val != nil {
|
||||
entry := map[string]interface{}{
|
||||
"path": toIfaceSlice(currentPath),
|
||||
"value": val,
|
||||
}
|
||||
*values = append(*values, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processDefaultObject recursively processes a default object and creates entries for all nested values
|
||||
func processDefaultObject(obj map[string]interface{}, path []string, values *[]interface{}) {
|
||||
for key, value := range obj {
|
||||
currentPath := append(path, key)
|
||||
|
||||
// If the value is a map, process it recursively
|
||||
if nestedObj, ok := value.(map[string]interface{}); ok {
|
||||
processDefaultObject(nestedObj, currentPath, values)
|
||||
} else {
|
||||
// For primitive values, create an entry
|
||||
entry := map[string]interface{}{
|
||||
"path": toIfaceSlice(currentPath),
|
||||
"value": value,
|
||||
}
|
||||
*values = append(*values, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeJSON makes maps/slices JSON-safe for k8s Unstructured:
|
||||
// - converts all int/int32/... to float64
|
||||
// - leaves strings, bools, nil as-is
|
||||
func normalizeJSON(v any) any {
|
||||
switch t := v.(type) {
|
||||
case map[string]any:
|
||||
out := make(map[string]any, len(t))
|
||||
for k, val := range t {
|
||||
out[k] = normalizeJSON(val)
|
||||
}
|
||||
return out
|
||||
case []any:
|
||||
out := make([]any, len(t))
|
||||
for i := range t {
|
||||
out[i] = normalizeJSON(t[i])
|
||||
}
|
||||
return out
|
||||
case int:
|
||||
return float64(t)
|
||||
case int8:
|
||||
return float64(t)
|
||||
case int16:
|
||||
return float64(t)
|
||||
case int32:
|
||||
return float64(t)
|
||||
case int64:
|
||||
return float64(t)
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return float64(reflect.ValueOf(t).Convert(reflect.TypeOf(uint64(0))).Uint())
|
||||
case float32:
|
||||
return float64(t)
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
var camelSplitter = regexp.MustCompile(`(?m)([A-Z]+[a-z0-9]*|[a-z0-9]+)`)
|
||||
|
||||
func splitCamel(s string) []string {
|
||||
return camelSplitter.FindAllString(s, -1)
|
||||
}
|
||||
310
internal/controller/dashboard/sidebar.go
Normal file
310
internal/controller/dashboard/sidebar.go
Normal file
@@ -0,0 +1,310 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1"
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
)
|
||||
|
||||
// ensureSidebar creates/updates multiple Sidebar resources that share the same menu:
|
||||
// - The "details" sidebar tied to the current kind (stock-project-factory-<kind>-details)
|
||||
// - The stock-instance sidebars: api-form, api-table, builtin-form, builtin-table
|
||||
// - The stock-project sidebars: api-form, api-table, builtin-form, builtin-table, crd-form, crd-table
|
||||
//
|
||||
// Menu rules:
|
||||
// - The first section is "Marketplace" with two hardcoded entries:
|
||||
// - Marketplace (/openapi-ui/{clusterName}/{namespace}/factory/marketplace)
|
||||
// - Tenant Info (/openapi-ui/{clusterName}/{namespace}/factory/info-details/info)
|
||||
// - All other sections are built from CRDs where spec.dashboard != nil.
|
||||
// - Categories are ordered strictly as:
|
||||
// Marketplace, IaaS, PaaS, NaaS, <others A→Z>, Resources, Administration
|
||||
// - Items within each category: sort by Weight (desc), then Label (A→Z).
|
||||
func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
||||
// Build the full menu once.
|
||||
|
||||
// 1) Fetch all CRDs
|
||||
var all []cozyv1alpha1.CozystackResourceDefinition
|
||||
if m.crdListFn != nil {
|
||||
s, err := m.crdListFn(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
all = s
|
||||
} else {
|
||||
var crdList cozyv1alpha1.CozystackResourceDefinitionList
|
||||
if err := m.client.List(ctx, &crdList, &client.ListOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
all = crdList.Items
|
||||
}
|
||||
|
||||
// 2) Build category -> []item map (only for CRDs with spec.dashboard != nil)
|
||||
type item struct {
|
||||
Key string
|
||||
Label string
|
||||
Link string
|
||||
Weight int
|
||||
}
|
||||
categories := map[string][]item{} // category label -> children
|
||||
keysAndTags := map[string]any{} // plural -> []string{ "<lower(kind)>-sidebar" }
|
||||
|
||||
for i := range all {
|
||||
def := &all[i]
|
||||
|
||||
// Include ONLY when spec.dashboard != nil
|
||||
if def.Spec.Dashboard == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip resources with non-empty spec.dashboard.name
|
||||
if strings.TrimSpace(def.Spec.Dashboard.Name) != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
g, v, kind := pickGVK(def)
|
||||
plural := pickPlural(kind, def)
|
||||
cat := safeCategory(def) // falls back to "Resources" if empty
|
||||
|
||||
// Label: prefer dashboard.Plural if provided
|
||||
label := titleFromKindPlural(kind, plural)
|
||||
if def.Spec.Dashboard.Plural != "" {
|
||||
label = def.Spec.Dashboard.Plural
|
||||
}
|
||||
|
||||
// Weight (default 0)
|
||||
weight := def.Spec.Dashboard.Weight
|
||||
|
||||
link := fmt.Sprintf("/openapi-ui/{clusterName}/{namespace}/api-table/%s/%s/%s", g, v, plural)
|
||||
|
||||
categories[cat] = append(categories[cat], item{
|
||||
Key: plural,
|
||||
Label: label,
|
||||
Link: link,
|
||||
Weight: weight,
|
||||
})
|
||||
|
||||
// keysAndTags: plural -> [ "<lower(kind)>-sidebar" ]
|
||||
keysAndTags[plural] = []any{fmt.Sprintf("%s-sidebar", strings.ToLower(kind))}
|
||||
}
|
||||
|
||||
// 3) Sort items within each category by Weight (desc), then Label (A→Z)
|
||||
for cat := range categories {
|
||||
sort.Slice(categories[cat], func(i, j int) bool {
|
||||
if categories[cat][i].Weight != categories[cat][j].Weight {
|
||||
return categories[cat][i].Weight < categories[cat][j].Weight // lower weight first
|
||||
}
|
||||
return strings.ToLower(categories[cat][i].Label) < strings.ToLower(categories[cat][j].Label)
|
||||
})
|
||||
}
|
||||
|
||||
// 4) Order categories strictly:
|
||||
// Marketplace (hardcoded), IaaS, PaaS, NaaS, <others A→Z>, Resources, Administration
|
||||
orderedCats := orderCategoryLabels(categories)
|
||||
|
||||
// 5) Build menuItems (hardcode "Marketplace"; then dynamic categories; then hardcode "Administration")
|
||||
menuItems := []any{
|
||||
map[string]any{
|
||||
"key": "marketplace",
|
||||
"label": "Marketplace",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"key": "marketplace",
|
||||
"label": "Marketplace",
|
||||
"link": "/openapi-ui/{clusterName}/{namespace}/factory/marketplace",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, cat := range orderedCats {
|
||||
// Skip "Marketplace" and "Administration" here since they're hardcoded
|
||||
if strings.EqualFold(cat, "Marketplace") || strings.EqualFold(cat, "Administration") {
|
||||
continue
|
||||
}
|
||||
children := []any{}
|
||||
for _, it := range categories[cat] {
|
||||
children = append(children, map[string]any{
|
||||
"key": it.Key,
|
||||
"label": it.Label,
|
||||
"link": it.Link,
|
||||
})
|
||||
}
|
||||
if len(children) > 0 {
|
||||
menuItems = append(menuItems, map[string]any{
|
||||
"key": slugify(cat),
|
||||
"label": cat,
|
||||
"children": children,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Add hardcoded Administration section
|
||||
menuItems = append(menuItems, map[string]any{
|
||||
"key": "administration",
|
||||
"label": "Administration",
|
||||
"children": []any{
|
||||
map[string]any{
|
||||
"key": "info",
|
||||
"label": "Info",
|
||||
"link": "/openapi-ui/{clusterName}/{namespace}/factory/info-details/info",
|
||||
},
|
||||
map[string]any{
|
||||
"key": "modules",
|
||||
"label": "Modules",
|
||||
"link": "/openapi-ui/{clusterName}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules",
|
||||
},
|
||||
map[string]any{
|
||||
"key": "tenants",
|
||||
"label": "Tenants",
|
||||
"link": "/openapi-ui/{clusterName}/{namespace}/api-table/apps.cozystack.io/v1alpha1/tenants",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// 6) Prepare the list of Sidebar IDs to upsert with the SAME content
|
||||
_, _, thisKind := pickGVK(crd)
|
||||
lowerThisKind := strings.ToLower(thisKind)
|
||||
detailsID := fmt.Sprintf("stock-project-factory-%s-details", lowerThisKind)
|
||||
|
||||
targetIDs := []string{
|
||||
// original details sidebar
|
||||
detailsID,
|
||||
|
||||
// stock-instance sidebars
|
||||
"stock-instance-api-form",
|
||||
"stock-instance-api-table",
|
||||
"stock-instance-builtin-form",
|
||||
"stock-instance-builtin-table",
|
||||
|
||||
// stock-project sidebars
|
||||
"stock-project-factory-marketplace",
|
||||
"stock-project-factory-workloadmonitor-details",
|
||||
"stock-project-api-form",
|
||||
"stock-project-api-table",
|
||||
"stock-project-builtin-form",
|
||||
"stock-project-builtin-table",
|
||||
"stock-project-crd-form",
|
||||
"stock-project-crd-table",
|
||||
}
|
||||
|
||||
// 7) Upsert all target sidebars with identical menuItems and keysAndTags
|
||||
return m.upsertMultipleSidebars(ctx, crd, targetIDs, keysAndTags, menuItems)
|
||||
}
|
||||
|
||||
// upsertMultipleSidebars creates/updates several Sidebar resources with the same menu spec.
|
||||
func (m *Manager) upsertMultipleSidebars(
|
||||
ctx context.Context,
|
||||
crd *cozyv1alpha1.CozystackResourceDefinition,
|
||||
ids []string,
|
||||
keysAndTags map[string]any,
|
||||
menuItems []any,
|
||||
) error {
|
||||
for _, id := range ids {
|
||||
spec := map[string]any{
|
||||
"id": id,
|
||||
"keysAndTags": keysAndTags,
|
||||
"menuItems": menuItems,
|
||||
}
|
||||
|
||||
obj := &dashv1alpha1.Sidebar{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "dashboard.cozystack.io",
|
||||
Version: "v1alpha1",
|
||||
Kind: "Sidebar",
|
||||
})
|
||||
obj.SetName(id)
|
||||
|
||||
if _, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj.Spec = dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// orderCategoryLabels returns category labels ordered strictly as:
|
||||
//
|
||||
// Marketplace, IaaS, PaaS, NaaS, <others A→Z>, Resources, Administration.
|
||||
//
|
||||
// It only returns labels that exist in `cats` (except "Marketplace" which is hardcoded by caller).
|
||||
func orderCategoryLabels[T any](cats map[string][]T) []string {
|
||||
if len(cats) == 0 {
|
||||
return []string{"Marketplace", "IaaS", "PaaS", "NaaS", "Resources", "Administration"}
|
||||
}
|
||||
|
||||
head := []string{"Marketplace", "IaaS", "PaaS", "NaaS"}
|
||||
tail := []string{"Resources", "Administration"}
|
||||
|
||||
present := make(map[string]struct{}, len(cats))
|
||||
for k := range cats {
|
||||
present[k] = struct{}{}
|
||||
}
|
||||
|
||||
var result []string
|
||||
|
||||
// Add head anchors (keep "Marketplace" in the order signature for the caller)
|
||||
for _, h := range head {
|
||||
result = append(result, h)
|
||||
delete(present, h)
|
||||
}
|
||||
|
||||
// Collect "others": exclude tail
|
||||
var others []string
|
||||
for k := range present {
|
||||
if k == "Resources" || k == "Administration" {
|
||||
continue
|
||||
}
|
||||
others = append(others, k)
|
||||
}
|
||||
sort.Slice(others, func(i, j int) bool { return strings.ToLower(others[i]) < strings.ToLower(others[j]) })
|
||||
|
||||
// Append others, then tail (always in fixed order)
|
||||
result = append(result, others...)
|
||||
result = append(result, tail...)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// safeCategory returns spec.dashboard.category or "Resources" if not set.
|
||||
func safeCategory(def *cozyv1alpha1.CozystackResourceDefinition) string {
|
||||
if def == nil || def.Spec.Dashboard == nil {
|
||||
return "Resources"
|
||||
}
|
||||
if def.Spec.Dashboard.Category != "" {
|
||||
return def.Spec.Dashboard.Category
|
||||
}
|
||||
return "Resources"
|
||||
}
|
||||
|
||||
// slugify converts a category label to a key-friendly identifier.
|
||||
// "User Management" -> "usermanagement", "PaaS" -> "paas".
|
||||
func slugify(s string) string {
|
||||
s = strings.TrimSpace(strings.ToLower(s))
|
||||
out := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') {
|
||||
out = append(out, c)
|
||||
}
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
266
internal/controller/dashboard/webextras.go
Normal file
266
internal/controller/dashboard/webextras.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1"
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
// Ensure the three additional dashboard/frontend resources exist:
|
||||
// - TableUriMapping (dashboard.cozystack.io/v1alpha1)
|
||||
// - Breadcrumb (dashboard.cozystack.io/v1alpha1)
|
||||
// - CustomFormsOverride (dashboard.cozystack.io/v1alpha1)
|
||||
//
|
||||
// Call these from Manager.EnsureForCRD() after ensureCustomColumnsOverride.
|
||||
|
||||
// --------------------------- TableUriMapping -----------------------------
|
||||
|
||||
func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
||||
// Links are fully managed by the CustomColumnsOverride.
|
||||
return nil
|
||||
}
|
||||
|
||||
// ------------------------------- Breadcrumb -----------------------------
|
||||
|
||||
func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
||||
_, _, kind := pickGVK(crd)
|
||||
|
||||
lowerKind := strings.ToLower(kind)
|
||||
detailID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind)
|
||||
|
||||
obj := &dashv1alpha1.Breadcrumb{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "dashboard.cozystack.io",
|
||||
Version: "v1alpha1",
|
||||
Kind: "Breadcrumb",
|
||||
})
|
||||
obj.SetName(detailID)
|
||||
|
||||
plural := pickPlural(kind, crd)
|
||||
|
||||
// Prefer dashboard.Plural for UI label if provided
|
||||
labelPlural := titleFromKindPlural(kind, plural)
|
||||
if crd != nil && crd.Spec.Dashboard != nil && crd.Spec.Dashboard.Plural != "" {
|
||||
labelPlural = crd.Spec.Dashboard.Plural
|
||||
}
|
||||
|
||||
key := plural // e.g., "virtualmachines"
|
||||
label := labelPlural
|
||||
link := fmt.Sprintf("/openapi-ui/{clusterName}/{namespace}/api-table/apps.cozystack.io/v1alpha1/%s", plural)
|
||||
// If Name is set, change the first breadcrumb item to "Tenant Modules"
|
||||
// TODO add parameter to this
|
||||
if crd.Spec.Dashboard.Name != "" {
|
||||
key = "tenantmodules"
|
||||
label = "Tenant Modules"
|
||||
link = "/openapi-ui/{clusterName}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules"
|
||||
}
|
||||
|
||||
items := []any{
|
||||
map[string]any{
|
||||
"key": key,
|
||||
"label": label,
|
||||
"link": link,
|
||||
},
|
||||
map[string]any{
|
||||
"key": strings.ToLower(kind), // "etcd"
|
||||
"label": "{6}", // literal, as in your example
|
||||
},
|
||||
}
|
||||
|
||||
spec := map[string]any{
|
||||
"id": detailID,
|
||||
"breadcrumbItems": items,
|
||||
}
|
||||
|
||||
_, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj.Spec = dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// --------------------------- CustomFormsOverride ------------------------
|
||||
|
||||
func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error {
|
||||
g, v, kind := pickGVK(crd)
|
||||
plural := pickPlural(kind, crd)
|
||||
|
||||
name := fmt.Sprintf("%s.%s.%s", g, v, plural)
|
||||
customizationID := fmt.Sprintf("default-/%s/%s/%s", g, v, plural)
|
||||
|
||||
obj := &dashv1alpha1.CustomFormsOverride{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "dashboard.cozystack.io",
|
||||
Version: "v1alpha1",
|
||||
Kind: "CustomFormsOverride",
|
||||
})
|
||||
obj.SetName(name)
|
||||
|
||||
// Replicates your Helm includes (system metadata + api + status).
|
||||
hidden := []any{}
|
||||
hidden = append(hidden, hiddenMetadataSystem()...)
|
||||
hidden = append(hidden, hiddenMetadataAPI()...)
|
||||
hidden = append(hidden, hiddenStatus()...)
|
||||
|
||||
// If Name is set, hide metadata
|
||||
if crd.Spec.Dashboard != nil && strings.TrimSpace(crd.Spec.Dashboard.Name) != "" {
|
||||
hidden = append([]interface{}{
|
||||
[]any{"metadata"},
|
||||
}, hidden...)
|
||||
}
|
||||
|
||||
sort := make([]any, len(crd.Spec.Dashboard.KeysOrder))
|
||||
for i, v := range crd.Spec.Dashboard.KeysOrder {
|
||||
sort[i] = v
|
||||
}
|
||||
|
||||
spec := map[string]any{
|
||||
"customizationId": customizationID,
|
||||
"hidden": hidden,
|
||||
"sort": sort,
|
||||
"schema": map[string]any{}, // {}
|
||||
"strategy": "merge",
|
||||
}
|
||||
|
||||
_, err := controllerutil.CreateOrUpdate(ctx, m.client, obj, func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, obj, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj.Spec = dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ----------------------- CustomFormsPrefill -----------------------
|
||||
|
||||
func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
app := crd.Spec.Application
|
||||
group := "apps.cozystack.io"
|
||||
version := "v1alpha1"
|
||||
|
||||
name := fmt.Sprintf("%s.%s.%s", group, version, app.Plural)
|
||||
customizationID := fmt.Sprintf("default-/%s/%s/%s", group, version, app.Plural)
|
||||
|
||||
values, err := buildPrefillValues(app.OpenAPISchema)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// If Name is set, prefill metadata.name
|
||||
if crd.Spec.Dashboard != nil && strings.TrimSpace(crd.Spec.Dashboard.Name) != "" {
|
||||
values = append([]interface{}{
|
||||
map[string]interface{}{
|
||||
"path": toIfaceSlice([]string{"metadata", "name"}),
|
||||
"value": crd.Spec.Dashboard.Name,
|
||||
},
|
||||
}, values...)
|
||||
}
|
||||
|
||||
cfp := &dashv1alpha1.CustomFormsPrefill{}
|
||||
cfp.Name = name // cluster-scoped
|
||||
|
||||
specMap := map[string]any{
|
||||
"customizationId": customizationID,
|
||||
"values": values,
|
||||
}
|
||||
specBytes, err := json.Marshal(specMap)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
mutate := func() error {
|
||||
if err := controllerutil.SetOwnerReference(crd, cfp, m.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
cfp.Spec = dashv1alpha1.ArbitrarySpec{
|
||||
JSON: apiextv1.JSON{Raw: specBytes},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
op, err := controllerutil.CreateOrUpdate(ctx, m.client, cfp, mutate)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
switch op {
|
||||
case controllerutil.OperationResultCreated:
|
||||
logger.Info("Created CustomFormsPrefill", "name", cfp.Name)
|
||||
case controllerutil.OperationResultUpdated:
|
||||
logger.Info("Updated CustomFormsPrefill", "name", cfp.Name)
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
// ------------------------------ Helpers ---------------------------------
|
||||
|
||||
// titleFromKindPlural returns a presentable plural label, e.g.:
|
||||
// kind="VirtualMachine", plural="virtualmachines" => "VirtualMachines"
|
||||
func titleFromKindPlural(kind, plural string) string {
|
||||
label := kind
|
||||
if !strings.HasSuffix(strings.ToLower(plural), "s") || !strings.HasSuffix(strings.ToLower(plural), "S") {
|
||||
label += "s"
|
||||
} else {
|
||||
label += "s"
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
// The hidden lists below mirror the Helm templates you shared.
|
||||
// Each entry is a path as nested string array, e.g. ["metadata","creationTimestamp"].
|
||||
|
||||
func hiddenMetadataSystem() []any {
|
||||
return []any{
|
||||
[]any{"metadata", "annotations"},
|
||||
[]any{"metadata", "labels"},
|
||||
[]any{"metadata", "namespace"},
|
||||
[]any{"metadata", "creationTimestamp"},
|
||||
[]any{"metadata", "deletionGracePeriodSeconds"},
|
||||
[]any{"metadata", "deletionTimestamp"},
|
||||
[]any{"metadata", "finalizers"},
|
||||
[]any{"metadata", "generateName"},
|
||||
[]any{"metadata", "generation"},
|
||||
[]any{"metadata", "managedFields"},
|
||||
[]any{"metadata", "ownerReferences"},
|
||||
[]any{"metadata", "resourceVersion"},
|
||||
[]any{"metadata", "selfLink"},
|
||||
[]any{"metadata", "uid"},
|
||||
}
|
||||
}
|
||||
|
||||
func hiddenMetadataAPI() []any {
|
||||
return []any{
|
||||
[]any{"kind"},
|
||||
[]any{"apiVersion"},
|
||||
[]any{"appVersion"},
|
||||
}
|
||||
}
|
||||
|
||||
func hiddenStatus() []any {
|
||||
return []any{
|
||||
[]any{"status"},
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,10 @@ type runtimeConfig struct {
|
||||
func (l *LineageControllerWebhook) initConfig() {
|
||||
l.initOnce.Do(func() {
|
||||
if l.config.Load() == nil {
|
||||
l.config.Store(&runtimeConfig{chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition)})
|
||||
l.config.Store(&runtimeConfig{
|
||||
chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition),
|
||||
appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,11 +5,10 @@ import (
|
||||
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=list;watch
|
||||
// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=list;watch;get
|
||||
|
||||
func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
@@ -20,7 +19,7 @@ func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager
|
||||
func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
l := log.FromContext(ctx)
|
||||
crds := &cozyv1alpha1.CozystackResourceDefinitionList{}
|
||||
if err := c.List(ctx, crds, &client.ListOptions{Namespace: "cozy-system"}); err != nil {
|
||||
if err := c.List(ctx, crds); err != nil {
|
||||
l.Error(err, "failed reading CozystackResourceDefinitions")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
yq -o json -i '.properties = {}' values.schema.json
|
||||
yq -o json -i '.properties = {}' values.schema.json
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -5,6 +5,7 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
image:
|
||||
docker buildx build images/clickhouse-backup \
|
||||
|
||||
@@ -2,6 +2,7 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
update:
|
||||
tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/FerretDB/FerretDB | awk -F'[/^]' '{sub("^v", "", $$3)} END{print $$3}') && \
|
||||
|
||||
@@ -18,6 +18,7 @@ image-nginx:
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
update:
|
||||
tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/chrislim2888/IP2Location-C-Library | awk -F'[/^]' 'END{print $$3}') && \
|
||||
|
||||
@@ -3,3 +3,4 @@ PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"]
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -7,6 +7,7 @@ include ../../../scripts/package.mk
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
yq -o=json -i '.properties.version.enum = (load("files/versions.yaml") | keys)' values.schema.json
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-csi-driver image-cluster-autoscaler
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
image:
|
||||
docker buildx build images/mariadb-backup \
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -20,6 +20,8 @@ apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-credentials
|
||||
labels:
|
||||
internal.cozystack.io/tenantsecret: "true"
|
||||
stringData:
|
||||
{{- range $user, $u := .Values.users }}
|
||||
{{ quote $user }}: {{ quote (index $passwords $user) }}
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -29,6 +29,13 @@ rules:
|
||||
resources:
|
||||
- workloadmonitors
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups:
|
||||
- core.cozystack.io
|
||||
resources:
|
||||
- tenantmodules
|
||||
- tenantsecrets
|
||||
- tenantsecretstables
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
@@ -178,6 +185,13 @@ rules:
|
||||
resources:
|
||||
- workloadmonitors
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups:
|
||||
- core.cozystack.io
|
||||
resources:
|
||||
- tenantmodules
|
||||
- tenantsecrets
|
||||
- tenantsecretstables
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -269,6 +283,13 @@ rules:
|
||||
resources:
|
||||
- workloadmonitors
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups:
|
||||
- core.cozystack.io
|
||||
resources:
|
||||
- tenantmodules
|
||||
- tenantsecrets
|
||||
- tenantsecretstables
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -336,6 +357,13 @@ rules:
|
||||
resources:
|
||||
- workloadmonitors
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups:
|
||||
- core.cozystack.io
|
||||
resources:
|
||||
- tenantmodules
|
||||
- tenantsecrets
|
||||
- tenantsecretstables
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -7,3 +7,4 @@ generate:
|
||||
# && yq -i -o json ".properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
|
||||
PREFERENCES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/preferences.yaml | yq 'split(" ") | . + [""]' -o json) \
|
||||
&& yq -i -o json ".properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -11,10 +11,12 @@ stringData:
|
||||
{{- end }}
|
||||
{{- if or .Values.cloudInit .Values.sshKeys }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
apiVersion: core.cozystack.io/v1alpha1
|
||||
kind: TenantSecret
|
||||
metadata:
|
||||
name: {{ include "virtual-machine.fullname" . }}-cloud-init
|
||||
labels:
|
||||
apps.cozystack.io/virtual-machine: {{ .Release.Name }}
|
||||
stringData:
|
||||
userdata: |
|
||||
{{- if .Values.cloudInit }}
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -6,3 +6,4 @@ generate:
|
||||
# && yq -i -o json ".properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json
|
||||
PREFERENCES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/preferences.yaml | yq 'split(" ") | . + [""]' -o json) \
|
||||
&& yq -i -o json ".properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -2,3 +2,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -92,7 +92,7 @@ releases:
|
||||
releaseName: cozystack-api
|
||||
chart: cozy-cozystack-api
|
||||
namespace: cozy-system
|
||||
dependsOn: [cilium,kubeovn]
|
||||
dependsOn: [cilium,kubeovn,cozystack-controller]
|
||||
|
||||
- name: cozystack-controller
|
||||
releaseName: cozystack-controller
|
||||
@@ -297,6 +297,24 @@ releases:
|
||||
- keycloak-configure
|
||||
{{- end }}
|
||||
|
||||
- name: dashboard-config
|
||||
releaseName: dashboard-config
|
||||
chart: cozy-dashboard-config
|
||||
namespace: cozy-dashboard
|
||||
values:
|
||||
{{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }}
|
||||
{{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }}
|
||||
{{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }}
|
||||
dependsOn:
|
||||
- cilium
|
||||
- kubeovn
|
||||
- dashboard
|
||||
- cozystack-api
|
||||
{{- if eq $oidcEnabled "true" }}
|
||||
- keycloak-configure
|
||||
{{- end }}
|
||||
|
||||
|
||||
- name: kamaji
|
||||
releaseName: kamaji
|
||||
chart: cozy-kamaji
|
||||
|
||||
@@ -39,7 +39,7 @@ releases:
|
||||
releaseName: cozystack-api
|
||||
chart: cozy-cozystack-api
|
||||
namespace: cozy-system
|
||||
dependsOn: []
|
||||
dependsOn: [cozystack-controller]
|
||||
|
||||
- name: cozystack-controller
|
||||
releaseName: cozystack-controller
|
||||
@@ -177,11 +177,27 @@ releases:
|
||||
{{- $dashboardKCValues := dig "data" "values.yaml" (dict) $dashboardKCconfig }}
|
||||
{{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }}
|
||||
{{- if eq $oidcEnabled "true" }}
|
||||
dependsOn: [keycloak-configure]
|
||||
dependsOn: [keycloak-configure,cozystack-api]
|
||||
{{- else }}
|
||||
dependsOn: []
|
||||
{{- end }}
|
||||
|
||||
- name: dashboard-config
|
||||
releaseName: dashboard-config
|
||||
chart: cozy-dashboard-config
|
||||
namespace: cozy-dashboard
|
||||
values:
|
||||
{{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }}
|
||||
{{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig | fromYaml }}
|
||||
{{- toYaml (deepCopy $dashboardKCValues | mergeOverwrite (fromYaml (include "cozystack.defaultDashboardValues" .))) | nindent 4 }}
|
||||
dependsOn:
|
||||
- cilium
|
||||
- kubeovn
|
||||
- dashboard
|
||||
{{- if eq $oidcEnabled "true" }}
|
||||
- keycloak-configure
|
||||
{{- end }}
|
||||
|
||||
{{- if $oidcEnabled }}
|
||||
- name: keycloak
|
||||
releaseName: keycloak
|
||||
|
||||
@@ -5,3 +5,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -4,3 +4,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -4,4 +4,5 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
yq -o json -i '.properties = {}' values.schema.json
|
||||
yq -o json -i '.properties = {}' values.schema.json
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -9,3 +9,4 @@ get-cloudflare-ips:
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -7,6 +7,7 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
image:
|
||||
docker buildx build images/grafana \
|
||||
|
||||
@@ -4,3 +4,4 @@ include ../../../scripts/package.mk
|
||||
|
||||
generate:
|
||||
cozyvalues-gen -v values.yaml -s values.schema.json -r README.md
|
||||
../../../hack/update-crd.sh
|
||||
|
||||
@@ -16,8 +16,3 @@ image-cozystack-api:
|
||||
IMAGE="$(REGISTRY)/cozystack-api:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-api.json -o json -r)" \
|
||||
yq -i '.cozystackAPI.image = strenv(IMAGE)' values.yaml
|
||||
rm -f images/cozystack-api.json
|
||||
|
||||
generate:
|
||||
rm -rf openapi-schemas
|
||||
mkdir -p openapi-schemas
|
||||
find ../../apps ../../extra -maxdepth 2 -name values.schema.json -exec sh -ec 'ln -s ../{} openapi-schemas/$$(basename $$(dirname {})).json' \;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/bootbox/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/bucket/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/clickhouse/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/etcd/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/ferretdb/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/http-cache/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/info/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/ingress/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/kafka/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/kubernetes/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/monitoring/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/mysql/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/nats/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/postgres/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/rabbitmq/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/redis/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../extra/seaweedfs/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/tcp-balancer/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/tenant/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/virtual-machine/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/vm-disk/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/vm-instance/values.schema.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../apps/vpn/values.schema.json
|
||||
@@ -11,3 +11,17 @@ spec:
|
||||
name: cozystack-api
|
||||
namespace: cozy-system
|
||||
version: v1alpha1
|
||||
---
|
||||
apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
metadata:
|
||||
name: v1alpha1.core.cozystack.io
|
||||
spec:
|
||||
insecureSkipTLSVerify: true
|
||||
group: core.cozystack.io
|
||||
groupPriorityMinimum: 1000
|
||||
versionPriority: 15
|
||||
service:
|
||||
name: cozystack-api
|
||||
namespace: cozy-system
|
||||
version: v1alpha1
|
||||
|
||||
@@ -1,622 +0,0 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: bucket
|
||||
spec:
|
||||
application:
|
||||
kind: Bucket
|
||||
singular: bucket
|
||||
plural: buckets
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/bucket.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: bucket-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: bucket
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: clickhouse
|
||||
spec:
|
||||
application:
|
||||
kind: ClickHouse
|
||||
singular: clickhouse
|
||||
plural: clickhouses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/clickhouse.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: clickhouse-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: clickhouse
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: httpcache
|
||||
spec:
|
||||
application:
|
||||
kind: HTTPCache
|
||||
singular: httpcache
|
||||
plural: httpcaches
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/http-cache.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: http-cache-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: http-cache
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: nats
|
||||
spec:
|
||||
application:
|
||||
kind: NATS
|
||||
singular: nats
|
||||
plural: natses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/nats.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: nats-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: nats
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: tcpbalancer
|
||||
spec:
|
||||
application:
|
||||
kind: TCPBalancer
|
||||
singular: tcpbalancer
|
||||
plural: tcpbalancers
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/tcp-balancer.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: tcp-balancer-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: tcp-balancer
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: virtualmachine
|
||||
spec:
|
||||
application:
|
||||
kind: VirtualMachine
|
||||
singular: virtualmachine
|
||||
plural: virtualmachines
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/virtual-machine.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: virtual-machine-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: virtual-machine
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vpn
|
||||
spec:
|
||||
application:
|
||||
kind: VPN
|
||||
singular: vpn
|
||||
plural: vpns
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/vpn.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: vpn-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vpn
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: mysql
|
||||
spec:
|
||||
application:
|
||||
kind: MySQL
|
||||
singular: mysql
|
||||
plural: mysqls
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/mysql.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: mysql-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: mysql
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: tenant
|
||||
spec:
|
||||
application:
|
||||
kind: Tenant
|
||||
singular: tenant
|
||||
plural: tenants
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/tenant.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: tenant-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: tenant
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: kubernetes
|
||||
spec:
|
||||
application:
|
||||
kind: Kubernetes
|
||||
singular: kubernetes
|
||||
plural: kuberneteses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/kubernetes.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: kubernetes-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: kubernetes
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
application:
|
||||
kind: Redis
|
||||
singular: redis
|
||||
plural: redises
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/redis.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: redis-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: redis
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
spec:
|
||||
application:
|
||||
kind: RabbitMQ
|
||||
singular: rabbitmq
|
||||
plural: rabbitmqs
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/rabbitmq.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: rabbitmq-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: rabbitmq
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
application:
|
||||
kind: Postgres
|
||||
singular: postgres
|
||||
plural: postgreses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/postgres.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: postgres-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: postgres
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
- matchLabels:
|
||||
cnpg.io/userType: superuser
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: ferretdb
|
||||
spec:
|
||||
application:
|
||||
kind: FerretDB
|
||||
singular: ferretdb
|
||||
plural: ferretdbs
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/ferretdb.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ferretdb-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: ferretdb
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: kafka
|
||||
spec:
|
||||
application:
|
||||
kind: Kafka
|
||||
singular: kafka
|
||||
plural: kafkas
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/kafka.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: kafka-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: kafka
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vmdisk
|
||||
spec:
|
||||
application:
|
||||
kind: VMDisk
|
||||
singular: vmdisk
|
||||
plural: vmdisks
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/vm-disk.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: vm-disk-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vm-disk
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vminstance
|
||||
spec:
|
||||
application:
|
||||
kind: VMInstance
|
||||
singular: vminstance
|
||||
plural: vminstances
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/vm-instance.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: vm-instance-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vm-instance
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: monitoring
|
||||
spec:
|
||||
application:
|
||||
kind: Monitoring
|
||||
singular: monitoring
|
||||
plural: monitorings
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/monitoring.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: monitoring
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: etcd
|
||||
spec:
|
||||
application:
|
||||
kind: Etcd
|
||||
singular: etcd
|
||||
plural: etcds
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/etcd.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: etcd
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: ingress
|
||||
spec:
|
||||
application:
|
||||
kind: Ingress
|
||||
singular: ingress
|
||||
plural: ingresses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/ingress.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: ingress
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: seaweedfs
|
||||
spec:
|
||||
application:
|
||||
kind: SeaweedFS
|
||||
singular: seaweedfs
|
||||
plural: seaweedfses
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/seaweedfs.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: seaweedfs
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: bootbox
|
||||
spec:
|
||||
application:
|
||||
kind: BootBox
|
||||
singular: bootbox
|
||||
plural: bootboxes
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/bootbox.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: bootbox
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
---
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: info
|
||||
spec:
|
||||
application:
|
||||
kind: Info
|
||||
singular: info
|
||||
plural: infos
|
||||
openAPISchema: |
|
||||
{{- .Files.Get "openapi-schemas/info.json" | fromJson | toJson | nindent 6 }}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: info
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: bucket
|
||||
spec:
|
||||
application:
|
||||
kind: Bucket
|
||||
plural: buckets
|
||||
singular: bucket
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{}}
|
||||
release:
|
||||
prefix: bucket-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: bucket
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
singular: Bucket
|
||||
plural: Buckets
|
||||
category: IaaS
|
||||
weight: 80
|
||||
description: S3 compatible storage
|
||||
tags:
|
||||
- storage
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: clickhouse
|
||||
spec:
|
||||
application:
|
||||
kind: ClickHouse
|
||||
singular: clickhouse
|
||||
plural: clickhouses
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"backup":{"description":"Backup configuration","type":"object","default":{},"required":["cleanupStrategy","enabled","resticPassword","s3AccessKey","s3Bucket","s3Region","s3SecretKey","schedule"],"properties":{"cleanupStrategy":{"description":"Retention strategy for cleaning up old backups","type":"string","default":"--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"},"enabled":{"description":"Enable regular backups, default is `false`","type":"boolean","default":false},"resticPassword":{"description":"Password for Restic backup encryption","type":"string","default":"<password>"},"s3AccessKey":{"description":"Access key for S3, used for authentication","type":"string","default":"<your-access-key>"},"s3Bucket":{"description":"S3 bucket used for storing backups","type":"string","default":"s3.example.org/clickhouse-backups"},"s3Region":{"description":"AWS S3 region where backups are stored","type":"string","default":"us-east-1"},"s3SecretKey":{"description":"Secret key for S3, used for authentication","type":"string","default":"<your-secret-key>"},"schedule":{"description":"Cron schedule for automated backups","type":"string","default":"0 2 * * *"}}},"clickhouseKeeper":{"description":"Clickhouse Keeper configuration","type":"object","default":{},"required":["resourcesPreset"],"properties":{"enabled":{"description":"Deploy ClickHouse Keeper for cluster coordination","type":"boolean","default":true},"replicas":{"description":"Number of Keeper replicas","type":"integer","default":3},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size, available for application data","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"logStorageSize":{"description":"Size of Persistent Volume for logs","default":"2Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"logTTL":{"description":"TTL (expiration time) for `query_log` and `query_thread_log`","type":"integer","default":15},"replicas":{"description":"Number of Clickhouse replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"shards":{"description":"Number of Clickhouse shards","type":"integer","default":1},"size":{"description":"Persistent Volume Claim size, available for application data","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string"},"users":{"description":"Users configuration","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user","type":"string"},"readonly":{"description":"User is `readonly`, default is `false`.","type":"boolean"}}}}}}
|
||||
release:
|
||||
prefix: clickhouse-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: clickhouse
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: PaaS
|
||||
singular: ClickHouse
|
||||
plural: ClickHouse
|
||||
description: Managed ClickHouse service
|
||||
tags: []
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIwMikiLz4KPHBhdGggZD0iTTIzIDEwNUgzNFYxMTZIMjNWMTA1WiIgZmlsbD0iI0ZGMDAwMCIvPgo8cGF0aCBkPSJNMjMgMjhIMzRWMTA1SDIzVjI4Wk00NSAyOEg1NS45OTk5VjExNkg0NVYyOFpNNjYuOTk5OSAyOEg3Ny45OTk5VjExNkg2Ni45OTk5VjI4Wk04OC45OTk5IDI4SDk5Ljk5OTlWMTE2SDg4Ljk5OTlWMjhaTTExMSA2My43NDk5SDEyMlY4MC4yNDk5SDExMVY2My43NDk5WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIwMiIgeDE9Ii0wLjQ5OTk5OCIgeTE9IjEuNSIgeDI9IjE1My41IiB5Mj0iMTYyIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkNDMDAiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRkY3QTAwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "shards"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "logStorageSize"], ["spec", "logTTL"], ["spec", "users"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "s3Region"], ["spec", "backup", "s3Bucket"], ["spec", "backup", "schedule"], ["spec", "backup", "cleanupStrategy"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "backup", "resticPassword"], ["spec", "clickhouseKeeper"], ["spec", "clickhouseKeeper", "enabled"], ["spec", "clickhouseKeeper", "size"], ["spec", "clickhouseKeeper", "resourcesPreset"], ["spec", "clickhouseKeeper", "replicas"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: etcd
|
||||
spec:
|
||||
application:
|
||||
kind: Etcd
|
||||
plural: etcds
|
||||
singular: etcd
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of etcd replicas","type":"integer","default":3},"resources":{"description":"Resource configuration for etcd","type":"object","default":{},"properties":{"cpu":{"description":"The number of CPU cores allocated","default":4,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"The amount of memory allocated","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"size":{"description":"Persistent Volume size","default":"4Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string"}}}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: etcd
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: Administration
|
||||
singular: Etcd
|
||||
plural: Etcd
|
||||
name: etcd
|
||||
description: Storage for Kubernetes clusters
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5NjMpIi8+CjxwYXRoIGQ9Ik0xMjIuNDQyIDczLjQ3MjlDMTIxLjk1OSA3My41MTM0IDEyMS40NzQgNzMuNTMyMiAxMjAuOTU4IDczLjUzMjJDMTE3Ljk2NSA3My41MzIyIDExNS4wNjEgNzIuODMwNCAxMTIuNDQyIDcxLjU0NTFDMTEzLjMxNCA2Ni41NDIxIDExMy42ODUgNjEuNTAxOSAxMTMuNTg4IDU2LjQ4MDJDMTEwLjc0OCA1Mi4zNzIzIDEwNy41MDIgNDguNDk2NSAxMDMuODM4IDQ0LjkyNTdDMTA1LjQyOCA0MS45NDU0IDEwNy43NzggMzkuMzgxMSAxMTAuNzExIDM3LjU2MjhMMTExLjk3MSAzNi43ODQyTDExMC45ODkgMzUuNjc3NEMxMDUuOTMyIDI5Ljk4MzIgOTkuODk3MSAyNS41ODA5IDkzLjA1NDcgMjIuNTkzN0w5MS42OTAyIDIyTDkxLjM0MzcgMjMuNDQyM0M5MC41Mjc3IDI2LjgwMzYgODguODIyMiAyOS44MzYgODYuNDgwNyAzMi4yNjk1QzgxLjk4MDMgMjkuODc3NCA3Ny4yNzg4IDI3Ljk0NCA3Mi40MzA1IDI2LjQ3OTdDNjcuNTkzNyAyNy45NDA4IDYyLjkwMDUgMjkuODY4NiA1OC40MDIgMzIuMjU3MUM1Ni4wNzAxIDI5LjgyNjggNTQuMzY4OCAyNi44MDE4IDUzLjU1NiAyMy40NTAxTDUzLjIwNzIgMjIuMDA4M0w1MS44NDc3IDIyLjU5OTJDNDUuMDkxNCAyNS41NDMxIDM4Ljg5MDEgMzAuMDY0NyAzMy45MTYyIDM1LjY3NDJMMzIuOTMxOCAzNi43ODMzTDM0LjE5IDM3LjU2MTlDMzcuMTE0MiAzOS4zNzMzIDM5LjQ1NzYgNDEuOTIyNCA0MS4wNDQ0IDQ0Ljg4NjZDMzcuMzkxNyA0OC40NDM1IDM0LjE0OTUgNTIuMzA3IDMxLjMxMTkgNTYuMzk1OUMzMS4yMDE0IDYxLjQxNTQgMzEuNTUzNSA2Ni40OTI0IDMyLjQyOTcgNzEuNTY0NEMyOS44MjMxIDcyLjgzNzggMjYuOTM1OCA3My41MzE4IDIzLjk2MjggNzMuNTMxOEMyMy40NDA5IDczLjUzMTggMjIuOTUyNyA3My41MTI5IDIyLjQ3ODIgNzMuNDczM0wyMSA3My4zNjA2TDIxLjEzODUgNzQuODM2NUMyMS44NjI5IDgyLjMwMzMgMjQuMTgxNCA4OS40MDUzIDI4LjAzMzQgOTUuOTQ3MUwyOC43ODUzIDk3LjIyMzdMMjkuOTE0MiA5Ni4yNjU2QzMyLjUzMDUgOTQuMDQ2NSAzNS42OTE3IDkyLjU3NyAzOS4wNTMgOTEuOTg0N0M0MS4yNjg5IDk2LjUxNTUgNDMuODk1MyAxMDAuNzcyIDQ2Ljg3NDcgMTA0LjcyNUM1MS42Mjg3IDEwNi4zODcgNTYuNTgxOSAxMDcuNjI5IDYxLjY5NzEgMTA4LjM2N0M2Mi4xODc3IDExMS43NSA2MS43OTcgMTE1LjI0OSA2MC40NjI0IDExOC40ODRMNTkuODk5NSAxMTkuODU1TDYxLjM0NjkgMTIwLjE3NEM2NS4wNTI5IDEyMC45ODkgNjguNzkxNyAxMjEuNDA0IDcyLjQ1MjYgMTIxLjQwNEw4My41NTUxIDEyMC4xNzRMODUuMDAzOSAxMTkuODU1TDg0LjQzOTcgMTE4LjQ4MkM4My4xMDg3IDExNS4yNDYgODIuNzE4IDExMS43NDMgODMuMjA4NiAxMDguMzZDODguMzAzNiAxMDcuNjIxIDkzLjIzODQgMTA2LjM4MiA5Ny45NzQ4IDEwNC43MjVDMTAwLjk1NyAxMDAuNzY5IDEwMy41ODYgOTYuNTA5NSAxMDUuODA1IDkxLjk3MjhDMTA5LjE3NyA5Mi41NjE0IDExMi4zNTYgOTQuMDMxNyAxMTQuOTg5IDk2LjI1NzNMMTE2LjExOCA5Ny4yMTQxTDExNi44NjYgOTUuOTQwN0MxMjAuNzI1IDg5LjM5MDUgMTIzLjA0MyA4Mi4yODkxIDEyMy43NTYgNzQuODM0MkwxMjMuODk1IDczLjM2MUwxMjIuNDQyIDczLjQ3MjlaTTg4LjMxOTcgOTEuNTE4MUM4My4wNjczIDkyLjk0NjYgNzcuNzMzIDkzLjY2NzcgNzIuNDMwNSA5My42Njc3QzY3LjExMzcgOTMuNjY3NyA2MS43ODU5IDkyLjk0NyA1Ni41MjkgOTEuNTE4MUM1My42NDQ4IDg3LjAzNjYgNTEuMzY0NSA4Mi4yMzU3IDQ5LjcyMzQgNzcuMTgxMkM0OC4wODkyIDcyLjE1MDIgNDcuMTMyOSA2Ni44Nzk1IDQ2Ljg1NTQgNjEuNDUyMkM1MC4yNTA0IDU3LjI1NDcgNTQuMTExIDUzLjU3NzYgNTguMzc2NyA1MC40ODIzQzYyLjcxMTQgNDcuMzI5NCA2Ny40MjcxIDQ0Ljc2NzkgNzIuNDMwNSA0Mi44NDFDNzcuNDI1NiA0NC43NjgzIDgyLjEzMjYgNDcuMzI2MiA4Ni40NTcyIDUwLjQ2NTdDOTAuNzM5NCA1My41Nzc2IDk0LjYxNzEgNTcuMjgzMiA5OC4wMjg3IDYxLjUwN0M5Ny43Mzc4IDY2LjkwMzQgOTYuNzcgNzIuMTQzOCA5NS4xMzMgNzcuMTY2NUM5My40OTYxIDgyLjIyIDkxLjIwODQgODcuMDM2MSA4OC4zMTk3IDkxLjUxODFaTTc2Ljc2ODQgNjYuMTk3NEM3Ni43Njg0IDY5LjkwODEgNzkuNzc1NCA3Mi45MDk2IDgzLjQ4MSA3Mi45MDk2Qzg3LjE4NTcgNzIuOTA5NiA5MC4xODk1IDY5LjkwODYgOTAuMTg5NSA2Ni4xOTc0QzkwLjE4OTUgNjIuNTAxIDg3LjE4NTcgNTkuNDg4MSA4My40ODEgNTkuNDg4MUM3OS43NzU0IDU5LjQ4ODEgNzYuNzY4NCA2Mi41MDEgNzYuNzY4NCA2Ni4xOTc0Wk02OC4wOTU0IDY2LjE5NzRDNjguMDk1NCA2OS45MDgxIDY1LjA4ODggNzIuOTA5NiA2MS4zODMyIDcyLjkwOTZDNTcuNjc0OSA3Mi45MDk2IDU0LjY3NjYgNjkuOTA4NiA1NC42NzY2IDY2LjE5NzRDNTQuNjc2NiA2Mi41MDI0IDU3LjY3NTMgNTkuNDg5NCA2MS4zODMyIDU5LjQ4OTRDNjUuMDg4OCA1OS40ODk0IDY4LjA5NTQgNjIuNTAyNCA2OC4wOTU0IDY2LjE5NzRaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yOTYzIiB4MT0iNS41IiB5MT0iMTEiIHgyPSIxNDEiIHkyPSIxMjQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjNTNCMkYwIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzQxOUVEQSIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo=
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "size"], ["spec", "storageClass"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resources", "cpu"], ["spec", "resources", "memory"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: http-cache
|
||||
spec:
|
||||
application:
|
||||
kind: HTTPCache
|
||||
plural: httpcaches
|
||||
singular: httpcache
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"endpoints":{"description":"Endpoints configuration, as a list of <ip:port>","type":"array","default":[],"items":{"type":"string"}},"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"haproxy":{"description":"HAProxy configuration","type":"object","default":{},"required":["replicas","resources","resourcesPreset"],"properties":{"replicas":{"description":"Number of HAProxy replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"nginx":{"description":"Nginx configuration","type":"object","default":{},"required":["replicas","resourcesPreset"],"properties":{"replicas":{"description":"Number of Nginx replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"size":{"description":"Persistent Volume Claim size, available for application data","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string"}}}
|
||||
release:
|
||||
prefix: http-cache-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: http-cache
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: NaaS
|
||||
singular: HTTP Cache
|
||||
plural: HTTP Cache
|
||||
description: Layer7 load balancer and caching service
|
||||
tags:
|
||||
- cache
|
||||
- network
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyNSkiLz4KPHBhdGggZD0iTTI2LjAwMjYgMzcuODU4OEMyNi4wMDI2IDYwLjkxOSAyNi4wMDI2IDgzLjk4MTQgMjYuMDAyNiAxMDcuMDQ2QzI1Ljk3MyAxMDguMzIzIDI2LjE5OTYgMTA5LjU5MyAyNi42NjkyIDExMC43ODNDMjcuMTM4NyAxMTEuOTcyIDI3Ljg0MTggMTEzLjA1NiAyOC43Mzc0IDExMy45NzJDMzAuNDUzOSAxMTUuNjU5IDMyLjcgMTE2LjcwOSAzNS4xMDA5IDExNi45NDhDMzcuNTAxOSAxMTcuMTg3IDM5LjkxMjYgMTE2LjYgNDEuOTMxIDExNS4yODRDNDMuMjgyIDExNC4zNzEgNDQuMzg4MSAxMTMuMTQzIDQ1LjE1MjcgMTExLjcwN0M0NS45MTc0IDExMC4yNzEgNDYuMzE3NSAxMDguNjcxIDQ2LjMxODEgMTA3LjA0NkM0Ni4zMTgxIDkwLjM1MjggNDYuMjg2MSA3My42NTk3IDQ2LjMxODEgNTYuOTY2NkM2MS42MTY4IDc1LjE4ODkgNzYuOTQ3NCA5My4zODU2IDkyLjMxIDExMS41NTdDOTQuNDQ0NCAxMTMuNzA4IDk3LjA4NzUgMTE1LjI5MSA5OS45OTcgMTE2LjE2MkMxMDIuOTA2IDExNy4wMzIgMTA1Ljk4OSAxMTcuMTYyIDEwOC45NjIgMTE2LjUzOUMxMTEuMDYxIDExNi4xMjggMTEyLjk3MyAxMTUuMDU3IDExNC40MTUgMTEzLjQ4NUMxMTUuODU3IDExMS45MTMgMTE2Ljc1NCAxMDkuOTIxIDExNi45NzQgMTA3LjgwNEMxMTcuMDA5IDg0LjI2ODEgMTE3LjAwOSA2MC43MzQzIDExNi45NzQgMzcuMjAyNUMxMTYuNzU0IDM0LjY5MDcgMTE1LjU5NSAzMi4zNTIyIDExMy43MjYgMzAuNjQ4NkMxMTEuODU4IDI4Ljk0NSAxMDkuNDE1IDI4IDEwNi44ODEgMjhDMTA0LjM0NiAyOCAxMDEuOTAzIDI4Ljk0NSAxMDAuMDM1IDMwLjY0ODZDOTguMTY2MyAzMi4zNTIyIDk3LjAwNzQgMzQuNjkwNyA5Ni43ODY5IDM3LjIwMjVDOTYuNzg2OSA1NC4xNjMyIDk2LjY4NDQgNzEuMTA0OCA5Ni43ODY5IDg4LjA1OTFDODEuNzYxNiA3MC40MzU4IDY2LjkyMTkgNTIuNjU5NiA1MS45NTQzIDM0Ljk3MjVDNDkuOTgxIDMyLjQ1NTQgNDcuMzY4NSAzMC41MDczIDQ0LjM4NjMgMjkuMzI5MUM0MS40MDQxIDI4LjE1MDkgMzguMTU5OSAyNy43ODUyIDM0Ljk4ODMgMjguMjY5OEMzMi41ODU3IDI4LjUzNTkgMzAuMzU4MyAyOS42NDkzIDI4LjcwOTkgMzEuNDA4NEMyNy4wNjE1IDMzLjE2NzUgMjYuMTAxIDM1LjQ1NTkgMjYuMDAyNiAzNy44NTg4WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODFfMjgyNSIgeDE9IjEwIiB5MT0iMTUuNSIgeDI9IjE0NCIgeTI9IjEzMS41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMwMEM1NEEiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDE5NjM5Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "endpoints"], ["spec", "haproxy"], ["spec", "haproxy", "replicas"], ["spec", "haproxy", "resources"], ["spec", "haproxy", "resourcesPreset"], ["spec", "nginx"], ["spec", "nginx", "replicas"], ["spec", "nginx", "resources"], ["spec", "nginx", "resourcesPreset"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: info
|
||||
spec:
|
||||
application:
|
||||
kind: Info
|
||||
plural: infos
|
||||
singular: info
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{}}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: info
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
name: info
|
||||
category: Administration
|
||||
singular: Info
|
||||
plural: Info
|
||||
description: Info
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF8xNDRfMykiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzE0NF8zKSI+CjxwYXRoIGQ9Ik03Ny42NDA3IDk3LjA4NDRMODIuODMzIDk3LjM2MDRWMTA0LjYzN0g2MS4xNzI4Vjk3LjcxOTdMNjQuMTc3MSA5Ny40NDk1QzY1LjgxMDEgOTcuMjY4NCA2Ni44MTA2IDk2LjcxOTMgNjYuODEwNiA5NC41MzQzVjY5LjIzMTRDNjYuODEwNiA2Ny4yMjE3IDY2LjI3MDEgNjYuNTg2NCA2NC41MzY1IDY2LjU4NjRMNjEuMzU2OCA2Ni40MDgxVjU4Ljg1ODRINzcuNjQ2NUw3Ny42NDA3IDk3LjA4NDRaTTcxLjI3MjYgMzkuMzYzQzc1LjI4MDQgMzkuMzYzIDc4LjE4NyA0Mi4zNzMxIDc4LjE4NyA0Ni4xODgzQzc4LjE4NyA1MC4wMTQ5IDc1LjI3MTggNTIuODM4MSA3MS4xNzc4IDUyLjgzODFDNjYuOTk3NSA1Mi44MzgxIDY0LjI2NjMgNTAuMDE0OSA2NC4yNjYzIDQ2LjE4ODNDNjQuMjY2MyA0Mi4zNzMxIDY2Ljk5NzUgMzkuMzYzIDcxLjI3MjYgMzkuMzYzWk03MiAxMThDNDYuNjM2OCAxMTggMjYgOTcuMzYzMiAyNiA3MkMyNiA0Ni42MzY4IDQ2LjYzNjggMjYgNzIgMjZDOTcuMzU3NSAyNiAxMTggNDYuNjM2OCAxMTggNzJDMTE4IDk3LjM2MzIgOTcuMzU3NSAxMTggNzIgMTE4Wk03MiAzNC42MjVDNTEuMzkyIDM0LjYyNSAzNC42MjUgNTEuMzkyIDM0LjYyNSA3MkMzNC42MjUgOTIuNjA4IDUxLjM5MiAxMDkuMzc1IDcyIDEwOS4zNzVDOTIuNjA4IDEwOS4zNzUgMTA5LjM3NSA5Mi42MDggMTA5LjM3NSA3MkMxMDkuMzc1IDUxLjM5MiA5Mi42MDggMzQuNjI1IDcyIDM0LjYyNVoiIGZpbGw9IndoaXRlIi8+CjwvZz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8xNDRfMyIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgxLjMyMjk4ZS0wNSAtNy41MDAwMSkgcm90YXRlKDQ0LjcxNzgpIHNjYWxlKDIxNS4zMTcgMzEyLjQ1NSkiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMDBCNUU3Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwMzk4NCIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzE0NF8zIj4KPHJlY3Qgd2lkdGg9IjkyIiBoZWlnaHQ9IjkyIiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjYgMjYpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: ingress
|
||||
spec:
|
||||
application:
|
||||
kind: Ingress
|
||||
plural: ingresses
|
||||
singular: ingress
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"cloudflareProxy":{"description":"Restoring original visitor IPs when Cloudflare proxied is enabled","type":"boolean","default":false},"replicas":{"description":"Number of ingress-nginx replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each ingress-nginx replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"whitelist":{"description":"List of client networks","type":"array","default":[],"items":{"type":"string"}}}}
|
||||
release:
|
||||
prefix: ""
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: ingress
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: Administration
|
||||
singular: Ingress
|
||||
plural: Ingress
|
||||
name: ingress
|
||||
description: NGINX Ingress Controller
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODRfMzIyOSkiLz4KPHBhdGggZD0iTTg2LjkyNzQgMzcuMTA3NEgxN1YxMDcuMDM1SDg2LjkyNzRWMzcuMTA3NFoiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTEyNy42NDMgMjlIMTA3LjQ1NVY0OS4xODgzSDEyNy42NDNWMjlaIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik0xMjcuNjQzIDYxLjcyNjZIMTA3LjQ1NVY4MS45MTQ5SDEyNy42NDNWNjEuNzI2NloiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTEyNy42NDMgOTQuNDUyMUgxMDcuNDU1VjExNC42NEgxMjcuNjQzVjk0LjQ1MjFaIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik04OC41MTM3IDcyLjA3MTNIMTA2LjI3IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik04Ny41Njc0IDgwLjQyNDhMMTA3LjczIDk1Ljc4MDUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTg3LjU2NzQgNjMuNzE4MUwxMDcuNzMgNDguMzYyMyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4NF8zMjI5IiB4MT0iMTAiIHkxPSIxNS41IiB4Mj0iMTQ0IiB5Mj0iMTMxLjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzAwREE1MyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDk2MzkiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "whitelist"], ["spec", "cloudflareProxy"], ["spec", "resources"], ["spec", "resourcesPreset"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: kafka
|
||||
spec:
|
||||
application:
|
||||
kind: Kafka
|
||||
plural: kafkas
|
||||
singular: kafka
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"kafka":{"description":"Kafka configuration","type":"object","default":{},"required":["replicas","resourcesPreset","size","storageClass"],"properties":{"replicas":{"description":"Number of Kafka replicas","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size for Kafka","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the Kafka data","type":"string"}}},"topics":{"description":"Topics configuration","type":"array","default":[],"items":{"type":"object","required":["config","name","partitions","replicas"],"properties":{"config":{"description":"Topic configuration","type":"object","x-kubernetes-preserve-unknown-fields":true},"name":{"description":"Topic name","type":"string"},"partitions":{"description":"Number of partitions","type":"integer"},"replicas":{"description":"Number of replicas","type":"integer"}}}},"zookeeper":{"description":"Zookeeper configuration","type":"object","default":{},"required":["replicas","resourcesPreset","size","storageClass"],"properties":{"replicas":{"description":"Number of ZooKeeper replicas","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size for ZooKeeper","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the ZooKeeper data","type":"string"}}}}}
|
||||
release:
|
||||
prefix: kafka-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: kafka
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: PaaS
|
||||
singular: Kafka
|
||||
plural: Kafka
|
||||
description: Managed Kafka service
|
||||
tags:
|
||||
- messaging
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyMCkiLz4KPHBhdGggZD0iTTkxLjAzMDcgNzcuODE4NUM4Ni44NTc3IDc3LjgxODUgODMuMTE2NiA3OS42ODE4IDgwLjU1NDcgODIuNjE1NEw3My45OTAxIDc3LjkzMTVDNzQuNjg2OSA3NS45OTc4IDc1LjA4NyA3My45MjE1IDc1LjA4NyA3MS43NDgyQzc1LjA4NyA2OS42MTI2IDc0LjcwMDggNjcuNTcxMSA3NC4wMjY5IDY1LjY2Nkw4MC41NzY5IDYxLjAzMThDODMuMTM4NSA2My45NTA1IDg2Ljg2OTkgNjUuODAzNyA5MS4wMzA3IDY1LjgwMzdDOTguNzMyOCA2NS44MDM3IDEwNSA1OS40ODg0IDEwNSA1MS43MjQ3QzEwNSA0My45NjEgOTguNzMyOCAzNy42NDU3IDkxLjAzMDcgMzcuNjQ1N0M4My4zMjg1IDM3LjY0NTcgNzcuMDYxNCA0My45NjEgNzcuMDYxNCA1MS43MjQ3Qzc3LjA2MTQgNTMuMTE0MyA3Ny4yNjk3IDU0LjQ1NDMgNzcuNjQzNSA1NS43MjMzTDcxLjA4OTEgNjAuMzU5OEM2OC4zNTEyIDU2LjkzNjUgNjQuNDA5IDU0LjU0NjMgNTkuOTE3NCA1My44MTY2VjQ1Ljg1NTNDNjYuMjQ1MSA0NC41MTU4IDcxLjAxMjggMzguODQ5NSA3MS4wMTI4IDMyLjA3OUM3MS4wMTI4IDI0LjMxNTMgNjQuNzQ1NyAxOCA1Ny4wNDM1IDE4QzQ5LjM0MTQgMTggNDMuMDc0MiAyNC4zMTUzIDQzLjA3NDIgMzIuMDc5QzQzLjA3NDIgMzguNzU4OSA0Ny43MTg0IDQ0LjM1NTIgNTMuOTE5NiA0NS43OTAzVjUzLjg1NTFDNDUuNDU2NyA1NS4zNTIzIDM5IDYyLjc5NjEgMzkgNzEuNzQ4MkMzOSA4MC43NDQgNDUuNTIwNiA4OC4yMTUxIDU0LjA0NDYgODkuNjYxM1Y5OC4xNzcyQzQ3Ljc4MDEgOTkuNTY1IDQzLjA3NDIgMTA1LjE5NiA0My4wNzQyIDExMS45MjFDNDMuMDc0MiAxMTkuNjg1IDQ5LjM0MTQgMTI2IDU3LjA0MzUgMTI2QzY0Ljc0NTcgMTI2IDcxLjAxMjggMTE5LjY4NSA3MS4wMTI4IDExMS45MjFDNzEuMDEyOCAxMDUuMTk2IDY2LjMwNyA5OS41NjUgNjAuMDQyNCA5OC4xNzcyVjg5LjY2MTFDNjQuMzU2OSA4OC45Mjg2IDY4LjI2MDEgODYuNjQwNyA3MS4wMjUyIDgzLjIyMzRMNzcuNjMzNyA4Ny45Mzc2Qzc3LjI2NjkgODkuMTk1MiA3Ny4wNjE0IDkwLjUyMTkgNzcuMDYxNCA5MS44OTc1Qzc3LjA2MTQgOTkuNjYxMiA4My4zMjg1IDEwNS45NzYgOTEuMDMwNyAxMDUuOTc2Qzk4LjczMjggMTA1Ljk3NiAxMDUgOTkuNjYxMiAxMDUgOTEuODk3NUMxMDUgODQuMTMzOCA5OC43MzI4IDc3LjgxODUgOTEuMDMwNyA3Ny44MTg1Wk05MS4wMzA3IDQ0Ljg5ODVDOTQuNzY1NiA0NC44OTg1IDk3LjgwMzQgNDcuOTYxNSA5Ny44MDM0IDUxLjcyNDdDOTcuODAzNCA1NS40ODc5IDk0Ljc2NTYgNTguNTUwNiA5MS4wMzA3IDU4LjU1MDZDODcuMjk1OCA1OC41NTA2IDg0LjI1OCA1NS40ODc5IDg0LjI1OCA1MS43MjQ3Qzg0LjI1OCA0Ny45NjE1IDg3LjI5NTggNDQuODk4NSA5MS4wMzA3IDQ0Ljg5ODVaTTUwLjI3MDUgMzIuMDc5QzUwLjI3MDUgMjguMzE1OCA1My4zMDg2IDI1LjI1MzEgNTcuMDQzNSAyNS4yNTMxQzYwLjc3ODUgMjUuMjUzMSA2My44MTYzIDI4LjMxNTggNjMuODE2MyAzMi4wNzlDNjMuODE2MyAzNS44NDIyIDYwLjc3ODUgMzguOTA0OSA1Ny4wNDM1IDM4LjkwNDlDNTMuMzA4NiAzOC45MDQ5IDUwLjI3MDUgMzUuODQyMiA1MC4yNzA1IDMyLjA3OVpNNjMuODE2MyAxMTEuOTIxQzYzLjgxNjMgMTE1LjY4NCA2MC43Nzg1IDExOC43NDcgNTcuMDQzNSAxMTguNzQ3QzUzLjMwODYgMTE4Ljc0NyA1MC4yNzA1IDExNS42ODQgNTAuMjcwNSAxMTEuOTIxQzUwLjI3MDUgMTA4LjE1OCA1My4zMDg2IDEwNS4wOTUgNTcuMDQzNSAxMDUuMDk1QzYwLjc3ODUgMTA1LjA5NSA2My44MTYzIDEwOC4xNTggNjMuODE2MyAxMTEuOTIxWk01Ny4wNDMgODEuMjY4MUM1MS44MzM5IDgxLjI2ODEgNDcuNTk2MiA3Ni45OTggNDcuNTk2MiA3MS43NDgyQzQ3LjU5NjIgNjYuNDk4MiA1MS44MzM5IDYyLjIyNzMgNTcuMDQzIDYyLjIyNzNDNjIuMjUxOSA2Mi4yMjczIDY2LjQ4OTUgNjYuNDk4MiA2Ni40ODk1IDcxLjc0ODJDNjYuNDg5NSA3Ni45OTggNjIuMjUxOSA4MS4yNjgxIDU3LjA0MyA4MS4yNjgxWk05MS4wMzA3IDk4LjcyMzdDODcuMjk1OCA5OC43MjM3IDg0LjI1OCA5NS42NjA3IDg0LjI1OCA5MS44OTc1Qzg0LjI1OCA4OC4xMzQzIDg3LjI5NTggODUuMDcxNiA5MS4wMzA3IDg1LjA3MTZDOTQuNzY1NiA4NS4wNzE2IDk3LjgwMzQgODguMTM0MyA5Ny44MDM0IDkxLjg5NzVDOTcuODAzNCA5NS42NjA3IDk0Ljc2NTYgOTguNzIzNyA5MS4wMzA3IDk4LjcyMzdaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4MV8yODIwIiB4MT0iMTQwIiB5MT0iMTMwLjUiIHgyPSI0IiB5Mj0iOS40OTk5OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcC8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzQzNDE0MSIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo=
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "external"], ["spec", "topics"], ["spec", "kafka"], ["spec", "kafka", "replicas"], ["spec", "kafka", "resources"], ["spec", "kafka", "resourcesPreset"], ["spec", "kafka", "size"], ["spec", "kafka", "storageClass"], ["spec", "zookeeper"], ["spec", "zookeeper", "replicas"], ["spec", "zookeeper", "resources"], ["spec", "zookeeper", "resourcesPreset"], ["spec", "zookeeper", "size"], ["spec", "zookeeper", "storageClass"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,35 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: nats
|
||||
spec:
|
||||
application:
|
||||
kind: NATS
|
||||
plural: natses
|
||||
singular: nats
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"config":{"description":"NATS configuration","type":"object","default":{},"properties":{"merge":{"description":"Additional configuration to merge into NATS config (see example)","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true},"resolver":{"description":"Additional resolver configuration to merge into NATS config (see example)","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"jetstream":{"description":"Jetstream configuration","type":"object","default":{},"required":["enabled","size"],"properties":{"enabled":{"description":"Enable or disable Jetstream. Set to `true` (default) to enable Jetstream for persistent messaging in NATS.","type":"boolean","default":true},"size":{"description":"Jetstream persistent storage size. Specifies the size of the persistent storage for Jetstream (message store).","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"replicas":{"description":"Number of replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"storageClass":{"description":"StorageClass used to store the data","type":"string"},"users":{"description":"Users configuration","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user","type":"string"}}}}}}
|
||||
release:
|
||||
prefix: nats-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: nats
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: PaaS
|
||||
singular: NATS
|
||||
plural: NATS
|
||||
description: Managed NATS service
|
||||
tags:
|
||||
- messaging
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyMSkiLz4KPHJlY3Qgd2lkdGg9IjE0NCIgaGVpZ2h0PSIxNDQiIHJ4PSIyNCIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4zIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTE3LjQ4IDI1SDI3Vjk4Ljk2OTNINjYuMDY4OUw4Ny43MDc1IDExOVY5OC45NjkzSDExNy40OFYyNVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05Mi4xMzUyIDcyLjQ1NTJWNDIuNjI1SDEwMi43NzNWODEuMTk5OUg4Ni42NTE5TDU0LjExNCA1MC44NDE0VjgxLjIzMjJINDMuNDQ0M1Y0Mi42MjVINjAuMTI2Mkw5Mi4xMzUyIDcyLjQ1NTJaIiBmaWxsPSJibGFjayIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4MV8yODIxIiB4MT0iMTAiIHkxPSIxNS41IiB4Mj0iMTQ0IiB5Mj0iMTMxLjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzM4NUM5MyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMkE1NzQiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "storageClass"], ["spec", "external"], ["spec", "users"], ["spec", "jetstream"], ["spec", "jetstream", "enabled"], ["spec", "jetstream", "size"], ["spec", "config"], ["spec", "config", "merge"], ["spec", "config", "resolver"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,35 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
spec:
|
||||
application:
|
||||
kind: RabbitMQ
|
||||
plural: rabbitmqs
|
||||
singular: rabbitmq
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"replicas":{"description":"Number of RabbitMQ replicas","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size, available for application data","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string"},"users":{"description":"Users configuration","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user","type":"string"}}}},"vhosts":{"description":"Virtual Hosts configuration","type":"object","default":{},"additionalProperties":{"type":"object","required":["roles"],"properties":{"roles":{"description":"Virtual host roles list","type":"object","properties":{"admin":{"description":"List of admin users","type":"array","items":{"type":"string"}},"readonly":{"description":"List of readonly users","type":"array","items":{"type":"string"}}}}}}}}}
|
||||
release:
|
||||
prefix: rabbitmq-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: rabbitmq
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: PaaS
|
||||
singular: RabbitMQ
|
||||
plural: RabbitMQ
|
||||
description: Managed RabbitMQ service
|
||||
tags:
|
||||
- messaging
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5NzIpIi8+CjxwYXRoIGQ9Ik0xMTEuNDExIDYyLjhIODIuNDkzOUM4MS43OTY5IDYyLjc5OTcgODEuMTI4NSA2Mi41MjI4IDgwLjYzNTYgNjIuMDMwMUM4MC4xNDI3IDYxLjUzNzMgNzkuODY1NiA2MC44NjkxIDc5Ljg2NTMgNjAuMTcyMlYzMC4wNDEyQzc5Ljg2NTMgMjcuODEgNzguMDU1NiAyNiA3NS44MjQ5IDI2SDY1LjUwMjFDNjMuMjcgMjYgNjEuNDYxNCAyNy44MSA2MS40NjE0IDMwLjA0MTJWNTkuOTg5OEM2MS40NjE0IDYxLjU0MzUgNjAuMjA1IDYyLjgwNjUgNTguNjUwOCA2Mi44MTMzTDQ5LjE3NDMgNjIuODU4NEM0Ny42MDY5IDYyLjg2NjkgNDYuMzMzNiA2MS41OTU1IDQ2LjMzNjYgNjAuMDI5OEw0Ni4zOTU0IDMwLjA0OEM0Ni40MDA1IDI3LjgxMzQgNDQuNTkwMiAyNiA0Mi4zNTUgMjZIMzIuMDQwN0MyOS44MDgzIDI2IDI4IDI3LjgxIDI4IDMwLjA0MTJWMTE0LjQxMkMyOCAxMTYuMzk0IDI5LjYwNjEgMTE4IDMxLjU4NzEgMTE4SDExMS40MTFDMTEzLjM5NCAxMTggMTE1IDExNi4zOTQgMTE1IDExNC40MTJWNjYuMzg4QzExNSA2NC40MDU4IDExMy4zOTQgNjIuOCAxMTEuNDExIDYyLjhaTTk3Ljg1MDggOTQuNDc3OUM5Ny44NTA4IDk3LjA3NTUgOTUuNzQ0NSA5OS4xODE3IDkzLjE0NjQgOTkuMTgxN0g4NC45ODg0QzgyLjM5IDk5LjE4MTcgODAuMjgzNiA5Ny4wNzU1IDgwLjI4MzYgOTQuNDc3OVY4Ni4zMjE3QzgwLjI4MzYgODMuNzIzOCA4Mi4zOSA4MS42MTc5IDg0Ljk4ODQgODEuNjE3OUg5My4xNDY0Qzk1Ljc0NDUgODEuNjE3OSA5Ny44NTA4IDgzLjcyMzggOTcuODUwOCA4Ni4zMjE3Vjk0LjQ3NzlaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yOTcyIiB4MT0iNSIgeTE9Ii03LjUiIHgyPSIxNDEiIHkyPSIxMjQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkY4MjJGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0ZGNjYwMCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo=
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "users"], ["spec", "vhosts"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
application:
|
||||
kind: Redis
|
||||
plural: redises
|
||||
singular: redis
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"authEnabled":{"description":"Enable password generation","type":"boolean","default":true},"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"replicas":{"description":"Number of Redis replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size, available for application data","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string"}}}
|
||||
release:
|
||||
prefix: redis-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: redis
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: PaaS
|
||||
singular: Redis
|
||||
plural: Redis
|
||||
description: Managed Redis service
|
||||
tags:
|
||||
- cache
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIxMykiLz4KPHBhdGggZD0iTTEyMC4xNDkgOTUuNTQ5MUMxMTQuNTg2IDk4LjQ0ODUgODUuNzcwOSAxMTAuMjk2IDc5LjYzNjMgMTEzLjQ5NUM3My41MDE2IDExNi42OTMgNzAuMDkzNyAxMTYuNjYyIDY1LjI0NzIgMTE0LjM0NkM2MC40MDEyIDExMi4wMjkgMjkuNzM2NCA5OS42NDIzIDI0LjIxMjUgOTcuMDAxOUMyMS40NTE5IDk1LjY4MjcgMjAgOTQuNTY4NyAyMCA5My41MTY2VjgyLjk4MDlDMjAgODIuOTgwOSA1OS45MjIgNzQuMjkwMSA2Ni4zNjY5IDcxLjk3NzhDNzIuODExNSA2OS42NjU2IDc1LjA0NzYgNjkuNTgyMSA4MC41MzIgNzEuNTkxQzg2LjAxNzMgNzMuNjAwOCAxMTguODEyIDc5LjUxNzYgMTI0LjIzMyA4MS41MDI5TDEyNC4yMyA5MS44ODk2QzEyNC4yMzEgOTIuOTMxMSAxMjIuOTggOTQuMDczNiAxMjAuMTQ5IDk1LjU0OTFaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDg1LjA3NTJDMTE0LjU4NSA4Ny45NzM0IDg1Ljc3IDk5LjgyMTggNzkuNjM1NCAxMDMuMDJDNzMuNTAxMSAxMDYuMjE5IDcwLjA5MzIgMTA2LjE4NyA2NS4yNDcyIDEwMy44NzFDNjAuNDAwNyAxMDEuNTU1IDI5LjczNzEgODkuMTY2OCAyNC4yMTM2IDg2LjUyOEMxOC42OTAxIDgzLjg4NzYgMTguNTc0NCA4Mi4wNzA0IDI0LjAwMDMgNzkuOTQ1OEMyOS40MjYxIDc3LjgyMDUgNTkuOTIxNSA2NS44NTYxIDY2LjM2NzIgNjMuNTQzOEM3Mi44MTE4IDYxLjIzMjQgNzUuMDQ3NSA2MS4xNDgxIDgwLjUzMTkgNjMuMTU3OEM4Ni4wMTY4IDY1LjE2NjggMTE0LjY2IDc2LjU2NzYgMTIwLjA3OSA3OC41NTI1QzEyNS41MDEgODAuNTM5OSAxMjUuNzA5IDgyLjE3NjMgMTIwLjE0NyA4NS4wNzUyWiIgZmlsbD0iI0M2MzAyQiIvPgo8cGF0aCBkPSJNMTIwLjE0OSA3OC41MDJDMTE0LjU4NiA4MS40MDE4IDg1Ljc3MDkgOTMuMjQ5MyA3OS42MzYzIDk2LjQ0ODhDNzMuNTAxNiA5OS42NDYyIDcwLjA5MzcgOTkuNjE1MiA2NS4yNDcyIDk3LjI5ODVDNjAuNDAwOCA5NC45ODMgMjkuNzM2NCA4Mi41OTUyIDI0LjIxMjUgNzkuOTU0N0MyMS40NTE5IDc4LjYzNTUgMjAgNzcuNTIzMiAyMCA3Ni40NzA3VjY1LjkzMzhDMjAgNjUuOTMzOCA1OS45MjIgNTcuMjQzNCA2Ni4zNjY5IDU0LjkzMTFDNzIuODExNSA1Mi42MTg5IDc1LjA0NzYgNTIuNTM1IDgwLjUzMiA1NC41NDQzQzg2LjAxNzcgNTYuNTUzNiAxMTguODEzIDYyLjQ2OTMgMTI0LjIzMyA2NC40NTVMMTI0LjIzIDc0Ljg0MjhDMTI0LjIzMSA3NS44ODQgMTIyLjk4IDc3LjAyNjQgMTIwLjE0OSA3OC41MDJaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDY4LjAyODJDMTE0LjU4NSA3MC45MjcxIDg1Ljc3IDgyLjc3NDcgNzkuNjM1NCA4NS45NzM3QzczLjUwMTEgODkuMTcxNiA3MC4wOTMyIDg5LjE0MDIgNjUuMjQ3MiA4Ni44MjM1QzYwLjQwMDcgODQuNTA4NCAyOS43MzcxIDcyLjEyMDEgMjQuMjEzNiA2OS40ODA5QzE4LjY5MDEgNjYuODQxMyAxOC41NzQ0IDY1LjAyMzcgMjQuMDAwMyA2Mi44OTg0QzI5LjQyNjEgNjAuNzc0MiA1OS45MjE5IDQ4LjgwOSA2Ni4zNjcyIDQ2LjQ5NzJDNzIuODExOCA0NC4xODUzIDc1LjA0NzUgNDQuMTAxNCA4MC41MzE5IDQ2LjExMDhDODYuMDE2OCA0OC4xMTk3IDExNC42NiA1OS41MTk3IDEyMC4wNzkgNjEuNTA1NUMxMjUuNTAxIDYzLjQ5MjQgMTI1LjcwOSA2NS4xMjkyIDEyMC4xNDcgNjguMDI4MloiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTEyMC4xNDkgNjAuODIyNEMxMTQuNTg2IDYzLjcyMTQgODUuNzcwOSA3NS41Njk4IDc5LjYzNjMgNzguNzY5MkM3My41MDE2IDgxLjk2NzEgNzAuMDkzNyA4MS45MzU3IDY1LjI0NzIgNzkuNjE5QzYwLjQwMDggNzcuMzAzNSAyOS43MzY0IDY0LjkxNTIgMjQuMjEyNSA2Mi4yNzZDMjEuNDUxOSA2MC45NTU2IDIwIDU5Ljg0MjggMjAgNTguNzkxNVY0OC4yNTQyQzIwIDQ4LjI1NDIgNTkuOTIyIDM5LjU2NDIgNjYuMzY2OSAzNy4yNTI0QzcyLjgxMTUgMzQuOTM5NyA3NS4wNDc2IDM0Ljg1NjcgODAuNTMyIDM2Ljg2NTZDODYuMDE3NyAzOC44NzQ5IDExOC44MTMgNDQuNzkwNSAxMjQuMjMzIDQ2Ljc3NjNMMTI0LjIzIDU3LjE2MzdDMTI0LjIzMSA1OC4yMDQgMTIyLjk4IDU5LjM0NjUgMTIwLjE0OSA2MC44MjI0WiIgZmlsbD0iIzkxMjYyNiIvPgo8cGF0aCBkPSJNMTIwLjE0NyA1MC4zNDlDMTE0LjU4NSA1My4yNDc5IDg1Ljc2OTggNjUuMDk2MyA3OS42MzUyIDY4LjI5NDFDNzMuNTAwOSA3MS40OTIgNzAuMDkzIDcxLjQ2MDYgNjUuMjQ2OSA2OS4xNDUxQzYwLjQwMDkgNjYuODI4MyAyOS43MzY5IDU0LjQ0MDkgMjQuMjEzOCA1MS44MDEzQzE4LjY4OTkgNDkuMTYyMSAxOC41NzQ2IDQ3LjM0NDEgMjQgNDUuMjE5MkMyOS40MjU5IDQzLjA5NDYgNTkuOTIxNyAzMS4xMzEgNjYuMzY3IDI4LjgxODRDNzIuODExNiAyNi41MDYxIDc1LjA0NzMgMjYuNDIzIDgwLjUzMTcgMjguNDMyNEM4Ni4wMTY2IDMwLjQ0MTcgMTE0LjY1OSA0MS44NDE4IDEyMC4wNzkgNDMuODI3NUMxMjUuNTAxIDQ1LjgxMjggMTI1LjcwOSA0Ny40NSAxMjAuMTQ3IDUwLjM0OVoiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTg0Ljg1NDEgNDAuMDk5NEw3NS44OTI2IDQxLjAyOThMNzMuODg2NSA0NS44NTdMNzAuNjQ2MyA0MC40NzAzTDYwLjI5ODMgMzkuNTQwNEw2OC4wMTk3IDM2Ljc1NThMNjUuNzAzIDMyLjQ4MTRMNzIuOTMyMSAzNS4zMDg4TDc5Ljc0NzEgMzMuMDc3NUw3Ny45MDUyIDM3LjQ5NzJMODQuODU0MSA0MC4wOTk0Wk03My4zNTE1IDYzLjUxODRMNTYuNjI2NiA1Ni41ODE2TDgwLjU5MiA1Mi45MDI5TDczLjM1MTUgNjMuNTE4NFpNNTAuMTYzNyA0Mi43ODI2QzU3LjIzODEgNDIuNzgyNiA2Mi45NzMgNDUuMDA1NyA2Mi45NzMgNDcuNzQ3NUM2Mi45NzMgNTAuNDkwMSA1Ny4yMzgxIDUyLjcxMjggNTAuMTYzNyA1Mi43MTI4QzQzLjA4OTMgNTIuNzEyOCAzNy4zNTQ1IDUwLjQ4OTcgMzcuMzU0NSA0Ny43NDc1QzM3LjM1NDUgNDUuMDA1NyA0My4wODkzIDQyLjc4MjYgNTAuMTYzNyA0Mi43ODI2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTk1LjQ0MzQgNDEuNDE3NEwxMDkuNjI3IDQ3LjAyMjRMOTUuNDU1NiA1Mi42MjJMOTUuNDQzNCA0MS40MTc0WiIgZmlsbD0iIzYyMUIxQyIvPgo8cGF0aCBkPSJNNzkuNzUyOSA0Ny42MjYxTDk1LjQ0NDkgNDEuNDE4OUw5NS40NTcxIDUyLjYyMzZMOTMuOTE4NCA1My4yMjU0TDc5Ljc1MjkgNDcuNjI2MVoiIGZpbGw9IiM5QTI5MjgiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIxMyIgeDE9IjE4OSIgeTE9IjIxMC41IiB4Mj0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0E4MDAwMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkNGQ0YiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "authEnabled"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: tenant
|
||||
spec:
|
||||
application:
|
||||
kind: Tenant
|
||||
singular: tenant
|
||||
plural: tenants
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"etcd":{"description":"Deploy own Etcd cluster","type":"boolean","default":false},"host":{"description":"The hostname used to access tenant services (defaults to using the tenant name as a subdomain for it's parent tenant host).","type":"string"},"ingress":{"description":"Deploy own Ingress Controller","type":"boolean","default":false},"isolated":{"description":"Enforce tenant namespace with network policies, `true` by default","type":"boolean","default":true},"monitoring":{"description":"Deploy own Monitoring Stack","type":"boolean","default":false},"resourceQuotas":{"description":"Define resource quotas for the tenant","type":"object","default":{},"additionalProperties":{"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}},"seaweedfs":{"description":"Deploy own SeaweedFS","type":"boolean","default":false}}}
|
||||
release:
|
||||
prefix: tenant-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: tenant
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: Administration
|
||||
singular: Tenant
|
||||
plural: Tenants
|
||||
description: Separated tenant namespace
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzQwMykiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zNDAzKSI+CjxwYXRoIGQ9Ik03MiAyOUM2Ni4zOTI2IDI5IDYxLjAxNDggMzEuMjM4OCA1Ny4wNDk3IDM1LjIyNEM1My4wODQ3IDM5LjIwOTEgNTAuODU3MSA0NC42MTQxIDUwLjg1NzEgNTAuMjVDNTAuODU3MSA1NS44ODU5IDUzLjA4NDcgNjEuMjkwOSA1Ny4wNDk3IDY1LjI3NkM2MS4wMTQ4IDY5LjI2MTIgNjYuMzkyNiA3MS41IDcyIDcxLjVDNzcuNjA3NCA3MS41IDgyLjk4NTIgNjkuMjYxMiA4Ni45NTAzIDY1LjI3NkM5MC45MTUzIDYxLjI5MDkgOTMuMTQyOSA1NS44ODU5IDkzLjE0MjkgNTAuMjVDOTMuMTQyOSA0NC42MTQxIDkwLjkxNTMgMzkuMjA5MSA4Ni45NTAzIDM1LjIyNEM4Mi45ODUyIDMxLjIzODggNzcuNjA3NCAyOSA3MiAyOVpNNjAuOTgyNiA4My4zMDM3QzYwLjQ1NCA4Mi41ODk4IDU5LjU5NTEgODIuMTkxNCA1OC43MTk2IDgyLjI3NDRDNDUuMzg5NyA4My43MzU0IDM1IDk1LjEwNzQgMzUgMTA4LjkwM0MzNSAxMTEuNzI2IDM3LjI3OTUgMTE0IDQwLjA3MSAxMTRIMTAzLjkyOUMxMDYuNzM3IDExNCAxMDkgMTExLjcwOSAxMDkgMTA4LjkwM0MxMDkgOTUuMTA3NCA5OC42MTAzIDgzLjc1MiA4NS4yNjM4IDgyLjI5MUM4NC4zODg0IDgyLjE5MTQgODMuNTI5NSA4Mi42MDY0IDgzLjAwMDkgODMuMzIwM0w3NC4wOTc4IDk1LjI0MDJDNzMuMDQwNiA5Ni42NTE0IDcwLjkyNjMgOTYuNjUxNCA2OS44NjkyIDk1LjI0MDJMNjAuOTY2MSA4My4zMjAzTDYwLjk4MjYgODMuMzAzN1oiIGZpbGw9ImJsYWNrIi8+CjwvZz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODdfMzQwMyIgeDE9IjcyIiB5MT0iMTQ0IiB4Mj0iLTEuMjgxN2UtMDUiIHkyPSI0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNDMEQ2RkYiLz4KPHN0b3Agb2Zmc2V0PSIwLjMiIHN0b3AtY29sb3I9IiNDNERBRkYiLz4KPHN0b3Agb2Zmc2V0PSIwLjY1IiBzdG9wLWNvbG9yPSIjRDNFOUZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0U5RkZGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzY4N18zNDAzIj4KPHJlY3Qgd2lkdGg9Ijc0IiBoZWlnaHQ9Ijg1IiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzUgMjkpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "etcd"], ["spec", "monitoring"], ["spec", "ingress"], ["spec", "seaweedfs"], ["spec", "isolated"], ["spec", "resourceQuotas"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,36 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: virtual-machine
|
||||
spec:
|
||||
application:
|
||||
kind: VirtualMachine
|
||||
plural: virtualmachines
|
||||
singular: virtualmachine
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"cloudInit":{"description":"Cloud-init user data config. See cloud-init documentation for more details: [format](https://cloudinit.readthedocs.io/en/latest/explanation/format.html), [examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html).","type":"string"},"cloudInitSeed":{"description":"A seed string to generate an SMBIOS UUID for the VM.","type":"string"},"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"externalMethod":{"description":"Specify method to pass through the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`","type":"string","default":"PortList","enum":["PortList","WholeIP"]},"externalPorts":{"description":"Specify ports to forward from outside the cluster","type":"array","default":[22],"items":{"type":"integer"}},"gpus":{"description":"List of GPUs to attach","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"name":{"description":"The name of the GPU to attach. This should match the GPU resource name in the cluster.","type":"string"}}}},"instanceProfile":{"description":"Virtual Machine preferences profile","type":"string","default":"ubuntu","enum":["alpine","centos.7","centos.7.desktop","centos.stream10","centos.stream10.desktop","centos.stream8","centos.stream8.desktop","centos.stream8.dpdk","centos.stream9","centos.stream9.desktop","centos.stream9.dpdk","cirros","fedora","fedora.arm64","opensuse.leap","opensuse.tumbleweed","rhel.10","rhel.10.arm64","rhel.7","rhel.7.desktop","rhel.8","rhel.8.desktop","rhel.8.dpdk","rhel.9","rhel.9.arm64","rhel.9.desktop","rhel.9.dpdk","rhel.9.realtime","sles","ubuntu","windows.10","windows.10.virtio","windows.11","windows.11.virtio","windows.2k16","windows.2k16.virtio","windows.2k19","windows.2k19.virtio","windows.2k22","windows.2k22.virtio","windows.2k25","windows.2k25.virtio",""]},"instanceType":{"description":"Virtual Machine instance type","type":"string","default":"u1.medium"},"resources":{"description":"Resources","type":"object","default":{},"properties":{"cpu":{"description":"The number of CPU cores allocated to the virtual machine","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"The amount of memory allocated to the virtual machine","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"sockets":{"description":"The number of CPU sockets allocated to the virtual machine (used to define vCPU topology)","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"running":{"description":"if the virtual machine should be running","type":"boolean","default":true},"sshKeys":{"description":"List of SSH public keys for authentication. Can be a single key or a list of keys.","type":"array","default":[],"items":{"type":"string"}},"systemDisk":{"description":"System disk configuration","type":"object","default":{},"required":["image","storage"],"properties":{"image":{"description":"The base image for the virtual machine. Allowed values: `ubuntu`, `cirros`, `alpine`, `fedora` and `talos`","type":"string","default":"ubuntu","enum":["ubuntu","cirros","alpine","fedora","talos"]},"storage":{"description":"The size of the disk allocated for the virtual machine","type":"string","default":"5Gi"},"storageClass":{"description":"StorageClass used to store the data","type":"string","default":"replicated"}}}}}
|
||||
release:
|
||||
prefix: virtual-machine-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: virtual-machine
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: IaaS
|
||||
singular: Virtual Machine
|
||||
plural: Virtual Machines
|
||||
description: Virtual Machine (simple)
|
||||
weight: 10
|
||||
tags:
|
||||
- compute
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzQ1NCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zNDU0KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMDBCM0ZGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi41Mjc1IDUzLjgzNjdDNzIuNDQzMSA1My44MzUxIDcyLjM2MDUgNTMuODEyMiA3Mi4yODczIDUzLjc3MDFMNTYuNDY5OSA0NC43OTM0QzU2LjM5ODMgNDQuNzUxOSA1Ni4zMzg4IDQ0LjY5MjMgNTYuMjk3MyA0NC42MjA3QzU2LjI1NTkgNDQuNTQ5IDU2LjIzMzggNDQuNDY3OCA1Ni4yMzM0IDQ0LjM4NUM1Ni4yMzM0IDQ0LjIxNjkgNTYuMzI1OCA0NC4wNjE3IDU2LjQ2OTkgNDMuOTc4NUw3Mi4xOTEyIDM1LjA2MDlDNzIuMjYzNyAzNS4wMjEgNzIuMzQ1IDM1IDcyLjQyNzcgMzVDNzIuNTEwNSAzNSA3Mi41OTE4IDM1LjAyMSA3Mi42NjQzIDM1LjA2MDlMODguNDg3MiA0NC4wMzk1Qzg4LjU1OTEgNDQuMDgwMSA4OC42MTg4IDQ0LjEzOTIgODguNjYgNDQuMjEwN0M4OC43MDEzIDQ0LjI4MjIgODguNzIyNyA0NC4zNjM1IDg4LjcyMTkgNDQuNDQ2Qzg4LjcyMjUgNDQuNTI4NSA4OC43MDEgNDQuNjA5NyA4OC42NTk4IDQ0LjY4MTJDODguNjE4NSA0NC43NTI2IDg4LjU1ODkgNDQuODExOCA4OC40ODcyIDQ0Ljg1MjVMNzIuNzcxNCA1My43NjgzQzcyLjY5NzIgNTMuODExNCA3Mi42MTMzIDUzLjgzNDkgNzIuNTI3NSA1My44MzY3IiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBvcGFjaXR5PSIwLjciIGQ9Ik03MC4yNTUzIDc1LjY1MTdDNzAuMTcxIDc1LjY1MzUgNzAuMDg3OCA3NS42MzE3IDcwLjAxNTEgNzUuNTg4OEw1NC4yNDU4IDY2LjY0MTdDNTQuMTcxNSA2Ni42MDI0IDU0LjEwOTUgNjYuNTQzNiA1NC4wNjYxIDY2LjQ3MTZDNTQuMDIyOCA2Ni4zOTk3IDU0IDY2LjMxNzMgNTQgNjYuMjMzM1Y0OC4yNzhDNTQgNDguMTA4IDU0LjA5MjQgNDcuOTU0NiA1NC4yNDM5IDQ3Ljg2OTZDNTQuMzE3MiA0Ny44MjcxIDU0LjQwMDQgNDcuODA0NyA1NC40ODUxIDQ3LjgwNDdDNTQuNTY5NyA0Ny44MDQ3IDU0LjY1MjkgNDcuODI3MSA1NC43MjYyIDQ3Ljg2OTZMNzAuNDkzNyA1Ni44MTMxQzcwLjU2NDIgNTYuODU2NSA3MC42MjI1IDU2LjkxNyA3MC42NjMyIDU2Ljk4OTFDNzAuNzAzOSA1Ny4wNjEyIDcwLjcyNTcgNTcuMTQyNCA3MC43MjY1IDU3LjIyNTFWNzUuMTgwNUM3MC43MjU5IDc1LjI2MjggNzAuNzA0MiA3NS4zNDM2IDcwLjY2MzUgNzUuNDE1MUM3MC42MjI3IDc1LjQ4NjYgNzAuNTY0MiA3NS41NDY0IDcwLjQ5MzcgNzUuNTg4OEM3MC40MjA2IDc1LjYyOTEgNzAuMzM4NyA3NS42NTA3IDcwLjI1NTMgNzUuNjUxNyIgZmlsbD0id2hpdGUiLz4KPHBhdGggb3BhY2l0eT0iMC40IiBkPSJNNzQuNzE5OCA3NS42NTExQzc0LjYzMzMgNzUuNjUxMiA3NC41NDgyIDc1LjYyOTYgNzQuNDcyMiA3NS41ODgzQzc0LjQwMTYgNzUuNTQ2MSA3NC4zNDMyIDc1LjQ4NjIgNzQuMzAyNyA3NS40MTQ3Qzc0LjI2MjMgNzUuMzQzMSA3NC4yNDExIDc1LjI2MjIgNzQuMjQxMiA3NS4xOFY1Ny4zMzczQzc0LjI0MTIgNTcuMTcxIDc0LjMzMzYgNTcuMDE1OCA3NC40NzIyIDU2LjkyOUw5MC4yMzk3IDQ3Ljk4NTVDOTAuMzExOSA0Ny45NDM4IDkwLjM5MzggNDcuOTIxOSA5MC40NzcxIDQ3LjkyMTlDOTAuNTYwNSA0Ny45MjE5IDkwLjY0MjQgNDcuOTQzOCA5MC43MTQ2IDQ3Ljk4NTVDOTAuNzg3NiA0OC4wMjU1IDkwLjg0ODUgNDguMDg0MiA5MC44OTExIDQ4LjE1NTdDOTAuOTMzNyA0OC4yMjcyIDkwLjk1NjMgNDguMzA4OCA5MC45NTY2IDQ4LjM5MlY2Ni4yMzI4QzkwLjk1NyA2Ni4zMTY0IDkwLjkzNDcgNjYuMzk4NSA5MC44OTIxIDY2LjQ3MDRDOTAuODQ5NSA2Ni41NDI0IDkwLjc4ODEgNjYuNjAxNCA5MC43MTQ2IDY2LjY0MTFMNzQuOTUyNiA3NS41ODgzQzc0Ljg4MjUgNzUuNjMwNyA3NC44MDE4IDc1LjY1MjUgNzQuNzE5OCA3NS42NTExIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zNDU0IiB4MT0iMTYxIiB5MT0iMTgwIiB4Mj0iMy41OTI4NGUtMDciIHkyPSI0Ljk5OTk4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNTk1NjU2Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfNjg3XzM0NTQiPgo8cmVjdCB3aWR0aD0iOTQiIGhlaWdodD0iOTQiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNSAyNSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "external"], ["spec", "externalMethod"], ["spec", "externalPorts"], ["spec", "running"], ["spec", "instanceType"], ["spec", "instanceProfile"], ["spec", "systemDisk"], ["spec", "systemDisk", "image"], ["spec", "systemDisk", "storage"], ["spec", "systemDisk", "storageClass"], ["spec", "gpus"], ["spec", "resources"], ["spec", "sshKeys"], ["spec", "cloudInit"], ["spec", "cloudInitSeed"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,36 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vm-disk
|
||||
spec:
|
||||
application:
|
||||
kind: VMDisk
|
||||
singular: vmdisk
|
||||
plural: vmdisks
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"optical":{"description":"Defines if disk should be considered optical","type":"boolean","default":false},"source":{"description":"The source image location used to create a disk","type":"object","default":{},"properties":{"http":{"description":"Download image from an HTTP source","type":"object","required":["url"],"properties":{"url":{"description":"URL to download the image","type":"string"}}},"image":{"description":"Use image by name: uploaded as \"golden image\" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, and `talos`.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the image to use","type":"string"}}},"upload":{"description":"Upload local image","type":"object"}}},"storage":{"description":"The size of the disk allocated for the virtual machine","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data","type":"string","default":"replicated"}}}
|
||||
release:
|
||||
prefix: vm-disk-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vm-disk
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: IaaS
|
||||
singular: VM Disk
|
||||
plural: VM Disks
|
||||
description: Virtual Machine disk
|
||||
weight: 51
|
||||
tags:
|
||||
- storage
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8zMzBfNDg5NjMpIi8+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2lfMzMwXzQ4OTYzKSI+CjxwYXRoIGQ9Ik03Mi4wMDAxIDI2LjYzNjdDNDYuODc3MiAyNi42MzY3IDI2LjUxMTIgNDcuMDAyNyAyNi41MTEyIDcyLjEyNTZDMjYuNTExMiA5Ny4yNDg0IDQ2Ljg3NzIgMTE3LjYxNCA3Mi4wMDAxIDExNy42MTRDOTcuMTIyOSAxMTcuNjE0IDExNy40ODkgOTcuMjQ4MiAxMTcuNDg5IDcyLjEyNTRDMTE3LjQ4OSA0Ny4wMDI1IDk3LjEyMjkgMjYuNjM2NyA3Mi4wMDAxIDI2LjYzNjdaTTcyLjAwMDEgODEuNjIxMkM2Ni43NTU3IDgxLjYyMTIgNjIuNTA0NCA3Ny4zNjk5IDYyLjUwNDQgNzIuMTI1NkM2Mi41MDQ0IDY2Ljg4MTIgNjYuNzU1NyA2Mi42Mjk5IDcyLjAwMDEgNjIuNjI5OUM3Ny4yNDQ0IDYyLjYyOTkgODEuNDk1NyA2Ni44ODEyIDgxLjQ5NTcgNzIuMTI1NkM4MS40OTU3IDc3LjM2OTkgNzcuMjQ0NCA4MS42MjEyIDcyLjAwMDEgODEuNjIxMloiIGZpbGw9IiNCQUQ5RkYiLz4KPC9nPgo8cGF0aCBkPSJNNTIuMDA3NSA2NS43MjA5TDMyLjI5NzYgNTkuMDQ5OEMzNi4yODQyIDQ3LjI3MTEgNDUuMzI4NSAzNy42MzE1IDU2LjQ5MSAzMy4yNjRMNjQuMDcyOCA1Mi42NDE5QzU4LjY0MiA1NC43NjY3IDU0LjAxOSA1OS43NzgzIDUyLjAwNzUgNjUuNzIwOVpNOTEuOTkyNiA3OC41M0wxMTEuNzAzIDg1LjIwMTFDMTA3LjcxNiA5Ni45Nzk5IDk4LjY3MTggMTA2LjYxOSA4Ny41MDkzIDExMC45ODdMNzkuOTI3NSA5MS42MDlDODUuMzU4MSA4OS40ODQyIDg5Ljk4MTMgODQuNDcyNiA5MS45OTI2IDc4LjUzWiIgZmlsbD0iI0VERjZGRiIvPgo8cGF0aCBkPSJNNTUuOTMyNCA1OC43MDI4QzU3LjY1MTQgNTYuNjE0IDU5LjcxOTQgNTQuODYzMiA2MS45ODk0IDUzLjYxODNDNjMuMTQ5IDUyLjk4MjQgNjQuMjYzMyA1My4xMjk2IDYzLjc4MTQgNTEuODk3OUw1Ny4yMDk1IDM1LjEwMDlDNTYuMjkwOSAzMi43NTI5IDU1LjI4MTQgMzMuNzI4NSA1My45MDYgMzQuMzg2OEM0OC45NzM0IDM2Ljc0NzYgNDQuNTM0OSA0MC4xNTkgNDAuODYwMSA0NC4zMTU0TDU1LjkzMjQgNTguNzAyOFpNODguMDY3NiA4NS41NDgxQzg1LjgzNTIgODguMjYwNSA4My4wMTQ4IDkwLjQwMjkgNzkuOTI2OSA5MS42MDhMODcuNTA4OSAxMTAuOTg2QzkzLjQ3ODUgMTA4LjY1NCA5OC44MzM2IDEwNC44MDYgMTAzLjE0IDk5LjkzNTVMODguMDY3NiA4NS41NDgxWiIgZmlsbD0iI0NERTNGRiIvPgo8cGF0aCBkPSJNNzIgODkuNDM4OEM2Mi40NTM0IDg5LjQzODggNTQuNjg2NSA4MS42NzIxIDU0LjY4NjUgNzIuMTI1NEM1NC42ODY1IDYyLjU3ODYgNjIuNDUzNCA1NC44MTE5IDcyIDU0LjgxMTlDODEuNTQ2OCA1NC44MTE5IDg5LjMxMzQgNjIuNTc4OCA4OS4zMTM0IDcyLjEyNTRDODkuMzEzNCA4MS42NzIgODEuNTQ2OCA4OS40Mzg4IDcyIDg5LjQzODhaTTcyIDU5LjExMDVDNjQuODIzNCA1OS4xMTA1IDU4Ljk4NDkgNjQuOTQ5IDU4Ljk4NDkgNzIuMTI1NkM1OC45ODQ5IDc5LjMwMjIgNjQuODIzNCA4NS4xNDA2IDcyIDg1LjE0MDZDNzkuMTc2NiA4NS4xNDA2IDg1LjAxNSA3OS4zMDIyIDg1LjAxNSA3Mi4xMjU2Qzg1LjAxNSA2NC45NDkgNzkuMTc2NiA1OS4xMTA1IDcyIDU5LjExMDVaIiBmaWxsPSIjMDBCNEZGIi8+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2lfMzMwXzQ4OTYzIiB4PSIyNi41MTEyIiB5PSIyNi42MzY3IiB3aWR0aD0iOTIuOTc3OCIgaGVpZ2h0PSI5Mi45Nzc1IiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+CjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+CjxmZUNvbG9yTWF0cml4IGluPSJTb3VyY2VBbHBoYSIgdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPgo8ZmVPZmZzZXQgZHg9IjIiIGR5PSIyIi8+CjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIuNSIvPgo8ZmVDb21wb3NpdGUgaW4yPSJoYXJkQWxwaGEiIG9wZXJhdG9yPSJhcml0aG1ldGljIiBrMj0iLTEiIGszPSIxIi8+CjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwIDAgMCAwIDEgMCAwIDAgMCAxIDAgMCAwIDAgMSAwIDAgMCAwLjIxIDAiLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbjI9InNoYXBlIiByZXN1bHQ9ImVmZmVjdDFfaW5uZXJTaGFkb3dfMzMwXzQ4OTYzIi8+CjwvZmlsdGVyPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMzMwXzQ4OTYzIiB4MT0iLTE1LjUiIHkxPSItMTIiIHgyPSIyMTYuNSIgeTI9IjE4NS41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM2NUNDRkYiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDQ0Mzc0Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "source"], ["spec", "optical"], ["spec", "storage"], ["spec", "storageClass"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,36 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vm-instance
|
||||
spec:
|
||||
application:
|
||||
kind: VMInstance
|
||||
singular: vminstance
|
||||
plural: vminstances
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"cloudInit":{"description":"Cloud-init user data config. See cloud-init documentation for more details: [format](https://cloudinit.readthedocs.io/en/latest/explanation/format.html), [examples](https://cloudinit.readthedocs.io/en/latest/reference/examples.html).","type":"string"},"cloudInitSeed":{"description":"A seed string to generate an SMBIOS UUID for the VM.","type":"string"},"disks":{"description":"List of disks to attach","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"bus":{"description":"Disk bus type, such as \"sata\"","type":"string"},"name":{"description":"Disk name","type":"string"}}}},"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"externalMethod":{"description":"Specify method to pass through the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`","type":"string","default":"PortList","enum":["PortList","WholeIP"]},"externalPorts":{"description":"Ports to forward from outside the cluster","type":"array","default":[22],"items":{"type":"integer"}},"gpus":{"description":"List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM)","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"name":{"description":"Name of GPU, such as \"nvidia.com/AD102GL_L40S\"","type":"string"}}}},"instanceProfile":{"description":"Virtual Machine preferences profile","type":"string","default":"ubuntu","enum":["alpine","centos.7","centos.7.desktop","centos.stream10","centos.stream10.desktop","centos.stream8","centos.stream8.desktop","centos.stream8.dpdk","centos.stream9","centos.stream9.desktop","centos.stream9.dpdk","cirros","fedora","fedora.arm64","opensuse.leap","opensuse.tumbleweed","rhel.10","rhel.10.arm64","rhel.7","rhel.7.desktop","rhel.8","rhel.8.desktop","rhel.8.dpdk","rhel.9","rhel.9.arm64","rhel.9.desktop","rhel.9.dpdk","rhel.9.realtime","sles","ubuntu","windows.10","windows.10.virtio","windows.11","windows.11.virtio","windows.2k16","windows.2k16.virtio","windows.2k19","windows.2k19.virtio","windows.2k22","windows.2k22.virtio","windows.2k25","windows.2k25.virtio",""]},"instanceType":{"description":"Virtual Machine instance type","type":"string","default":"u1.medium"},"resources":{"description":"Resources","type":"object","default":{},"properties":{"cpu":{"description":"The number of CPU cores allocated to the virtual machine","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"The amount of memory allocated to the virtual machine","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"sockets":{"description":"The number of CPU sockets allocated to the virtual machine (used to define vCPU topology)","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"running":{"description":"Determines if the virtual machine should be running","type":"boolean","default":true},"sshKeys":{"description":"List of SSH public keys for authentication. Can be a single key or a list of keys.","type":"array","default":[],"items":{"type":"string"}}}}
|
||||
release:
|
||||
prefix: vm-instance-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vm-instance
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: IaaS
|
||||
singular: VM Instance
|
||||
plural: VM Instances
|
||||
description: Virtual machine instance
|
||||
weight: 50
|
||||
tags:
|
||||
- compute
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzQ1NCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zNDU0KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMDBCM0ZGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi41Mjc1IDUzLjgzNjdDNzIuNDQzMSA1My44MzUxIDcyLjM2MDUgNTMuODEyMiA3Mi4yODczIDUzLjc3MDFMNTYuNDY5OSA0NC43OTM0QzU2LjM5ODMgNDQuNzUxOSA1Ni4zMzg4IDQ0LjY5MjMgNTYuMjk3MyA0NC42MjA3QzU2LjI1NTkgNDQuNTQ5IDU2LjIzMzggNDQuNDY3OCA1Ni4yMzM0IDQ0LjM4NUM1Ni4yMzM0IDQ0LjIxNjkgNTYuMzI1OCA0NC4wNjE3IDU2LjQ2OTkgNDMuOTc4NUw3Mi4xOTEyIDM1LjA2MDlDNzIuMjYzNyAzNS4wMjEgNzIuMzQ1IDM1IDcyLjQyNzcgMzVDNzIuNTEwNSAzNSA3Mi41OTE4IDM1LjAyMSA3Mi42NjQzIDM1LjA2MDlMODguNDg3MiA0NC4wMzk1Qzg4LjU1OTEgNDQuMDgwMSA4OC42MTg4IDQ0LjEzOTIgODguNjYgNDQuMjEwN0M4OC43MDEzIDQ0LjI4MjIgODguNzIyNyA0NC4zNjM1IDg4LjcyMTkgNDQuNDQ2Qzg4LjcyMjUgNDQuNTI4NSA4OC43MDEgNDQuNjA5NyA4OC42NTk4IDQ0LjY4MTJDODguNjE4NSA0NC43NTI2IDg4LjU1ODkgNDQuODExOCA4OC40ODcyIDQ0Ljg1MjVMNzIuNzcxNCA1My43NjgzQzcyLjY5NzIgNTMuODExNCA3Mi42MTMzIDUzLjgzNDkgNzIuNTI3NSA1My44MzY3IiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBvcGFjaXR5PSIwLjciIGQ9Ik03MC4yNTUzIDc1LjY1MTdDNzAuMTcxIDc1LjY1MzUgNzAuMDg3OCA3NS42MzE3IDcwLjAxNTEgNzUuNTg4OEw1NC4yNDU4IDY2LjY0MTdDNTQuMTcxNSA2Ni42MDI0IDU0LjEwOTUgNjYuNTQzNiA1NC4wNjYxIDY2LjQ3MTZDNTQuMDIyOCA2Ni4zOTk3IDU0IDY2LjMxNzMgNTQgNjYuMjMzM1Y0OC4yNzhDNTQgNDguMTA4IDU0LjA5MjQgNDcuOTU0NiA1NC4yNDM5IDQ3Ljg2OTZDNTQuMzE3MiA0Ny44MjcxIDU0LjQwMDQgNDcuODA0NyA1NC40ODUxIDQ3LjgwNDdDNTQuNTY5NyA0Ny44MDQ3IDU0LjY1MjkgNDcuODI3MSA1NC43MjYyIDQ3Ljg2OTZMNzAuNDkzNyA1Ni44MTMxQzcwLjU2NDIgNTYuODU2NSA3MC42MjI1IDU2LjkxNyA3MC42NjMyIDU2Ljk4OTFDNzAuNzAzOSA1Ny4wNjEyIDcwLjcyNTcgNTcuMTQyNCA3MC43MjY1IDU3LjIyNTFWNzUuMTgwNUM3MC43MjU5IDc1LjI2MjggNzAuNzA0MiA3NS4zNDM2IDcwLjY2MzUgNzUuNDE1MUM3MC42MjI3IDc1LjQ4NjYgNzAuNTY0MiA3NS41NDY0IDcwLjQ5MzcgNzUuNTg4OEM3MC40MjA2IDc1LjYyOTEgNzAuMzM4NyA3NS42NTA3IDcwLjI1NTMgNzUuNjUxNyIgZmlsbD0id2hpdGUiLz4KPHBhdGggb3BhY2l0eT0iMC40IiBkPSJNNzQuNzE5OCA3NS42NTExQzc0LjYzMzMgNzUuNjUxMiA3NC41NDgyIDc1LjYyOTYgNzQuNDcyMiA3NS41ODgzQzc0LjQwMTYgNzUuNTQ2MSA3NC4zNDMyIDc1LjQ4NjIgNzQuMzAyNyA3NS40MTQ3Qzc0LjI2MjMgNzUuMzQzMSA3NC4yNDExIDc1LjI2MjIgNzQuMjQxMiA3NS4xOFY1Ny4zMzczQzc0LjI0MTIgNTcuMTcxIDc0LjMzMzYgNTcuMDE1OCA3NC40NzIyIDU2LjkyOUw5MC4yMzk3IDQ3Ljk4NTVDOTAuMzExOSA0Ny45NDM4IDkwLjM5MzggNDcuOTIxOSA5MC40NzcxIDQ3LjkyMTlDOTAuNTYwNSA0Ny45MjE5IDkwLjY0MjQgNDcuOTQzOCA5MC43MTQ2IDQ3Ljk4NTVDOTAuNzg3NiA0OC4wMjU1IDkwLjg0ODUgNDguMDg0MiA5MC44OTExIDQ4LjE1NTdDOTAuOTMzNyA0OC4yMjcyIDkwLjk1NjMgNDguMzA4OCA5MC45NTY2IDQ4LjM5MlY2Ni4yMzI4QzkwLjk1NyA2Ni4zMTY0IDkwLjkzNDcgNjYuMzk4NSA5MC44OTIxIDY2LjQ3MDRDOTAuODQ5NSA2Ni41NDI0IDkwLjc4ODEgNjYuNjAxNCA5MC43MTQ2IDY2LjY0MTFMNzQuOTUyNiA3NS41ODgzQzc0Ljg4MjUgNzUuNjMwNyA3NC44MDE4IDc1LjY1MjUgNzQuNzE5OCA3NS42NTExIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zNDU0IiB4MT0iMTYxIiB5MT0iMTgwIiB4Mj0iMy41OTI4NGUtMDciIHkyPSI0Ljk5OTk4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNTk1NjU2Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfNjg3XzM0NTQiPgo8cmVjdCB3aWR0aD0iOTQiIGhlaWdodD0iOTQiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNSAyNSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "external"], ["spec", "externalMethod"], ["spec", "externalPorts"], ["spec", "running"], ["spec", "instanceType"], ["spec", "instanceProfile"], ["spec", "disks"], ["spec", "gpus"], ["spec", "resources"], ["spec", "sshKeys"], ["spec", "cloudInit"], ["spec", "cloudInitSeed"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: CozystackResourceDefinition
|
||||
metadata:
|
||||
name: vpn
|
||||
spec:
|
||||
application:
|
||||
kind: VPN
|
||||
plural: vpns
|
||||
singular: vpn
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster","type":"boolean","default":false},"externalIPs":{"description":"List of externalIPs for service. Optional. If not specified will use LoadBalancer service by default.","type":"array","default":[],"items":{"type":"string"}},"host":{"description":"Host used to substitute into generated URLs","type":"string"},"replicas":{"description":"Number of VPN server replicas","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each VPN server replica. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"users":{"description":"Users configuration","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user, autogenerated if none provided","type":"string"}}}}}}
|
||||
release:
|
||||
prefix: vpn-
|
||||
labels:
|
||||
cozystack.io/ui: "true"
|
||||
chart:
|
||||
name: vpn
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-apps
|
||||
namespace: cozy-public
|
||||
dashboard:
|
||||
category: NaaS
|
||||
singular: VPN
|
||||
plural: VPN
|
||||
description: Managed VPN service
|
||||
tags:
|
||||
- network
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDMuOTkyIDMwLjM2OTdDMTQzLjk5MiAyOS4yNTU2IDE0My45OTIgMjguMTUxNyAxNDMuOTkyIDI3LjA0NzdDMTQzLjk0NSAyNC42Mjg3IDE0My43MTcgMjIuMjE2NiAxNDMuMzA5IDE5LjgzMTZDMTQyLjkxMiAxNy40NDczIDE0Mi4xNTcgMTUuMTM2NSAxNDEuMDcyIDEyLjk3NjlDMTM5Ljk3IDEwLjgxOCAxMzguNTM0IDguODQ2NjUgMTM2LjgxNyA3LjEzNTc3TDEzMC45OTcgMi44OTA0NEMxMjguODM3IDEuODAyODkgMTI2LjUyNyAxLjA0MTg5IDEyNC4xNDQgMC42MzIyODNDMTIxLjc1NiAwLjIzNDgwOCAxMTkuMzQgMC4wMjM0MTEzIDExNi45MTkgMEMxMTUuODE1IDAgMjguMTQ2MSAwIDI3LjAzMjMgMEMyNC42MDQ3IDAuMDI0MjIxMSAyMi4xODI2IDAuMjM1NjA5IDE5Ljc4NzYgMC42MzIyODNDMTcuNDEyOCAxLjAzODUxIDE1LjExMjYgMS43OTk3NCAxMi45NjQzIDIuODkwNDRDMTAuODEzIDMuOTk1MTkgOC44NDYyNSA1LjQyNzM2IDcuMTM0MzYgNy4xMzU3N0M1LjQxNzY4IDguODQ0NCAzLjk4NDggMTAuODE2MyAyLjg4OTg3IDEyLjk3NjlDMS44MDA4NiAxNS4xMzYgMS4wNDMxMyAxNy40NDY4IDAuNjQyMTkzIDE5LjgzMTZDMC4yNDM0OTcgMjIuMjE2OSAwLjAyODc5OTggMjQuNjI5NCAwIDI3LjA0NzdDMCAyOC4xNTE3IDAgMTE1LjgzOCAwIDExNi45NTJDMC4wMjYxNzU1IDExOS4zODQgMC4yNDA4ODQgMTIxLjgxIDAuNjQyMTkzIDEyNC4yMDlDMS4wNDA0NCAxMjYuNTk0IDEuNzk4MjkgMTI4LjkwNSAyLjg4OTg3IDEzMS4wNjNDMy45ODUxNSAxMzMuMjE4IDUuNDE4MSAxMzUuMTgzIDcuMTM0MzYgMTM2Ljg4NEM4Ljg0MDk1IDEzOC41OTkgMTAuODA4NyAxNDAuMDMyIDEyLjk2NDMgMTQxLjEzQzE1LjExNDcgMTQyLjIwOSAxNy40MTQ2IDE0Mi45NiAxOS43ODc2IDE0My4zNThDMjIuMTczMSAxNDMuNzUxIDI0LjU4NDcgMTQzLjk2NiAyNy4wMDIyIDE0NEMyOC4xMTYgMTQ0IDExNS43ODUgMTQ0IDExNi44ODkgMTQ0QzExOS4zMDMgMTQzLjk2NyAxMjEuNzEyIDE0My43NTIgMTI0LjA5NCAxNDMuMzU4QzEyNi40ODUgMTQyLjk0NiAxMjguODAxIDE0Mi4xODIgMTMwLjk2NyAxNDEuMDg5QzEzMy4xMjEgMTM5Ljk5NCAxMzUuMDg2IDEzOC41NjEgMTM2Ljc4NyAxMzYuODQ0QzEzOC41MDMgMTM1LjE0IDEzOS45MzkgMTMzLjE3NiAxNDEuMDQyIDEzMS4wMjNDMTQyLjEzNyAxMjguODc5IDE0Mi45MDEgMTI2LjU4MSAxNDMuMzA5IDEyNC4yMDlDMTQzLjcxIDEyMS44MjMgMTQzLjkzMiAxMTkuNDExIDE0My45NzIgMTE2Ljk5MkMxNDMuOTkyIDExNS44MzggMTQ0LjAxMiAzMS42NzQ0IDE0My45OTIgMzAuMzY5N1oiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgxOCkiLz4KPHBhdGggZD0iTTExNS45NTUgNjcuNDIzMUMxMTQuOTQxIDU3LjgyMzQgMTEwLjcwMSA0OC44NTE4IDEwMy45MjggNDEuOTc1MkM5Ny4xNTQ5IDM1LjA5ODYgODguMjQ5NSAzMC43MjM5IDc4LjY2OCAyOS41NjY0VjQ2Ljc3ODZDODQuNDg4NyA0Ny45MTI3IDg5LjczMzggNTEuMDM2MiA5My41MDQ5IDU1LjYxMzdDOTcuMjc2IDYwLjE5MTIgOTkuMzM4MSA2NS45Mzc5IDk5LjMzODEgNzEuODY5MkM5OS4zMzgxIDc3LjgwMDQgOTcuMjc2IDgzLjU0NzEgOTMuNTA0OSA4OC4xMjQ2Qzg5LjczMzggOTIuNzAyMiA4NC40ODg3IDk1LjgyNTYgNzguNjY4IDk2Ljk1OThWMTE0LjIyMkM4OS43ODAxIDExMi44NzcgOTkuOTE3OCAxMDcuMjE1IDEwNi44OTQgOTguNDYwMUMxMTMuODY5IDg5LjcwNDggMTE3LjEyNCA3OC41NTczIDExNS45NTUgNjcuNDIzMVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yOC4wMTU1IDc2LjM2NTRDMjkuMDMxMSA4NS45NjQ0IDMzLjI3MTggOTQuOTM1MSA0MC4wNDQ3IDEwMS44MTFDNDYuODE3NSAxMDguNjg4IDU1LjcyMiAxMTMuMDYzIDY1LjMwMjggMTE0LjIyMlYyOS41NjY0QzU0LjE5MDcgMzAuOTExOSA0NC4wNTMgMzYuNTczMSAzNy4wNzcyIDQ1LjMyODRDMzAuMTAxMyA1NC4wODM3IDI2Ljg0NjcgNjUuMjMxMiAyOC4wMTU1IDc2LjM2NTRaIiBmaWxsPSIjNUJCMTkzIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfNjgxXzI4MTgiIHgxPSIxMzIuNSIgeTE9IjEzMi41IiB4Mj0iLTI0IiB5Mj0iLTE5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMxODM3MjkiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNDU5RDc1Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "external"], ["spec", "host"], ["spec", "users"], ["spec", "externalIPs"]]
|
||||
secrets:
|
||||
exclude:
|
||||
- matchLabels:
|
||||
apps.cozystack.io/tenantresource: "false"
|
||||
include: [{}]
|
||||
@@ -4,8 +4,11 @@ metadata:
|
||||
name: cozystack-api
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces"]
|
||||
resources: ["namespaces", "secrets"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "update", "patch", "delete"]
|
||||
- apiGroups: ["admissionregistration.k8s.io"]
|
||||
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations", "validatingadmissionpolicies", "validatingadmissionpolicybindings"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: tenantnamespaces-read
|
||||
rules:
|
||||
- apiGroups:
|
||||
- core.cozystack.io
|
||||
resources:
|
||||
- tenantnamespaces
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tenantnamespaces-read-authenticated
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: tenantnamespaces-read
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: Group
|
||||
name: system:authenticated
|
||||
@@ -1,2 +1,2 @@
|
||||
cozystackAPI:
|
||||
image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:be6aca4df4b769538454d6c65b7045b2bef81b2a15d70eeddbfdf55d6bd17d6c
|
||||
image: ghcr.io/cozystack/cozystack/cozystack-api:latest@sha256:73fd18b7dcc1782002574d3b6436f5f164d43c7fb0e78cdcf2d71fe10f9863fd
|
||||
|
||||
@@ -12,7 +12,7 @@ spec:
|
||||
listKind: CozystackResourceDefinitionList
|
||||
plural: cozystackresourcedefinitions
|
||||
singular: cozystackresourcedefinition
|
||||
scope: Namespaced
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
@@ -62,6 +62,67 @@ spec:
|
||||
- plural
|
||||
- singular
|
||||
type: object
|
||||
dashboard:
|
||||
description: Dashboard configuration for this resource
|
||||
properties:
|
||||
category:
|
||||
description: Category used to group resources in the UI (e.g.,
|
||||
"Storage", "Networking")
|
||||
type: string
|
||||
description:
|
||||
description: Short description shown in catalogs or headers (e.g.,
|
||||
"S3 compatible storage")
|
||||
type: string
|
||||
icon:
|
||||
description: Icon encoded as a string (e.g., inline SVG, base64,
|
||||
or data URI)
|
||||
type: string
|
||||
keysOrder:
|
||||
description: Order of keys in the YAML view
|
||||
items:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: array
|
||||
name:
|
||||
description: Hard-coded name used in the UI (e.g., "bucket")
|
||||
type: string
|
||||
plural:
|
||||
description: Plural human-readable name (e.g., "Buckets")
|
||||
type: string
|
||||
singular:
|
||||
description: Human-readable name shown in the UI (e.g., "Bucket")
|
||||
type: string
|
||||
singularResource:
|
||||
description: Whether this resource is singular (not a collection)
|
||||
in the UI
|
||||
type: boolean
|
||||
tabs:
|
||||
description: Which tabs to show for this resource
|
||||
items:
|
||||
description: DashboardTab enumerates allowed UI tabs.
|
||||
enum:
|
||||
- workloads
|
||||
- ingresses
|
||||
- services
|
||||
- secrets
|
||||
- yaml
|
||||
type: string
|
||||
type: array
|
||||
tags:
|
||||
description: Free-form tags for search and filtering
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
weight:
|
||||
description: Order weight for sorting resources in the UI (lower
|
||||
first)
|
||||
type: integer
|
||||
required:
|
||||
- category
|
||||
- plural
|
||||
- singular
|
||||
type: object
|
||||
release:
|
||||
description: Release configuration
|
||||
properties:
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.16.4
|
||||
name: breadcrumbs.dashboard.cozystack.io
|
||||
spec:
|
||||
group: dashboard.cozystack.io
|
||||
names:
|
||||
kind: Breadcrumb
|
||||
listKind: BreadcrumbList
|
||||
plural: breadcrumbs
|
||||
singular: breadcrumb
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
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
|
||||
spec:
|
||||
description: |-
|
||||
ArbitrarySpec holds schemaless user data and preserves unknown fields.
|
||||
We map the entire .spec to a single JSON payload to mirror the CRDs you provided.
|
||||
NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
status:
|
||||
description: CommonStatus is a generic Status block with Kubernetes conditions.
|
||||
properties:
|
||||
conditions:
|
||||
description: Conditions represent the latest available observations
|
||||
of an object's state.
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
observedGeneration:
|
||||
description: ObservedGeneration reflects the most recent generation
|
||||
observed by the controller.
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user