refactor: grouping Ingress options into defined struct

This commit is contained in:
Dario Tranchitella
2021-07-30 17:11:09 +02:00
parent 82480f3afd
commit b749e34547
12 changed files with 86 additions and 50 deletions

View File

@@ -171,13 +171,19 @@ func (t *Tenant) ConvertTo(dstRaw conversion.Hub) error {
}
}
if t.Spec.IngressClasses != nil {
dst.Spec.IngressClasses = &capsulev1beta1.AllowedListSpec{
if dst.Spec.IngressOptions == nil {
dst.Spec.IngressOptions = &capsulev1beta1.IngressOptions{}
}
dst.Spec.IngressOptions.IngressClasses = &capsulev1beta1.AllowedListSpec{
Exact: t.Spec.IngressClasses.Exact,
Regex: t.Spec.IngressClasses.Regex,
}
}
if t.Spec.IngressHostnames != nil {
dst.Spec.IngressHostnames = &capsulev1beta1.AllowedListSpec{
if dst.Spec.IngressOptions == nil {
dst.Spec.IngressOptions = &capsulev1beta1.IngressOptions{}
}
dst.Spec.IngressOptions.IngressHostnames = &capsulev1beta1.AllowedListSpec{
Exact: t.Spec.IngressHostnames.Exact,
Regex: t.Spec.IngressHostnames.Regex,
}
@@ -453,16 +459,16 @@ func (t *Tenant) ConvertFrom(srcRaw conversion.Hub) error {
Regex: src.Spec.StorageClasses.Regex,
}
}
if src.Spec.IngressClasses != nil {
if src.Spec.IngressOptions != nil && src.Spec.IngressOptions.IngressClasses != nil {
t.Spec.IngressClasses = &AllowedListSpec{
Exact: src.Spec.IngressClasses.Exact,
Regex: src.Spec.IngressClasses.Regex,
Exact: src.Spec.IngressOptions.IngressClasses.Exact,
Regex: src.Spec.IngressOptions.IngressClasses.Regex,
}
}
if src.Spec.IngressHostnames != nil {
if src.Spec.IngressOptions != nil && src.Spec.IngressOptions.IngressHostnames != nil {
t.Spec.IngressHostnames = &AllowedListSpec{
Exact: src.Spec.IngressHostnames.Exact,
Regex: src.Spec.IngressHostnames.Regex,
Exact: src.Spec.IngressOptions.IngressHostnames.Exact,
Regex: src.Spec.IngressOptions.IngressHostnames.Regex,
}
}
if src.Spec.ContainerRegistries != nil {

View File

@@ -229,11 +229,13 @@ func generateTenantsSpecs() (Tenant, capsulev1beta1.Tenant) {
},
},
},
NamespaceOptions: v1beta1NamespaceOptions,
ServiceOptions: v1beta1ServiceOptions,
StorageClasses: v1beta1AllowedListSpec,
IngressClasses: v1beta1AllowedListSpec,
IngressHostnames: v1beta1AllowedListSpec,
NamespaceOptions: v1beta1NamespaceOptions,
ServiceOptions: v1beta1ServiceOptions,
StorageClasses: v1beta1AllowedListSpec,
IngressOptions: &capsulev1beta1.IngressOptions{
IngressClasses: v1beta1AllowedListSpec,
IngressHostnames: v1beta1AllowedListSpec,
},
ContainerRegistries: v1beta1AllowedListSpec,
NodeSelector: nodeSelector,
NetworkPolicies: &capsulev1beta1.NetworkPolicySpec{

View File

@@ -0,0 +1,11 @@
// Copyright 2020-2021 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package v1beta1
type IngressOptions struct {
// Specifies the allowed IngressClasses assigned to the Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed IngressClasses. Optional.
IngressClasses *AllowedListSpec `json:"ingressClasses,omitempty"`
// Specifies the allowed hostnames in Ingresses for the given Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed hostnames. Optional.
IngressHostnames *AllowedListSpec `json:"ingressHostnames,omitempty"`
}

View File

@@ -17,10 +17,8 @@ type TenantSpec struct {
ServiceOptions *ServiceOptions `json:"serviceOptions,omitempty"`
// Specifies the allowed StorageClasses assigned to the Tenant. Capsule assures that all PersistentVolumeClaim resources created in the Tenant can use only one of the allowed StorageClasses. Optional.
StorageClasses *AllowedListSpec `json:"storageClasses,omitempty"`
// Specifies the allowed IngressClasses assigned to the Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed IngressClasses. Optional.
IngressClasses *AllowedListSpec `json:"ingressClasses,omitempty"`
// Specifies the allowed hostnames in Ingresses for the given Tenant. Capsule assures that all Ingress resources created in the Tenant can use only one of the allowed hostnames. Optional.
IngressHostnames *AllowedListSpec `json:"ingressHostnames,omitempty"`
// Specifies options for the Ingress resources, such as allowed hostnames and IngressClass. Optional.
IngressOptions *IngressOptions `json:"ingressOptions,omitempty"`
// Specifies the trusted Image Registries assigned to the Tenant. Capsule assures that all Pods resources created in the Tenant can use only one of the allowed trusted registries. Optional.
ContainerRegistries *AllowedListSpec `json:"containerRegistries,omitempty"`
// Specifies the label to control the placement of pods on a given pool of worker nodes. All namesapces 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.

View File

@@ -149,6 +149,31 @@ func (in *ExternalServiceIPsSpec) DeepCopy() *ExternalServiceIPsSpec {
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
if in.IngressClasses != nil {
in, out := &in.IngressClasses, &out.IngressClasses
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressHostnames != nil {
in, out := &in.IngressHostnames, &out.IngressHostnames
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressOptions.
func (in *IngressOptions) DeepCopy() *IngressOptions {
if in == nil {
return nil
}
out := new(IngressOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LimitRangesSpec) DeepCopyInto(out *LimitRangesSpec) {
*out = *in
@@ -417,14 +442,9 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressClasses != nil {
in, out := &in.IngressClasses, &out.IngressClasses
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressHostnames != nil {
in, out := &in.IngressHostnames, &out.IngressHostnames
*out = new(AllowedListSpec)
if in.IngressOptions != nil {
in, out := &in.IngressOptions, &out.IngressOptions
*out = new(IngressOptions)
(*in).DeepCopyInto(*out)
}
if in.ContainerRegistries != nil {

View File

@@ -64,12 +64,12 @@ func (r *Manager) syncNamespaceMetadata(namespace string, tnt *capsulev1beta1.Te
annotations["scheduler.alpha.kubernetes.io/node-selector"] = strings.Join(selector, ",")
}
if tnt.Spec.IngressClasses != nil {
if len(tnt.Spec.IngressClasses.Exact) > 0 {
annotations[capsulev1beta1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressClasses.Exact, ",")
if tnt.Spec.IngressOptions != nil && tnt.Spec.IngressOptions.IngressClasses != nil {
if len(tnt.Spec.IngressOptions.IngressClasses.Exact) > 0 {
annotations[capsulev1beta1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressOptions.IngressClasses.Exact, ",")
}
if len(tnt.Spec.IngressClasses.Regex) > 0 {
annotations[capsulev1beta1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressClasses.Regex
if len(tnt.Spec.IngressOptions.IngressClasses.Regex) > 0 {
annotations[capsulev1beta1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressOptions.IngressClasses.Regex
}
}

View File

@@ -23,8 +23,8 @@ func (IngressHostnames) Field() string {
func (IngressHostnames) Func() client.IndexerFunc {
return func(object client.Object) (out []string) {
tenant := object.(*capsulev1beta1.Tenant)
if tenant.Spec.IngressHostnames != nil {
out = append(out, tenant.Spec.IngressHostnames.Exact...)
if tenant.Spec.IngressOptions != nil && tenant.Spec.IngressOptions.IngressHostnames != nil {
out = append(out, tenant.Spec.IngressOptions.IngressHostnames.Exact...)
}
return
}

View File

@@ -111,23 +111,23 @@ func (r *class) OnDelete(client.Client, *admission.Decoder, record.EventRecorder
}
func (r *class) validateClass(tenant capsulev1beta1.Tenant, ingressClass *string) error {
if tenant.Spec.IngressClasses == nil {
if tenant.Spec.IngressOptions.IngressClasses == nil {
return nil
}
if ingressClass == nil {
return NewIngressClassNotValid(*tenant.Spec.IngressClasses)
return NewIngressClassNotValid(*tenant.Spec.IngressOptions.IngressClasses)
}
var valid, matched bool
if len(tenant.Spec.IngressClasses.Exact) > 0 {
valid = tenant.Spec.IngressClasses.ExactMatch(*ingressClass)
if len(tenant.Spec.IngressOptions.IngressClasses.Exact) > 0 {
valid = tenant.Spec.IngressOptions.IngressClasses.ExactMatch(*ingressClass)
}
matched = tenant.Spec.IngressClasses.RegexMatch(*ingressClass)
matched = tenant.Spec.IngressOptions.IngressClasses.RegexMatch(*ingressClass)
if !valid && !matched {
return NewIngressClassForbidden(*ingressClass, *tenant.Spec.IngressClasses)
return NewIngressClassForbidden(*ingressClass, *tenant.Spec.IngressOptions.IngressClasses)
}
return nil

View File

@@ -14,7 +14,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
capsulev1beta1 "github.com/clastix/capsule/api/v1beta1"
"github.com/clastix/capsule/pkg/configuration"
capsulewebhook "github.com/clastix/capsule/pkg/webhook"
"github.com/clastix/capsule/pkg/webhook/utils"
@@ -105,7 +104,7 @@ func (r *hostnames) OnDelete(client.Client, *admission.Decoder, record.EventReco
}
func (r *hostnames) validateHostnames(tenant capsulev1beta1.Tenant, hostnames []string) error {
if tenant.Spec.IngressHostnames == nil {
if tenant.Spec.IngressOptions == nil || tenant.Spec.IngressOptions.IngressHostnames == nil {
return nil
}
@@ -114,7 +113,7 @@ func (r *hostnames) validateHostnames(tenant capsulev1beta1.Tenant, hostnames []
var invalidHostnames []string
if len(hostnames) > 0 {
for _, currentHostname := range hostnames {
isPresent := HostnamesList(tenant.Spec.IngressHostnames.Exact).IsStringInList(currentHostname)
isPresent := HostnamesList(tenant.Spec.IngressOptions.IngressHostnames.Exact).IsStringInList(currentHostname)
if !isPresent {
invalidHostnames = append(invalidHostnames, currentHostname)
}
@@ -125,10 +124,10 @@ func (r *hostnames) validateHostnames(tenant capsulev1beta1.Tenant, hostnames []
}
var notMatchingHostnames []string
allowedRegex := tenant.Spec.IngressHostnames.Regex
allowedRegex := tenant.Spec.IngressOptions.IngressHostnames.Regex
if len(allowedRegex) > 0 {
for _, currentHostname := range hostnames {
matched, _ = regexp.MatchString(tenant.Spec.IngressHostnames.Regex, currentHostname)
matched, _ = regexp.MatchString(allowedRegex, currentHostname)
if !matched {
notMatchingHostnames = append(notMatchingHostnames, currentHostname)
}
@@ -139,7 +138,7 @@ func (r *hostnames) validateHostnames(tenant capsulev1beta1.Tenant, hostnames []
}
if !valid && !matched {
return NewIngressHostnamesNotValid(invalidHostnames, notMatchingHostnames, *tenant.Spec.IngressHostnames)
return NewIngressHostnamesNotValid(invalidHostnames, notMatchingHostnames, *tenant.Spec.IngressOptions.IngressHostnames)
}
return nil

View File

@@ -30,8 +30,8 @@ func (h *hostnameRegexHandler) validate(decoder *admission.Decoder, req admissio
return utils.ErroredResponse(err)
}
if tenant.Spec.IngressHostnames != nil && len(tenant.Spec.IngressHostnames.Regex) > 0 {
if _, err := regexp.Compile(tenant.Spec.IngressHostnames.Regex); err != nil {
if tenant.Spec.IngressOptions.IngressHostnames != nil && len(tenant.Spec.IngressOptions.IngressHostnames.Regex) > 0 {
if _, err := regexp.Compile(tenant.Spec.IngressOptions.IngressHostnames.Regex); err != nil {
response := admission.Denied("unable to compile allowedHostnames allowedRegex")
return &response

View File

@@ -33,8 +33,8 @@ func (h *hostnamesCollisionHandler) validateTenant(ctx context.Context, req admi
return utils.ErroredResponse(err)
}
if !h.configuration.AllowTenantIngressHostnamesCollision() && tenant.Spec.IngressHostnames != nil && len(tenant.Spec.IngressHostnames.Exact) > 0 {
for _, h := range tenant.Spec.IngressHostnames.Exact {
if !h.configuration.AllowTenantIngressHostnamesCollision() && tenant.Spec.IngressOptions != nil && tenant.Spec.IngressOptions.IngressHostnames != nil && len(tenant.Spec.IngressOptions.IngressHostnames.Exact) > 0 {
for _, h := range tenant.Spec.IngressOptions.IngressHostnames.Exact {
tntList := &capsulev1beta1.TenantList{}
if err := clt.List(ctx, tntList, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(".spec.ingressHostnames", h),

View File

@@ -30,8 +30,8 @@ func (h *ingressClassRegexHandler) validate(decoder *admission.Decoder, req admi
return utils.ErroredResponse(err)
}
if tenant.Spec.IngressClasses != nil && len(tenant.Spec.IngressClasses.Regex) > 0 {
if _, err := regexp.Compile(tenant.Spec.IngressClasses.Regex); err != nil {
if tenant.Spec.IngressOptions != nil && tenant.Spec.IngressOptions.IngressClasses != nil && len(tenant.Spec.IngressOptions.IngressClasses.Regex) > 0 {
if _, err := regexp.Compile(tenant.Spec.IngressOptions.IngressClasses.Regex); err != nil {
response := admission.Denied("unable to compile ingressClasses allowedRegex")
return &response