diff --git a/controllers/application/PROJECT b/controllers/application/PROJECT index fe4ddbc69d..6b9090ac7a 100644 --- a/controllers/application/PROJECT +++ b/controllers/application/PROJECT @@ -19,7 +19,16 @@ resources: controller: true domain: laf.dev group: application - kind: Specification + kind: Bundle + path: github.com/labring/laf/controllers/application/api/v1 + version: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: laf.dev + group: application + kind: CreationForm path: github.com/labring/laf/controllers/application/api/v1 version: v1 version: "3" diff --git a/controllers/application/api/v1/application_types.go b/controllers/application/api/v1/application_types.go index 255c9cd254..89a3a64744 100644 --- a/controllers/application/api/v1/application_types.go +++ b/controllers/application/api/v1/application_types.go @@ -28,12 +28,12 @@ import ( type ApplicationState string const ( - ApplicationStateCreated ApplicationState = "Created" - ApplicationStateStarted ApplicationState = "Started" - ApplicationStateStopped ApplicationState = "Stopped" - ApplicationStateRunning ApplicationState = "Running" - ApplicationStateRestarted ApplicationState = "Restarted" - ApplicationStateDeleted ApplicationState = "Deleted" + ApplicationStateInitializing ApplicationState = "Initializing" + ApplicationStateInitialized ApplicationState = "Initialized" + ApplicationStateStarting ApplicationState = "Starting" + ApplicationStateRunning ApplicationState = "Running" + ApplicationStateStopping ApplicationState = "Stopping" + ApplicationStateStopped ApplicationState = "Stopped" ) // ApplicationSpec defines the desired state of Application @@ -41,21 +41,15 @@ type ApplicationSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // DisplayName for the application - //+kubebuilder:validation:MinLength=3 - //+kubebuilder:validation:MaxLength=63 - //+kubebuilder:validation:Required - DisplayName string `json:"displayName"` - // State of the application - //+kubebuilder:validation:Enum=Created;Started;Stopped;Running;Restarted;Deleted + //+kubebuilder:validation:Enum=Running;Stopped; //+kubebuilder:validation:Required - //+kubebuilder:default:=Created - State ApplicationState `json:"state"` + //+kubebuilder:default:=Running + State ApplicationState `json:"state,omitempty"` - // Specification Name for the application + // Bundle Name for the application //+kubebuilder:validation:Required - SpecificationName string `json:"specificationName"` + BundleName string `json:"bundleName"` // Runtime Name of the application //+kubebuilder:validation:Required @@ -69,18 +63,33 @@ type ApplicationStatus struct { // AppId //+kubebuilder:validation:MinLength=3 - //+kubebuilder:validation:MaxLength=16 + //+kubebuilder:validation:MaxLength=24 //+kubebuilder:validation:Required AppId string `json:"appid"` - // Specification for the application - Specification SpecificationSpec `json:"specification"` - // State of the application - State ApplicationState `json:"state"` - - // Runtime for the application - Runtime v1.RuntimeSpec `json:"runtime"` + Phase ApplicationState `json:"state,omitempty"` + + // Bundle of the application + Bundle BundleSpec `json:"bundle,omitempty"` + + // Runtime of the application + Runtime v1.RuntimeSpec `json:"runtime,omitempty"` + + // Conditions: + // - type: DatabaseCreated + // status: True | False | Unknown + // reason: "DatabaseCreated" | "InsufficientResources" | "Unknown" + // message: "Database created Successfully" | "Insufficient resources to create database" | "Unknown error" + // - type: ObjectStorageCreated + // - type: GatewayCreated + // - type: InstanceCreated + // - type: InstanceReady + // - type: InstanceDeleted + // - type: DatabaseDeleted + // - type: ObjectStorageDeleted + // - type: GatewayDeleted + Conditions []metav1.Condition `json:"conditions,omitempty"` } //+kubebuilder:object:root=true diff --git a/controllers/application/api/v1/specification_types.go b/controllers/application/api/v1/bundle_types.go similarity index 64% rename from controllers/application/api/v1/specification_types.go rename to controllers/application/api/v1/bundle_types.go index 47a94a0d19..f9dfce54d2 100644 --- a/controllers/application/api/v1/specification_types.go +++ b/controllers/application/api/v1/bundle_types.go @@ -24,51 +24,51 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// SpecificationSpec defines the desired state of Specification -type SpecificationSpec struct { +// BundleSpec defines the desired state of Bundle +type BundleSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // DisplayName for the specification + // DisplayName for the bundle DisplayName string `json:"displayName"` - // Request CPU for the specification + // Request CPU for the bundle RequestCPU resource.Quantity `json:"requestCPU"` - // Request Memory for the specification + // Request Memory for the bundle RequestMemory resource.Quantity `json:"requestMemory"` - // Limit CPU for the specification + // Limit CPU for the bundle LimitCPU resource.Quantity `json:"limitCPU"` - // Limit Memory for the specification + // Limit Memory for the bundle LimitMemory resource.Quantity `json:"limitMemory"` - // Database capacity for the specification + // Database capacity for the bundle DatabaseCapacity resource.Quantity `json:"databaseCapacity"` - // Storage capacity for the specification + // Storage capacity for the bundle StorageCapacity resource.Quantity `json:"storageCapacity"` - // Network Bandwidth Outbound for the specification + // Network Bandwidth Outbound for the bundle NetworkBandwidthOutbound resource.Quantity `json:"networkBandwidthOutbound,omitempty"` - // Network Bandwidth Inbound for the specification + // Network Bandwidth Inbound for the bundle NetworkBandwidthInbound resource.Quantity `json:"networkBandwidthInbound,omitempty"` - // Network Traffic Outbound for the specification + // Network Traffic Outbound for the bundle NetworkTrafficOutbound resource.Quantity `json:"networkTrafficOutbound"` - // Priority for the specification. - // The default value is 0, which means that the specification is not currently available for creating new applications. + // Priority for the bundle. + // The default value is 0, which means that the bundle is not currently available for creating new applications. //+kubebuilder:validation:Minimum=0 //+kubebuilder:validation:Maximum=1000 //+kubebuilder:validation:Default=10 Priority int32 `json:"priority"` } -// SpecificationStatus defines the observed state of Specification -type SpecificationStatus struct { +// BundleStatus defines the observed state of Bundle +type BundleStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file } @@ -76,24 +76,24 @@ type SpecificationStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status -// Specification is the Schema for the specifications API -type Specification struct { +// Bundle is the Schema for the bundles API +type Bundle struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec SpecificationSpec `json:"spec,omitempty"` - Status SpecificationStatus `json:"status,omitempty"` + Spec BundleSpec `json:"spec,omitempty"` + Status BundleStatus `json:"status,omitempty"` } //+kubebuilder:object:root=true -// SpecificationList contains a list of Specification -type SpecificationList struct { +// BundleList contains a list of Bundle +type BundleList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []Specification `json:"items"` + Items []Bundle `json:"items"` } func init() { - SchemeBuilder.Register(&Specification{}, &SpecificationList{}) + SchemeBuilder.Register(&Bundle{}, &BundleList{}) } diff --git a/controllers/application/api/v1/creationform_types.go b/controllers/application/api/v1/creationform_types.go new file mode 100644 index 0000000000..68f75b26b1 --- /dev/null +++ b/controllers/application/api/v1/creationform_types.go @@ -0,0 +1,81 @@ +/* +Copyright 2022. + +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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// CreationFormSpec defines the desired state of CreationForm +type CreationFormSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // DisplayName for the application + //+kubebuilder:validation:MinLength=3 + //+kubebuilder:validation:MaxLength=63 + //+kubebuilder:validation:Required + DisplayName string `json:"displayName"` + + // Bundle Name for the application + //+kubebuilder:validation:Required + BundleName string `json:"bundleName"` + + // Runtime Name of the application + //+kubebuilder:validation:Required + RuntimeName string `json:"runtimeName"` +} + +// CreationFormStatus defines the observed state of CreationForm +type CreationFormStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + AppId string `json:"appid,omitempty"` + + Namespace string `json:"namespace,omitempty"` + + Created bool `json:"created,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// CreationForm is the Schema for the creationforms API +type CreationForm struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CreationFormSpec `json:"spec,omitempty"` + Status CreationFormStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// CreationFormList contains a list of CreationForm +type CreationFormList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CreationForm `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CreationForm{}, &CreationFormList{}) +} diff --git a/controllers/application/api/v1/zz_generated.deepcopy.go b/controllers/application/api/v1/zz_generated.deepcopy.go index 23420191b6..5a6c2ce60b 100644 --- a/controllers/application/api/v1/zz_generated.deepcopy.go +++ b/controllers/application/api/v1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -102,8 +103,15 @@ func (in *ApplicationSpec) DeepCopy() *ApplicationSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) { *out = *in - in.Specification.DeepCopyInto(&out.Specification) - out.Runtime = in.Runtime + in.Bundle.DeepCopyInto(&out.Bundle) + in.Runtime.DeepCopyInto(&out.Runtime) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationStatus. @@ -117,7 +125,7 @@ func (in *ApplicationStatus) DeepCopy() *ApplicationStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Specification) DeepCopyInto(out *Specification) { +func (in *Bundle) DeepCopyInto(out *Bundle) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -125,18 +133,18 @@ func (in *Specification) DeepCopyInto(out *Specification) { out.Status = in.Status } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Specification. -func (in *Specification) DeepCopy() *Specification { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bundle. +func (in *Bundle) DeepCopy() *Bundle { if in == nil { return nil } - out := new(Specification) + out := new(Bundle) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Specification) DeepCopyObject() runtime.Object { +func (in *Bundle) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -144,31 +152,31 @@ func (in *Specification) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SpecificationList) DeepCopyInto(out *SpecificationList) { +func (in *BundleList) DeepCopyInto(out *BundleList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Specification, len(*in)) + *out = make([]Bundle, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpecificationList. -func (in *SpecificationList) DeepCopy() *SpecificationList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleList. +func (in *BundleList) DeepCopy() *BundleList { if in == nil { return nil } - out := new(SpecificationList) + out := new(BundleList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SpecificationList) DeepCopyObject() runtime.Object { +func (in *BundleList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -176,7 +184,7 @@ func (in *SpecificationList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SpecificationSpec) DeepCopyInto(out *SpecificationSpec) { +func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { *out = *in out.RequestCPU = in.RequestCPU.DeepCopy() out.RequestMemory = in.RequestMemory.DeepCopy() @@ -189,27 +197,116 @@ func (in *SpecificationSpec) DeepCopyInto(out *SpecificationSpec) { out.NetworkTrafficOutbound = in.NetworkTrafficOutbound.DeepCopy() } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpecificationSpec. -func (in *SpecificationSpec) DeepCopy() *SpecificationSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec. +func (in *BundleSpec) DeepCopy() *BundleSpec { + if in == nil { + return nil + } + out := new(BundleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleStatus) DeepCopyInto(out *BundleStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleStatus. +func (in *BundleStatus) DeepCopy() *BundleStatus { + if in == nil { + return nil + } + out := new(BundleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CreationForm) DeepCopyInto(out *CreationForm) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreationForm. +func (in *CreationForm) DeepCopy() *CreationForm { + if in == nil { + return nil + } + out := new(CreationForm) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CreationForm) 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 *CreationFormList) DeepCopyInto(out *CreationFormList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CreationForm, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreationFormList. +func (in *CreationFormList) DeepCopy() *CreationFormList { + if in == nil { + return nil + } + out := new(CreationFormList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CreationFormList) 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 *CreationFormSpec) DeepCopyInto(out *CreationFormSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreationFormSpec. +func (in *CreationFormSpec) DeepCopy() *CreationFormSpec { if in == nil { return nil } - out := new(SpecificationSpec) + out := new(CreationFormSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SpecificationStatus) DeepCopyInto(out *SpecificationStatus) { +func (in *CreationFormStatus) DeepCopyInto(out *CreationFormStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpecificationStatus. -func (in *SpecificationStatus) DeepCopy() *SpecificationStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreationFormStatus. +func (in *CreationFormStatus) DeepCopy() *CreationFormStatus { if in == nil { return nil } - out := new(SpecificationStatus) + out := new(CreationFormStatus) in.DeepCopyInto(out) return out } diff --git a/controllers/application/config/crd/bases/application.laf.dev_applications.yaml b/controllers/application/config/crd/bases/application.laf.dev_applications.yaml index d551776873..08417c9170 100644 --- a/controllers/application/config/crd/bases/application.laf.dev_applications.yaml +++ b/controllers/application/config/crd/bases/application.laf.dev_applications.yaml @@ -35,109 +35,83 @@ spec: spec: description: ApplicationSpec defines the desired state of Application properties: - displayName: - description: DisplayName for the application - maxLength: 63 - minLength: 3 + bundleName: + description: Bundle Name for the application type: string runtimeName: description: Runtime Name of the application type: string - specificationName: - description: Specification Name for the application - type: string state: - default: Created + default: Running description: State of the application enum: - - Created - - Started - - Stopped - Running - - Restarted - - Deleted + - Stopped type: string required: - - displayName + - bundleName - runtimeName - - specificationName - - state type: object status: description: ApplicationStatus defines the observed state of Application properties: appid: description: AppId - maxLength: 16 + maxLength: 24 minLength: 3 type: string - runtime: - description: Runtime for the application - properties: - image: - description: Image is the container image to use for the runtime - type: string - type: - description: Type of the runtime - type: string - version: - description: Version is the version of the runtime - type: string - required: - - type - type: object - specification: - description: Specification for the application + bundle: + description: Bundle of the application properties: databaseCapacity: anyOf: - type: integer - type: string - description: Database capacity for the specification + description: Database capacity for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true displayName: - description: DisplayName for the specification + description: DisplayName for the bundle type: string limitCPU: anyOf: - type: integer - type: string - description: Limit CPU for the specification + description: Limit CPU for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true limitMemory: anyOf: - type: integer - type: string - description: Limit Memory for the specification + description: Limit Memory for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkBandwidthInbound: anyOf: - type: integer - type: string - description: Network Bandwidth Inbound for the specification + description: Network Bandwidth Inbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkBandwidthOutbound: anyOf: - type: integer - type: string - description: Network Bandwidth Outbound for the specification + description: Network Bandwidth Outbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkTrafficOutbound: anyOf: - type: integer - type: string - description: Network Traffic Outbound for the specification + description: Network Traffic Outbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true priority: - description: Priority for the specification. The default value - is 0, which means that the specification is not currently available - for creating new applications. + description: Priority for the bundle. The default value is 0, + which means that the bundle is not currently available for creating + new applications. format: int32 maximum: 1000 minimum: 0 @@ -146,21 +120,21 @@ spec: anyOf: - type: integer - type: string - description: Request CPU for the specification + description: Request CPU for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true requestMemory: anyOf: - type: integer - type: string - description: Request Memory for the specification + description: Request Memory for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true storageCapacity: anyOf: - type: integer - type: string - description: Storage capacity for the specification + description: Storage capacity for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true required: @@ -174,14 +148,141 @@ spec: - requestMemory - storageCapacity type: object + conditions: + description: 'Conditions: - type: DatabaseCreated status: True | False + | Unknown reason: "DatabaseCreated" | "InsufficientResources" | + "Unknown" message: "Database created Successfully" | "Insufficient + resources to create database" | "Unknown error" - type: ObjectStorageCreated + - type: GatewayCreated - type: InstanceCreated - type: InstanceReady + - type: InstanceDeleted - type: DatabaseDeleted - type: ObjectStorageDeleted + - type: GatewayDeleted' + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a foo's + current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + runtime: + description: Runtime of the application + properties: + deprecated: + description: Deprecated + type: boolean + image: + description: Images of the runtime + properties: + init: + description: Init image + type: string + main: + description: Main image + type: string + sidecar: + description: Sidecar image + type: string + required: + - main + type: object + type: + description: Type of the runtime. eg. node:laf, node:tcb, go:laf, + python:laf, php:laf, etc. + type: string + versions: + description: Version of the runtime + properties: + autoUpgradeFrom: + description: Versions that should auto upgrade from + items: + type: string + type: array + breakBefore: + description: Version that is breaking from + type: string + mustUpgradeFrom: + description: Versions that must upgrade from + items: + type: string + type: array + upgradeFrom: + description: Versions that suggested to upgrade from + items: + type: string + type: array + version: + description: Version is the version of the runtime + type: string + type: object + required: + - image + - type + - versions + type: object state: description: State of the application type: string required: - appid - - runtime - - specification - - state type: object type: object served: true diff --git a/controllers/application/config/crd/bases/application.laf.dev_specifications.yaml b/controllers/application/config/crd/bases/application.laf.dev_bundles.yaml similarity index 78% rename from controllers/application/config/crd/bases/application.laf.dev_specifications.yaml rename to controllers/application/config/crd/bases/application.laf.dev_bundles.yaml index ca431a7244..035ee23839 100644 --- a/controllers/application/config/crd/bases/application.laf.dev_specifications.yaml +++ b/controllers/application/config/crd/bases/application.laf.dev_bundles.yaml @@ -5,20 +5,20 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.9.0 creationTimestamp: null - name: specifications.application.laf.dev + name: bundles.application.laf.dev spec: group: application.laf.dev names: - kind: Specification - listKind: SpecificationList - plural: specifications - singular: specification + kind: Bundle + listKind: BundleList + plural: bundles + singular: bundle scope: Namespaced versions: - name: v1 schema: openAPIV3Schema: - description: Specification is the Schema for the specifications API + description: Bundle is the Schema for the bundles API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -33,57 +33,57 @@ spec: metadata: type: object spec: - description: SpecificationSpec defines the desired state of Specification + description: BundleSpec defines the desired state of Bundle properties: databaseCapacity: anyOf: - type: integer - type: string - description: Database capacity for the specification + description: Database capacity for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true displayName: - description: DisplayName for the specification + description: DisplayName for the bundle type: string limitCPU: anyOf: - type: integer - type: string - description: Limit CPU for the specification + description: Limit CPU for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true limitMemory: anyOf: - type: integer - type: string - description: Limit Memory for the specification + description: Limit Memory for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkBandwidthInbound: anyOf: - type: integer - type: string - description: Network Bandwidth Inbound for the specification + description: Network Bandwidth Inbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkBandwidthOutbound: anyOf: - type: integer - type: string - description: Network Bandwidth Outbound for the specification + description: Network Bandwidth Outbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true networkTrafficOutbound: anyOf: - type: integer - type: string - description: Network Traffic Outbound for the specification + description: Network Traffic Outbound for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true priority: - description: Priority for the specification. The default value is - 0, which means that the specification is not currently available - for creating new applications. + description: Priority for the bundle. The default value is 0, which + means that the bundle is not currently available for creating new + applications. format: int32 maximum: 1000 minimum: 0 @@ -92,21 +92,21 @@ spec: anyOf: - type: integer - type: string - description: Request CPU for the specification + description: Request CPU for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true requestMemory: anyOf: - type: integer - type: string - description: Request Memory for the specification + description: Request Memory for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true storageCapacity: anyOf: - type: integer - type: string - description: Storage capacity for the specification + description: Storage capacity for the bundle pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true required: @@ -121,7 +121,7 @@ spec: - storageCapacity type: object status: - description: SpecificationStatus defines the observed state of Specification + description: BundleStatus defines the observed state of Bundle type: object type: object served: true diff --git a/controllers/application/config/crd/bases/application.laf.dev_creationforms.yaml b/controllers/application/config/crd/bases/application.laf.dev_creationforms.yaml new file mode 100644 index 0000000000..c6aca40120 --- /dev/null +++ b/controllers/application/config/crd/bases/application.laf.dev_creationforms.yaml @@ -0,0 +1,68 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: creationforms.application.laf.dev +spec: + group: application.laf.dev + names: + kind: CreationForm + listKind: CreationFormList + plural: creationforms + singular: creationform + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: CreationForm is the Schema for the creationforms API + 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: CreationFormSpec defines the desired state of CreationForm + properties: + bundleName: + description: Bundle Name for the application + type: string + displayName: + description: DisplayName for the application + maxLength: 63 + minLength: 3 + type: string + runtimeName: + description: Runtime Name of the application + type: string + required: + - bundleName + - displayName + - runtimeName + type: object + status: + description: CreationFormStatus defines the observed state of CreationForm + properties: + appid: + type: string + created: + type: boolean + namespace: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/controllers/application/config/crd/kustomization.yaml b/controllers/application/config/crd/kustomization.yaml index a10646998c..104aba84db 100644 --- a/controllers/application/config/crd/kustomization.yaml +++ b/controllers/application/config/crd/kustomization.yaml @@ -3,32 +3,23 @@ # It should be run by config/default resources: - bases/application.laf.dev_applications.yaml -- bases/application.laf.dev_specifications.yaml -- bases/application.laf.dev_runtimes.yaml -- bases/application.laf.dev_runtimepackages.yaml -- bases/application.laf.dev_cloudfunctions.yaml -- bases/application.laf.dev_triggers.yaml +- bases/application.laf.dev_bundles.yaml +- bases/application.laf.dev_creationforms.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD #- patches/webhook_in_applications.yaml -#- patches/webhook_in_specifications.yaml -#- patches/webhook_in_runtimes.yaml -#- patches/webhook_in_runtimepackages.yaml -#- patches/webhook_in_cloudfunctions.yaml -#- patches/webhook_in_triggers.yaml +#- patches/webhook_in_bundles.yaml +#- patches/webhook_in_creationforms.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD #- patches/cainjection_in_applications.yaml -#- patches/cainjection_in_specifications.yaml -#- patches/cainjection_in_runtimes.yaml -#- patches/cainjection_in_runtimepackages.yaml -#- patches/cainjection_in_cloudfunctions.yaml -#- patches/cainjection_in_triggers.yaml +#- patches/cainjection_in_bundles.yaml +#- patches/cainjection_in_creationforms.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/controllers/application/config/crd/patches/cainjection_in_bundles.yaml b/controllers/application/config/crd/patches/cainjection_in_bundles.yaml new file mode 100644 index 0000000000..27a809f9b1 --- /dev/null +++ b/controllers/application/config/crd/patches/cainjection_in_bundles.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: bundles.application.laf.dev diff --git a/controllers/application/config/crd/patches/cainjection_in_creationforms.yaml b/controllers/application/config/crd/patches/cainjection_in_creationforms.yaml new file mode 100644 index 0000000000..20041ea07f --- /dev/null +++ b/controllers/application/config/crd/patches/cainjection_in_creationforms.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: creationforms.application.laf.dev diff --git a/controllers/application/config/crd/patches/webhook_in_bundles.yaml b/controllers/application/config/crd/patches/webhook_in_bundles.yaml new file mode 100644 index 0000000000..1902583992 --- /dev/null +++ b/controllers/application/config/crd/patches/webhook_in_bundles.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bundles.application.laf.dev +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/controllers/application/config/crd/patches/webhook_in_creationforms.yaml b/controllers/application/config/crd/patches/webhook_in_creationforms.yaml new file mode 100644 index 0000000000..04071fb17c --- /dev/null +++ b/controllers/application/config/crd/patches/webhook_in_creationforms.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: creationforms.application.laf.dev +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/controllers/application/config/rbac/runtime_editor_role.yaml b/controllers/application/config/rbac/bundle_editor_role.yaml similarity index 71% rename from controllers/application/config/rbac/runtime_editor_role.yaml rename to controllers/application/config/rbac/bundle_editor_role.yaml index 77d9600f01..29d76e26eb 100644 --- a/controllers/application/config/rbac/runtime_editor_role.yaml +++ b/controllers/application/config/rbac/bundle_editor_role.yaml @@ -1,13 +1,13 @@ -# permissions for end users to edit runtimes. +# permissions for end users to edit bundles. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: runtime-editor-role + name: bundle-editor-role rules: - apiGroups: - application.laf.dev resources: - - runtimes + - bundles verbs: - create - delete @@ -19,6 +19,6 @@ rules: - apiGroups: - application.laf.dev resources: - - runtimes/status + - bundles/status verbs: - get diff --git a/controllers/application/config/rbac/runtime_viewer_role.yaml b/controllers/application/config/rbac/bundle_viewer_role.yaml similarity index 68% rename from controllers/application/config/rbac/runtime_viewer_role.yaml rename to controllers/application/config/rbac/bundle_viewer_role.yaml index d29e3a9553..56fdd09515 100644 --- a/controllers/application/config/rbac/runtime_viewer_role.yaml +++ b/controllers/application/config/rbac/bundle_viewer_role.yaml @@ -1,13 +1,13 @@ -# permissions for end users to view runtimes. +# permissions for end users to view bundles. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: runtime-viewer-role + name: bundle-viewer-role rules: - apiGroups: - application.laf.dev resources: - - runtimes + - bundles verbs: - get - list @@ -15,6 +15,6 @@ rules: - apiGroups: - application.laf.dev resources: - - runtimes/status + - bundles/status verbs: - get diff --git a/controllers/application/config/rbac/cloudfunction_editor_role.yaml b/controllers/application/config/rbac/cloudfunction_editor_role.yaml deleted file mode 100644 index 27b1deeb09..0000000000 --- a/controllers/application/config/rbac/cloudfunction_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit cloudfunctions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: cloudfunction-editor-role -rules: -- apiGroups: - - application.laf.dev - resources: - - cloudfunctions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - application.laf.dev - resources: - - cloudfunctions/status - verbs: - - get diff --git a/controllers/application/config/rbac/cloudfunction_viewer_role.yaml b/controllers/application/config/rbac/cloudfunction_viewer_role.yaml deleted file mode 100644 index e9231415b5..0000000000 --- a/controllers/application/config/rbac/cloudfunction_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view cloudfunctions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: cloudfunction-viewer-role -rules: -- apiGroups: - - application.laf.dev - resources: - - cloudfunctions - verbs: - - get - - list - - watch -- apiGroups: - - application.laf.dev - resources: - - cloudfunctions/status - verbs: - - get diff --git a/controllers/application/config/rbac/trigger_editor_role.yaml b/controllers/application/config/rbac/creationform_editor_role.yaml similarity index 68% rename from controllers/application/config/rbac/trigger_editor_role.yaml rename to controllers/application/config/rbac/creationform_editor_role.yaml index efe729e437..e2878cf25b 100644 --- a/controllers/application/config/rbac/trigger_editor_role.yaml +++ b/controllers/application/config/rbac/creationform_editor_role.yaml @@ -1,13 +1,13 @@ -# permissions for end users to edit triggers. +# permissions for end users to edit creationforms. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: trigger-editor-role + name: creationform-editor-role rules: - apiGroups: - application.laf.dev resources: - - triggers + - creationforms verbs: - create - delete @@ -19,6 +19,6 @@ rules: - apiGroups: - application.laf.dev resources: - - triggers/status + - creationforms/status verbs: - get diff --git a/controllers/application/config/rbac/trigger_viewer_role.yaml b/controllers/application/config/rbac/creationform_viewer_role.yaml similarity index 64% rename from controllers/application/config/rbac/trigger_viewer_role.yaml rename to controllers/application/config/rbac/creationform_viewer_role.yaml index c156cce43e..435823a36c 100644 --- a/controllers/application/config/rbac/trigger_viewer_role.yaml +++ b/controllers/application/config/rbac/creationform_viewer_role.yaml @@ -1,13 +1,13 @@ -# permissions for end users to view triggers. +# permissions for end users to view creationforms. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: trigger-viewer-role + name: creationform-viewer-role rules: - apiGroups: - application.laf.dev resources: - - triggers + - creationforms verbs: - get - list @@ -15,6 +15,6 @@ rules: - apiGroups: - application.laf.dev resources: - - triggers/status + - creationforms/status verbs: - get diff --git a/controllers/application/config/rbac/role.yaml b/controllers/application/config/rbac/role.yaml index 904cb43e21..f3f76671f2 100644 --- a/controllers/application/config/rbac/role.yaml +++ b/controllers/application/config/rbac/role.yaml @@ -34,7 +34,7 @@ rules: - apiGroups: - application.laf.dev resources: - - specifications + - bundles verbs: - create - delete @@ -46,13 +46,39 @@ rules: - apiGroups: - application.laf.dev resources: - - specifications/finalizers + - bundles/finalizers verbs: - update - apiGroups: - application.laf.dev resources: - - specifications/status + - bundles/status + verbs: + - get + - patch + - update +- apiGroups: + - application.laf.dev + resources: + - creationforms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - application.laf.dev + resources: + - creationforms/finalizers + verbs: + - update +- apiGroups: + - application.laf.dev + resources: + - creationforms/status verbs: - get - patch diff --git a/controllers/application/config/rbac/runtimepackage_editor_role.yaml b/controllers/application/config/rbac/runtimepackage_editor_role.yaml deleted file mode 100644 index 9c55f3ed9f..0000000000 --- a/controllers/application/config/rbac/runtimepackage_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit runtimepackages. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: runtimepackage-editor-role -rules: -- apiGroups: - - application.laf.dev - resources: - - runtimepackages - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - application.laf.dev - resources: - - runtimepackages/status - verbs: - - get diff --git a/controllers/application/config/rbac/runtimepackage_viewer_role.yaml b/controllers/application/config/rbac/runtimepackage_viewer_role.yaml deleted file mode 100644 index 63bbf3b2bb..0000000000 --- a/controllers/application/config/rbac/runtimepackage_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view runtimepackages. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: runtimepackage-viewer-role -rules: -- apiGroups: - - application.laf.dev - resources: - - runtimepackages - verbs: - - get - - list - - watch -- apiGroups: - - application.laf.dev - resources: - - runtimepackages/status - verbs: - - get diff --git a/controllers/application/config/rbac/specification_editor_role.yaml b/controllers/application/config/rbac/specification_editor_role.yaml deleted file mode 100644 index 68ffe767a9..0000000000 --- a/controllers/application/config/rbac/specification_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit specifications. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: specification-editor-role -rules: -- apiGroups: - - application.laf.dev - resources: - - specifications - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - application.laf.dev - resources: - - specifications/status - verbs: - - get diff --git a/controllers/application/config/rbac/specification_viewer_role.yaml b/controllers/application/config/rbac/specification_viewer_role.yaml deleted file mode 100644 index 1c6e2000fe..0000000000 --- a/controllers/application/config/rbac/specification_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view specifications. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: specification-viewer-role -rules: -- apiGroups: - - application.laf.dev - resources: - - specifications - verbs: - - get - - list - - watch -- apiGroups: - - application.laf.dev - resources: - - specifications/status - verbs: - - get diff --git a/controllers/application/config/samples/application_v1_specification.yaml b/controllers/application/config/samples/application_v1_bundle.yaml similarity index 69% rename from controllers/application/config/samples/application_v1_specification.yaml rename to controllers/application/config/samples/application_v1_bundle.yaml index 70ac97a1e9..44931af632 100644 --- a/controllers/application/config/samples/application_v1_specification.yaml +++ b/controllers/application/config/samples/application_v1_bundle.yaml @@ -1,9 +1,9 @@ apiVersion: application.laf.dev/v1 -kind: Specification +kind: Bundle metadata: - name: standard-specification + name: bundle-sample spec: - displayName: "My Application" + displayName: "Standard" requestCPU: "500m" requestMemory: "128Mi" limitCPU: "1000m" @@ -11,4 +11,4 @@ spec: databaseCapacity: "1Gi" storageCapacity: "1Gi" networkTrafficOutbound: "1Gi" - priority: 10 \ No newline at end of file + priority: 10 diff --git a/controllers/application/config/samples/application_v1_creationform.yaml b/controllers/application/config/samples/application_v1_creationform.yaml new file mode 100644 index 0000000000..19f294e6e1 --- /dev/null +++ b/controllers/application/config/samples/application_v1_creationform.yaml @@ -0,0 +1,8 @@ +apiVersion: application.laf.dev/v1 +kind: CreationForm +metadata: + name: creationform-sample +spec: + displayName: "Sample Application Name" + bundleName: "bundle-sample" + runtimeName: "runtime-sample" diff --git a/controllers/application/controllers/application_controller.go b/controllers/application/controllers/application_controller.go index faf4d44cbc..54cb8a9495 100644 --- a/controllers/application/controllers/application_controller.go +++ b/controllers/application/controllers/application_controller.go @@ -27,6 +27,8 @@ import ( applicationv1 "github.com/labring/laf/controllers/application/api/v1" ) +const ApplicationFinalizer = "application.finalizers.laf.dev" + // ApplicationReconciler reconciles a Application object type ApplicationReconciler struct { client.Client diff --git a/controllers/application/controllers/specification_controller.go b/controllers/application/controllers/bundle_controller.go similarity index 52% rename from controllers/application/controllers/specification_controller.go rename to controllers/application/controllers/bundle_controller.go index 4357550573..e7845663bf 100644 --- a/controllers/application/controllers/specification_controller.go +++ b/controllers/application/controllers/bundle_controller.go @@ -28,81 +28,81 @@ import ( applicationv1 "github.com/labring/laf/controllers/application/api/v1" ) -const finalizerName = "spec.application.laf.dev" +const finalizerName = "bundle.application.laf.dev" -// SpecificationReconciler reconciles a Specification object -type SpecificationReconciler struct { +// BundleReconciler reconciles a Bundle object +type BundleReconciler struct { client.Client Scheme *runtime.Scheme } -//+kubebuilder:rbac:groups=application.laf.dev,resources=specifications,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=application.laf.dev,resources=specifications/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=application.laf.dev,resources=specifications/finalizers,verbs=update +//+kubebuilder:rbac:groups=application.laf.dev,resources=bundles,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=application.laf.dev,resources=bundles/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=application.laf.dev,resources=bundles/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. // TODO(user): Modify the Reconcile function to compare the state specified by -// the Specification object against the actual cluster state, and then +// the Bundle object against the actual cluster state, and then // perform operations to make the cluster state reflect the state specified by // the user. // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile -func (r *SpecificationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *BundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) - // get the specification - specification := &applicationv1.Specification{} - err := r.Get(ctx, req.NamespacedName, specification) + // get the bundle + bundle := &applicationv1.Bundle{} + err := r.Get(ctx, req.NamespacedName, bundle) if err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } // reconcile deletions - if !specification.ObjectMeta.DeletionTimestamp.IsZero() { - return r.delete(ctx, specification) + if !bundle.ObjectMeta.DeletionTimestamp.IsZero() { + return r.delete(ctx, bundle) } - return r.apply(ctx, specification) + return r.apply(ctx, bundle) } // apply the specification -func (r *SpecificationReconciler) apply(ctx context.Context, specification *applicationv1.Specification) (ctrl.Result, error) { +func (r *BundleReconciler) apply(ctx context.Context, bundle *applicationv1.Bundle) (ctrl.Result, error) { _log := log.FromContext(ctx) // add finalizer - if !util.ContainsString(specification.ObjectMeta.Finalizers, finalizerName) { - specification.ObjectMeta.Finalizers = append(specification.ObjectMeta.Finalizers, finalizerName) - err := r.Update(ctx, specification) + if !util.ContainsString(bundle.ObjectMeta.Finalizers, finalizerName) { + bundle.ObjectMeta.Finalizers = append(bundle.ObjectMeta.Finalizers, finalizerName) + err := r.Update(ctx, bundle) if err != nil { return ctrl.Result{}, err } - _log.Info("finalizer added for specification", "specification", specification.Name) + _log.Info("finalizer added for bundle", "bundle", bundle.Name) } return ctrl.Result{}, nil } // delete the specification -func (r *SpecificationReconciler) delete(ctx context.Context, specification *applicationv1.Specification) (ctrl.Result, error) { +func (r *BundleReconciler) delete(ctx context.Context, bundle *applicationv1.Bundle) (ctrl.Result, error) { _log := log.FromContext(ctx) // TODO: reject it if there are any applications using it // remove finalizer - specification.ObjectMeta.Finalizers = util.RemoveString(specification.ObjectMeta.Finalizers, finalizerName) - err := r.Update(ctx, specification) + bundle.ObjectMeta.Finalizers = util.RemoveString(bundle.ObjectMeta.Finalizers, finalizerName) + err := r.Update(ctx, bundle) if err != nil { return ctrl.Result{}, err } - _log.Info("finalizer removed for specification", "specification", specification.Name) + _log.Info("finalizer removed for bundle", "bundle", bundle.Name) return ctrl.Result{}, nil } // SetupWithManager sets up the controller with the Manager. -func (r *SpecificationReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *BundleReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&applicationv1.Specification{}). + For(&applicationv1.Bundle{}). Complete(r) } diff --git a/controllers/application/controllers/creationform_controller.go b/controllers/application/controllers/creationform_controller.go new file mode 100644 index 0000000000..3a89ed1c3f --- /dev/null +++ b/controllers/application/controllers/creationform_controller.go @@ -0,0 +1,204 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + applicationv1 "github.com/labring/laf/controllers/application/api/v1" + gonanoid "github.com/matoous/go-nanoid/v2" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "laf/pkg/util" + "os" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "strconv" +) + +const creationFormFinalizer = "creationform.finalizers.laf.dev" + +// CreationFormReconciler reconciles a CreationForm object +type CreationFormReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=application.laf.dev,resources=creationforms,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=application.laf.dev,resources=creationforms/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=application.laf.dev,resources=creationforms/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the CreationForm object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *CreationFormReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // get the form + form := &applicationv1.CreationForm{} + if err := r.Get(ctx, req.NamespacedName, form); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // reconcile deletion + if !form.ObjectMeta.DeletionTimestamp.IsZero() { + return r.delete(ctx, form) + } + + return r.apply(ctx, form) +} + +// apply the form +func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.CreationForm) (ctrl.Result, error) { + log := log.FromContext(ctx) + + // add finalizer if not present + if !util.ContainsString(form.ObjectMeta.Finalizers, creationFormFinalizer) { + form.ObjectMeta.Finalizers = append(form.ObjectMeta.Finalizers, creationFormFinalizer) + if err := r.Update(ctx, form); err != nil { + return ctrl.Result{}, err + } + + log.Info("Added finalizer to form") + } + + // TODO: validate the form spec: bundle, runtime + + // reconcile the namespace + if form.Status.Namespace == "" { + appid, err := GenerateAppId() + if err != nil { + return ctrl.Result{}, err + } + + // create the namespace + var namespace v1.Namespace + namespace.Name = GetAppNamespacePrefix() + appid + namespace.Labels = map[string]string{ + "laf.dev/appid": appid, + "laf.dev/namespace.type": "app", + } + + if err := r.Create(ctx, &namespace); err != nil { + return ctrl.Result{}, err + } + + log.Info("Created namespace for app") + + form.Status.AppId = appid + form.Status.Namespace = namespace.Name + form.Status.Created = false + if err := r.Status().Update(ctx, form); err != nil { + return ctrl.Result{}, err + } + + log.Info("Updated form status: fill the namespace") + return ctrl.Result{}, nil + } + + // reconcile the created status + if !form.Status.Created { + // create the app + var app applicationv1.Application + app.Namespace = form.Status.Namespace + app.Name = "app" + app.Labels = map[string]string{ + "laf.dev/appid": form.Status.AppId, + } + app.Annotations = map[string]string{ + "laf.dev/name": form.Spec.DisplayName, + } + app.Spec.State = applicationv1.ApplicationStateRunning + app.Spec.BundleName = form.Spec.BundleName + app.Spec.RuntimeName = form.Spec.RuntimeName + + if err := r.Create(ctx, &app); err != nil { + return ctrl.Result{}, err + } + + log.Info("Created app") + + form.Status.Created = true + if err := r.Status().Update(ctx, form); err != nil { + return ctrl.Result{}, err + } + + log.Info("Updated form status") + } else { + // delete the form + if err := r.Delete(ctx, form); err != nil { + return ctrl.Result{}, err + } + + log.Info("Deleted form") + } + + return ctrl.Result{}, nil +} + +// delete the form +func (r *CreationFormReconciler) delete(ctx context.Context, form *applicationv1.CreationForm) (ctrl.Result, error) { + log := log.FromContext(ctx) + + // remove finalizer + form.ObjectMeta.Finalizers = util.RemoveString(form.ObjectMeta.Finalizers, creationFormFinalizer) + if err := r.Update(ctx, form); err != nil { + return ctrl.Result{}, err + } + + log.Info("Removed finalizer from form") + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CreationFormReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&applicationv1.CreationForm{}). + Complete(r) +} + +// GetAppNamespacePrefix returns the app namespace prefix +func GetAppNamespacePrefix() string { + prefix := "" + if prefixStr := os.Getenv("APP_NAMESPACE_PREFIX"); prefixStr != "" { + prefix = prefixStr + } + return prefix +} + +// GenerateAppId generates app id +func GenerateAppId() (string, error) { + const alphabet = "23456789abcdefghijklmnopqrstuvwxyz" + size := 6 + + // get size from env + if sizeStr := os.Getenv("APPID_LENGTH"); sizeStr != "" { + int64, err := strconv.ParseInt(sizeStr, 10, 64) + if err == nil { + size = int(int64) + } + } + + appid, err := gonanoid.Generate(alphabet, size) + return appid, err +} diff --git a/controllers/application/controllers/suite_test.go b/controllers/application/controllers/suite_test.go index 0aac9aa70c..cf43b29cc9 100644 --- a/controllers/application/controllers/suite_test.go +++ b/controllers/application/controllers/suite_test.go @@ -22,6 +22,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/controllers/application/main.go b/controllers/application/main.go index 64d1a5a845..c583fb636f 100644 --- a/controllers/application/main.go +++ b/controllers/application/main.go @@ -96,14 +96,21 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Application") os.Exit(1) } - if err = (&controllers.SpecificationReconciler{ + + if err = (&controllers.BundleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Specification") + setupLog.Error(err, "unable to create controller", "controller", "Bundle") + os.Exit(1) + } + if err = (&controllers.CreationFormReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CreationForm") os.Exit(1) } - //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {