mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-02-14 18:09:58 +00:00
feat(controller): refactor namespace core loop and state management (#1680)
* feat(controller): allow owners to promote serviceaccounts within tenant as owners Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * feat(controller): refactor status handling for tenants and owned namespaces (including metrics) Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> --------- Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
This commit is contained in:
@@ -12,6 +12,7 @@ type NamespaceOptions struct {
|
||||
// Specifies the maximum number of namespaces allowed for that Tenant. Once the namespace quota assigned to the Tenant has been reached, the Tenant owner cannot create further namespaces. Optional.
|
||||
Quota *int32 `json:"quota,omitempty"`
|
||||
// Specifies additional labels and annotations the Capsule operator places on any Namespace resource in the Tenant. Optional.
|
||||
// Deprecated: Use additionalMetadataList instead
|
||||
AdditionalMetadata *api.AdditionalMetadataSpec `json:"additionalMetadata,omitempty"`
|
||||
// Specifies additional labels and annotations the Capsule operator places on any Namespace resource in the Tenant via a list. Optional.
|
||||
AdditionalMetadataList []api.AdditionalMetadataSelectorSpec `json:"additionalMetadataList,omitempty"`
|
||||
@@ -19,4 +20,7 @@ type NamespaceOptions struct {
|
||||
ForbiddenLabels api.ForbiddenListSpec `json:"forbiddenLabels,omitempty"`
|
||||
// Define the annotations that a Tenant Owner cannot set for their Namespace resources.
|
||||
ForbiddenAnnotations api.ForbiddenListSpec `json:"forbiddenAnnotations,omitempty"`
|
||||
// If enabled only metadata from additionalMetadata is reconciled to the namespaces.
|
||||
//+kubebuilder:default:=false
|
||||
ManagedMetadataOnly bool `json:"managedMetadataOnly,omitempty"`
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/projectcapsule/capsule/pkg/meta"
|
||||
)
|
||||
|
||||
// +kubebuilder:validation:Enum=Cordoned;Active
|
||||
type tenantState string
|
||||
|
||||
@@ -18,6 +24,68 @@ type TenantStatus struct {
|
||||
State tenantState `json:"state"`
|
||||
// How many namespaces are assigned to the Tenant.
|
||||
Size uint `json:"size"`
|
||||
// List of namespaces assigned to the Tenant.
|
||||
// List of namespaces assigned to the Tenant. (Deprecated)
|
||||
Namespaces []string `json:"namespaces,omitempty"`
|
||||
// Tracks state for the namespaces associated with this tenant
|
||||
Spaces []*TenantStatusNamespaceItem `json:"spaces,omitempty"`
|
||||
// Tenant Condition
|
||||
Conditions meta.ConditionList `json:"conditions"`
|
||||
}
|
||||
|
||||
type TenantStatusNamespaceItem struct {
|
||||
// Conditions
|
||||
Conditions meta.ConditionList `json:"conditions"`
|
||||
// Namespace Name
|
||||
Name string `json:"name"`
|
||||
// Namespace UID
|
||||
UID k8stypes.UID `json:"uid,omitempty"`
|
||||
// Managed Metadata
|
||||
Metadata *TenantStatusNamespaceMetadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type TenantStatusNamespaceMetadata struct {
|
||||
// Managed Labels
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
// Managed Annotations
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
func (ms *TenantStatus) GetInstance(stat *TenantStatusNamespaceItem) *TenantStatusNamespaceItem {
|
||||
for _, source := range ms.Spaces {
|
||||
if ms.instancequal(source, stat) {
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *TenantStatus) UpdateInstance(stat *TenantStatusNamespaceItem) {
|
||||
// Check if the tenant is already present in the status
|
||||
for i, source := range ms.Spaces {
|
||||
if ms.instancequal(source, stat) {
|
||||
ms.Spaces[i] = stat
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ms.Spaces = append(ms.Spaces, stat)
|
||||
}
|
||||
|
||||
func (ms *TenantStatus) RemoveInstance(stat *TenantStatusNamespaceItem) {
|
||||
// Filter out the datasource with given UID
|
||||
filter := []*TenantStatusNamespaceItem{}
|
||||
|
||||
for _, source := range ms.Spaces {
|
||||
if !ms.instancequal(source, stat) {
|
||||
filter = append(filter, source)
|
||||
}
|
||||
}
|
||||
|
||||
ms.Spaces = filter
|
||||
}
|
||||
|
||||
func (ms *TenantStatus) instancequal(a, b *TenantStatusNamespaceItem) bool {
|
||||
return a.Name == b.Name
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@ type TenantSpec struct {
|
||||
// Specifies the label to control the placement of pods on a given pool of worker nodes. All namespaces created within the Tenant will have the node selector annotation. This annotation tells the Kubernetes scheduler to place pods on the nodes having the selector label. Optional.
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||
// Specifies the NetworkPolicies assigned to the Tenant. The assigned NetworkPolicies are inherited by any namespace created in the Tenant. Optional.
|
||||
// Deprecated: Use Tenant Replications instead (https://projectcapsule.dev/docs/replications/)
|
||||
NetworkPolicies api.NetworkPolicySpec `json:"networkPolicies,omitempty"`
|
||||
// Specifies the resource min/max usage restrictions to the Tenant. The assigned values are inherited by any namespace created in the Tenant. Optional.
|
||||
// Deprecated: Use Tenant Replications instead (https://projectcapsule.dev/docs/replications/)
|
||||
LimitRanges api.LimitRangesSpec `json:"limitRanges,omitempty"`
|
||||
// Specifies a list of ResourceQuota resources assigned to the Tenant. The assigned values are inherited by any namespace created in the Tenant. The Capsule operator aggregates ResourceQuota at Tenant level, so that the hard quota is never crossed for the given Tenant. This permits the Tenant owner to consume resources in the Tenant regardless of the namespace. Optional.
|
||||
ResourceQuota api.ResourceQuotaSpec `json:"resourceQuotas,omitempty"`
|
||||
@@ -74,12 +76,13 @@ type TenantSpec struct {
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:resource:scope=Cluster,shortName=tnt
|
||||
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state",description="The actual state of the Tenant"
|
||||
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.conditions[?(@.type==\"Cordoned\")].reason",description="The actual state of the Tenant"
|
||||
// +kubebuilder:printcolumn:name="Namespace quota",type="integer",JSONPath=".spec.namespaceOptions.quota",description="The max amount of Namespaces can be created"
|
||||
// +kubebuilder:printcolumn:name="Namespace count",type="integer",JSONPath=".status.size",description="The total amount of Namespaces in use"
|
||||
// +kubebuilder:printcolumn:name="Node selector",type="string",JSONPath=".spec.nodeSelector",description="Node Selector applied to Pods"
|
||||
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="Reconcile Status for the tenant"
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="Reconcile Message for the tenant"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age"
|
||||
|
||||
// Tenant is the Schema for the tenants API.
|
||||
type Tenant struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -9,6 +9,7 @@ package v1beta2
|
||||
|
||||
import (
|
||||
"github.com/projectcapsule/capsule/pkg/api"
|
||||
"github.com/projectcapsule/capsule/pkg/meta"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -1215,6 +1216,24 @@ func (in *TenantStatus) DeepCopyInto(out *TenantStatus) {
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Spaces != nil {
|
||||
in, out := &in.Spaces, &out.Spaces
|
||||
*out = make([]*TenantStatusNamespaceItem, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(TenantStatusNamespaceItem)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make(meta.ConditionList, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantStatus.
|
||||
@@ -1226,3 +1245,59 @@ func (in *TenantStatus) DeepCopy() *TenantStatus {
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TenantStatusNamespaceItem) DeepCopyInto(out *TenantStatusNamespaceItem) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make(meta.ConditionList, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Metadata != nil {
|
||||
in, out := &in.Metadata, &out.Metadata
|
||||
*out = new(TenantStatusNamespaceMetadata)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantStatusNamespaceItem.
|
||||
func (in *TenantStatusNamespaceItem) DeepCopy() *TenantStatusNamespaceItem {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TenantStatusNamespaceItem)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TenantStatusNamespaceMetadata) DeepCopyInto(out *TenantStatusNamespaceMetadata) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantStatusNamespaceMetadata.
|
||||
func (in *TenantStatusNamespaceMetadata) DeepCopy() *TenantStatusNamespaceMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TenantStatusNamespaceMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user