feat(api): globaltenantresource and tenantresource support

This commit is contained in:
Dario Tranchitella
2022-10-13 15:51:43 +02:00
parent 360a8d2b56
commit cade41da81
8 changed files with 529 additions and 11 deletions

20
PROJECT
View File

@@ -9,7 +9,6 @@ repo: github.com/clastix/capsule
resources:
- api:
crdVersion: v1
namespaced: false
controller: true
domain: clastix.io
group: capsule
@@ -21,7 +20,6 @@ resources:
webhookVersion: v1
- api:
crdVersion: v1
namespaced: false
controller: true
domain: clastix.io
group: capsule
@@ -30,7 +28,6 @@ resources:
version: v1alpha1
- api:
crdVersion: v1
namespaced: false
domain: clastix.io
group: capsule
kind: Tenant
@@ -38,7 +35,6 @@ resources:
version: v1beta1
- api:
crdVersion: v1
namespaced: false
domain: clastix.io
group: capsule
kind: Tenant
@@ -46,11 +42,25 @@ resources:
version: v1beta2
- api:
crdVersion: v1
namespaced: false
controller: true
domain: clastix.io
group: capsule
kind: CapsuleConfiguration
path: github.com/clastix/capsule/api/v1beta2
version: v1beta2
- api:
crdVersion: v1
namespaced: true
domain: clastix.io
group: capsule
kind: TenantResource
path: github.com/clastix/capsule/api/v1beta2
version: v1beta2
- api:
crdVersion: v1
domain: clastix.io
group: capsule
kind: GlobalTenantResource
path: github.com/clastix/capsule/api/v1beta2
version: v1beta2
version: "3"

View File

@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
// Package v1beta1 contains API Schema definitions for the capsule v1beta1 API group
//+kubebuilder:object:generate=true
//+groupName=capsule.clastix.io
// +kubebuilder:object:generate=true
// +groupName=capsule.clastix.io
package v1beta1
import (

View File

@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
// Package v1beta2 contains API Schema definitions for the capsule v1beta2 API group
//+kubebuilder:object:generate=true
//+groupName=capsule.clastix.io
// +kubebuilder:object:generate=true
// +groupName=capsule.clastix.io
package v1beta2
import (

View File

@@ -9,10 +9,10 @@ import (
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func GetTypeLabel(t runtime.Object) (label string, err error) {
func GetTypeLabel(t metav1.Object) (label string, err error) {
switch v := t.(type) {
case *Tenant:
return "capsule.clastix.io/tenant", nil

View File

@@ -0,0 +1,49 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package v1beta2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// GlobalTenantResourceSpec defines the desired state of GlobalTenantResource.
type GlobalTenantResourceSpec struct {
// Defines the Tenant selector used target the tenants on which resources must be propagated.
TenantSelector metav1.LabelSelector `json:"tenantSelector,omitempty"`
TenantResourceSpec `json:",inline"`
}
// GlobalTenantResourceStatus defines the observed state of GlobalTenantResource.
type GlobalTenantResourceStatus struct {
// List of Tenants addressed by the GlobalTenantResource.
SelectedTenants []string `json:"selectedTenants"`
// List of the replicated resources for the given TenantResource.
ProcessedItems []ObjectReferenceStatus `json:"processedItems"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster
// GlobalTenantResource allows to propagate resource replications to a specific subset of Tenant resources.
type GlobalTenantResource struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GlobalTenantResourceSpec `json:"spec,omitempty"`
Status GlobalTenantResourceStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// GlobalTenantResourceList contains a list of GlobalTenantResource.
type GlobalTenantResourceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []GlobalTenantResource `json:"items"`
}
func init() {
SchemeBuilder.Register(&GlobalTenantResource{}, &GlobalTenantResourceList{})
}

View File

@@ -0,0 +1,75 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package v1beta2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// TenantResourceSpec defines the desired state of TenantResource.
type TenantResourceSpec struct {
// Define the period of time upon a second reconciliation must be invoked.
// Keep in mind that any change to the manifests will trigger a new reconciliation.
// +kubebuilder:default="60s"
ResyncPeriod metav1.Duration `json:"resyncPeriod"`
// When the replicated resource manifest is deleted, all the objects replicated so far will be automatically deleted.
// Disable this to keep replicated resources although the deletion of the replication manifest.
// +kubebuilder:default=true
PruningOnDelete *bool `json:"pruningOnDelete,omitempty"`
// Defines the rules to select targeting Namespace, along with the objects that must be replicated.
Resources []ResourceSpec `json:"resources"`
}
type ResourceSpec struct {
// Defines the Namespace selector to select the Tenant Namespaces on which the resources must be propagated.
// In case of nil value, all the Tenant Namespaces are targeted.
NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
// List of the resources already existing in other Namespaces that must be replicated.
NamespacedItems []ObjectReference `json:"namespacedItems,omitempty"`
// List of raw resources that must be replicated.
RawItems []RawExtension `json:"rawItems,omitempty"`
// Besides the Capsule metadata required by TenantResource controller, defines additional metadata that must be
// added to the replicated resources.
AdditionalMetadata *AdditionalMetadataSpec `json:"additionalMetadata,omitempty"`
}
// +kubebuilder:validation:XEmbeddedResource
// +kubebuilder:validation:XPreserveUnknownFields
type RawExtension struct {
runtime.RawExtension `json:",inline"`
}
// TenantResourceStatus defines the observed state of TenantResource.
type TenantResourceStatus struct {
// List of the replicated resources for the given TenantResource.
ProcessedItems []ObjectReferenceStatus `json:"processedItems"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// TenantResource allows a Tenant Owner, if enabled with proper RBAC, to propagate resources in its Namespace.
// The object must be deployed in a Tenant Namespace, and cannot reference object living in non-Tenant namespaces.
// For such cases, the GlobalTenantResource must be used.
type TenantResource struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec TenantResourceSpec `json:"spec,omitempty"`
Status TenantResourceStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// TenantResourceList contains a list of TenantResource.
type TenantResourceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TenantResource `json:"items"`
}
func init() {
SchemeBuilder.Register(&TenantResource{}, &TenantResourceList{})
}

View File

@@ -0,0 +1,72 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package v1beta2
import (
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type ObjectReferenceAbstract struct {
// Kind of the referent.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
Kind string `json:"kind"`
// Namespace of the referent.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
Namespace string `json:"namespace"`
// API version of the referent.
APIVersion string `json:"apiVersion,omitempty"`
}
type ObjectReferenceStatus struct {
ObjectReferenceAbstract `json:",inline"`
// Name of the referent.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name string `json:"name"`
}
type ObjectReference struct {
ObjectReferenceAbstract `json:",inline"`
// Label selector used to select the given resources in the given Namespace.
Selector metav1.LabelSelector `json:"selector"`
}
func (in *ObjectReferenceStatus) String() string {
return fmt.Sprintf("Kind=%s,APIVersion=%s,Namespace=%s,Name=%s", in.Kind, in.APIVersion, in.Namespace, in.Name)
}
func (in *ObjectReferenceStatus) ParseFromString(value string) error {
rawParts := strings.Split(value, ",")
if len(rawParts) != 4 {
return fmt.Errorf("unexpected raw parts")
}
for _, i := range rawParts {
parts := strings.Split(i, "=")
if len(parts) != 2 {
return fmt.Errorf("unrecognized separator")
}
k, v := parts[0], parts[1]
switch k {
case "Kind":
in.Kind = v
case "APIVersion":
in.APIVersion = v
case "Namespace":
in.Namespace = v
case "Name":
in.Name = v
default:
return fmt.Errorf("unrecognized marker: %s", k)
}
}
return nil
}

View File

@@ -11,6 +11,7 @@ package v1beta2
import (
"github.com/clastix/capsule/pkg/api"
"k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
@@ -183,6 +184,107 @@ func (in *CapsuleResources) DeepCopy() *CapsuleResources {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GlobalTenantResource) DeepCopyInto(out *GlobalTenantResource) {
*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 GlobalTenantResource.
func (in *GlobalTenantResource) DeepCopy() *GlobalTenantResource {
if in == nil {
return nil
}
out := new(GlobalTenantResource)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GlobalTenantResource) 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 *GlobalTenantResourceList) DeepCopyInto(out *GlobalTenantResourceList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]GlobalTenantResource, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalTenantResourceList.
func (in *GlobalTenantResourceList) DeepCopy() *GlobalTenantResourceList {
if in == nil {
return nil
}
out := new(GlobalTenantResourceList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GlobalTenantResourceList) 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 *GlobalTenantResourceSpec) DeepCopyInto(out *GlobalTenantResourceSpec) {
*out = *in
in.TenantSelector.DeepCopyInto(&out.TenantSelector)
in.TenantResourceSpec.DeepCopyInto(&out.TenantResourceSpec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalTenantResourceSpec.
func (in *GlobalTenantResourceSpec) DeepCopy() *GlobalTenantResourceSpec {
if in == nil {
return nil
}
out := new(GlobalTenantResourceSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GlobalTenantResourceStatus) DeepCopyInto(out *GlobalTenantResourceStatus) {
*out = *in
if in.SelectedTenants != nil {
in, out := &in.SelectedTenants, &out.SelectedTenants
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ProcessedItems != nil {
in, out := &in.ProcessedItems, &out.ProcessedItems
*out = make([]ObjectReferenceStatus, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalTenantResourceStatus.
func (in *GlobalTenantResourceStatus) DeepCopy() *GlobalTenantResourceStatus {
if in == nil {
return nil
}
out := new(GlobalTenantResourceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressOptions) DeepCopyInto(out *IngressOptions) {
*out = *in
@@ -267,6 +369,54 @@ func (in *NonLimitedResourceError) DeepCopy() *NonLimitedResourceError {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectReference) DeepCopyInto(out *ObjectReference) {
*out = *in
out.ObjectReferenceAbstract = in.ObjectReferenceAbstract
in.Selector.DeepCopyInto(&out.Selector)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference.
func (in *ObjectReference) DeepCopy() *ObjectReference {
if in == nil {
return nil
}
out := new(ObjectReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectReferenceAbstract) DeepCopyInto(out *ObjectReferenceAbstract) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReferenceAbstract.
func (in *ObjectReferenceAbstract) DeepCopy() *ObjectReferenceAbstract {
if in == nil {
return nil
}
out := new(ObjectReferenceAbstract)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectReferenceStatus) DeepCopyInto(out *ObjectReferenceStatus) {
*out = *in
out.ObjectReferenceAbstract = in.ObjectReferenceAbstract
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReferenceStatus.
func (in *ObjectReferenceStatus) DeepCopy() *ObjectReferenceStatus {
if in == nil {
return nil
}
out := new(ObjectReferenceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in OwnerListSpec) DeepCopyInto(out *OwnerListSpec) {
{
@@ -335,6 +485,61 @@ func (in *ProxySettings) DeepCopy() *ProxySettings {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RawExtension) DeepCopyInto(out *RawExtension) {
*out = *in
in.RawExtension.DeepCopyInto(&out.RawExtension)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawExtension.
func (in *RawExtension) DeepCopy() *RawExtension {
if in == nil {
return nil
}
out := new(RawExtension)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) {
*out = *in
if in.NamespaceSelector != nil {
in, out := &in.NamespaceSelector, &out.NamespaceSelector
*out = new(metav1.LabelSelector)
(*in).DeepCopyInto(*out)
}
if in.NamespacedItems != nil {
in, out := &in.NamespacedItems, &out.NamespacedItems
*out = make([]ObjectReference, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.RawItems != nil {
in, out := &in.RawItems, &out.RawItems
*out = make([]RawExtension, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AdditionalMetadata != nil {
in, out := &in.AdditionalMetadata, &out.AdditionalMetadata
*out = new(AdditionalMetadataSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec.
func (in *ResourceSpec) DeepCopy() *ResourceSpec {
if in == nil {
return nil
}
out := new(ResourceSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Tenant) DeepCopyInto(out *Tenant) {
*out = *in
@@ -394,6 +599,113 @@ func (in *TenantList) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantResource) DeepCopyInto(out *TenantResource) {
*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 TenantResource.
func (in *TenantResource) DeepCopy() *TenantResource {
if in == nil {
return nil
}
out := new(TenantResource)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantResource) 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 *TenantResourceList) DeepCopyInto(out *TenantResourceList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]TenantResource, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantResourceList.
func (in *TenantResourceList) DeepCopy() *TenantResourceList {
if in == nil {
return nil
}
out := new(TenantResourceList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TenantResourceList) 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 *TenantResourceSpec) DeepCopyInto(out *TenantResourceSpec) {
*out = *in
out.ResyncPeriod = in.ResyncPeriod
if in.PruningOnDelete != nil {
in, out := &in.PruningOnDelete, &out.PruningOnDelete
*out = new(bool)
**out = **in
}
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = make([]ResourceSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantResourceSpec.
func (in *TenantResourceSpec) DeepCopy() *TenantResourceSpec {
if in == nil {
return nil
}
out := new(TenantResourceSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantResourceStatus) DeepCopyInto(out *TenantResourceStatus) {
*out = *in
if in.ProcessedItems != nil {
in, out := &in.ProcessedItems, &out.ProcessedItems
*out = make([]ObjectReferenceStatus, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantResourceStatus.
func (in *TenantResourceStatus) DeepCopy() *TenantResourceStatus {
if in == nil {
return nil
}
out := new(TenantResourceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
*out = *in