Skip to content

Commit

Permalink
Merge branch 'crd-controller-base' into crd-controller-proxy-def
Browse files Browse the repository at this point in the history
  • Loading branch information
thisisnotashwin committed Sep 24, 2020
2 parents d2c4eb4 + 1b33c49 commit 635a221
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 43 deletions.
13 changes: 9 additions & 4 deletions api/common/configentry_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ func ValidateConfigEntry(
req admission.Request,
logger logr.Logger,
configEntryLister ConfigEntryLister,
cfgEntry ConfigEntryResource) admission.Response {
cfgEntry ConfigEntryResource,
enableConsulNamespaces bool,
nsMirroring bool) admission.Response {

// On create we need to validate that there isn't already a resource with
// the same name in a different namespace since we need to map all Kube
// resources to a single Consul namespace.
if req.Operation == v1beta1.Create {
// the same name in a different namespace if we're need to mapping all Kube
// resources to a single Consul namespace. The only case where we're not
// mapping all kube resources to a single Consul namespace is when we
// are running Consul enterprise with namespace mirroring.
singleConsulDestNS := !(enableConsulNamespaces && nsMirroring)
if req.Operation == v1beta1.Create && singleConsulDestNS {
logger.Info("validate create", "name", cfgEntry.Name())

list, err := configEntryLister.List(ctx)
Expand Down
34 changes: 33 additions & 1 deletion api/common/configentry_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func TestValidateConfigEntry(t *testing.T) {
cases := map[string]struct {
existingResources []ConfigEntryResource
newResource ConfigEntryResource
enableNamespaces bool
nsMirroring bool
expAllow bool
expErrMessage string
}{
Expand Down Expand Up @@ -58,6 +60,34 @@ func TestValidateConfigEntry(t *testing.T) {
expAllow: false,
expErrMessage: "mockkind resource with name \"foo\" is already defined – all mockkind resources must have unique names across namespaces",
},
"duplicate name, namespaces enabled": {
existingResources: []ConfigEntryResource{&mockConfigEntry{
MockName: "foo",
MockNamespace: "default",
}},
newResource: &mockConfigEntry{
MockName: "foo",
MockNamespace: otherNS,
Valid: true,
},
enableNamespaces: true,
expAllow: false,
expErrMessage: "mockkind resource with name \"foo\" is already defined – all mockkind resources must have unique names across namespaces",
},
"duplicate name, namespaces enabled, mirroring enabled": {
existingResources: []ConfigEntryResource{&mockConfigEntry{
MockName: "foo",
MockNamespace: "default",
}},
newResource: &mockConfigEntry{
MockName: "foo",
MockNamespace: otherNS,
Valid: true,
},
enableNamespaces: true,
nsMirroring: true,
expAllow: true,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
Expand All @@ -80,7 +110,9 @@ func TestValidateConfigEntry(t *testing.T) {
},
logrtest.TestLogger{T: t},
lister,
c.newResource)
c.newResource,
c.enableNamespaces,
c.nsMirroring)
require.Equal(t, c.expAllow, response.Allowed)
if c.expErrMessage != "" {
require.Equal(t, c.expErrMessage, response.AdmissionResponse.Result.Message)
Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/proxydefaults_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ func TestProxyDefaults_ValidateConfigInvalid(t *testing.T) {
},
}
t.Run(name, func(t *testing.T) {
require.Equal(t, proxyDefaults.validateConfig(field.NewPath("spec")).Detail, "must be valid map value")
require.Contains(t, proxyDefaults.validateConfig(field.NewPath("spec")).Detail, "must be valid map value")
})
}
}
Expand Down
8 changes: 5 additions & 3 deletions api/v1alpha1/proxydefaults_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (

type ProxyDefaultsValidator struct {
client.Client
ConsulClient *capi.Client
Logger logr.Logger
decoder *admission.Decoder
ConsulClient *capi.Client
Logger logr.Logger
decoder *admission.Decoder
EnableConsulNamespaces bool
EnableNSMirroring bool
}

// NOTE: The path value in the below line is the path to the webhook.
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/proxydefaults_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestValidateConfigEntry(t *testing.T) {
},
expAllow: false,
// This error message is because the value "1" is valid JSON but is an invalid map
expErrMessage: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.config: Invalid value: json.RawMessage{0x31}: must be valid map value",
expErrMessage: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.config: Invalid value: json.RawMessage{0x31}: must be valid map value: json: cannot unmarshal number into Go value of type map[string]interface {}",
},
"proxy default exists": {
existingResources: []runtime.Object{&ProxyDefaults{
Expand All @@ -65,7 +65,7 @@ func TestValidateConfigEntry(t *testing.T) {
},
},
expAllow: false,
expErrMessage: "proxydefaults resource already defined in cluster. Currently, only one global entry is supported",
expErrMessage: "proxydefaults resource already defined - only one global entry is supported",
},
"name not global": {
existingResources: []runtime.Object{},
Expand Down
34 changes: 20 additions & 14 deletions api/v1alpha1/servicedefaults_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

func NewServiceDefaultsValidator(client client.Client, consulClient *capi.Client, logger logr.Logger) *serviceDefaultsValidator {
return &serviceDefaultsValidator{
Client: client,
ConsulClient: consulClient,
Logger: logger,
}
}
// +kubebuilder:object:generate=false

type serviceDefaultsValidator struct {
client.Client
type ServiceDefaultsValidator struct {
ConsulClient *capi.Client
Logger logr.Logger
decoder *admission.Decoder

// EnableConsulNamespaces indicates that a user is running Consul Enterprise
// with version 1.7+ which supports namespaces.
EnableConsulNamespaces bool

// EnableNSMirroring causes Consul namespaces to be created to match the
// k8s namespace of any config entry custom resource. Config entries will
// be created in the matching Consul namespace.
EnableNSMirroring bool

decoder *admission.Decoder
client.Client
}

// NOTE: The path value in the below line is the path to the webhook.
Expand All @@ -34,7 +38,7 @@ type serviceDefaultsValidator struct {
//
// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-servicedefaults,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=servicedefaults,versions=v1alpha1,name=mutate-servicedefaults.consul.hashicorp.com

func (v *serviceDefaultsValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
func (v *ServiceDefaultsValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
var svcDefaults ServiceDefaults
err := v.decoder.Decode(req, &svcDefaults)
if err != nil {
Expand All @@ -45,10 +49,12 @@ func (v *serviceDefaultsValidator) Handle(ctx context.Context, req admission.Req
req,
v.Logger,
v,
&svcDefaults)
&svcDefaults,
v.EnableConsulNamespaces,
v.EnableNSMirroring)
}

func (v *serviceDefaultsValidator) List(ctx context.Context) ([]common.ConfigEntryResource, error) {
func (v *ServiceDefaultsValidator) List(ctx context.Context) ([]common.ConfigEntryResource, error) {
var svcDefaultsList ServiceDefaultsList
if err := v.Client.List(ctx, &svcDefaultsList); err != nil {
return nil, err
Expand All @@ -60,7 +66,7 @@ func (v *serviceDefaultsValidator) List(ctx context.Context) ([]common.ConfigEnt
return entries, nil
}

func (v *serviceDefaultsValidator) InjectDecoder(d *admission.Decoder) error {
func (v *ServiceDefaultsValidator) InjectDecoder(d *admission.Decoder) error {
v.decoder = d
return nil
}
34 changes: 20 additions & 14 deletions api/v1alpha1/serviceresolver_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

func NewServiceResolverValidator(client client.Client, consulClient *capi.Client, logger logr.Logger) *serviceResolverValidator {
return &serviceResolverValidator{
Client: client,
ConsulClient: consulClient,
Logger: logger,
}
}
// +kubebuilder:object:generate=false

type serviceResolverValidator struct {
client.Client
type ServiceResolverValidator struct {
ConsulClient *capi.Client
Logger logr.Logger
decoder *admission.Decoder

// EnableConsulNamespaces indicates that a user is running Consul Enterprise
// with version 1.7+ which supports namespaces.
EnableConsulNamespaces bool

// EnableNSMirroring causes Consul namespaces to be created to match the
// k8s namespace of any config entry custom resource. Config entries will
// be created in the matching Consul namespace.
EnableNSMirroring bool

decoder *admission.Decoder
client.Client
}

// NOTE: The path value in the below line is the path to the webhook.
Expand All @@ -35,7 +39,7 @@ type serviceResolverValidator struct {
//
// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-serviceresolver,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=serviceresolvers,versions=v1alpha1,name=mutate-serviceresolver.consul.hashicorp.com

func (v *serviceResolverValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
func (v *ServiceResolverValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
var svcResolver ServiceResolver
err := v.decoder.Decode(req, &svcResolver)
if err != nil {
Expand All @@ -46,10 +50,12 @@ func (v *serviceResolverValidator) Handle(ctx context.Context, req admission.Req
req,
v.Logger,
v,
&svcResolver)
&svcResolver,
v.EnableConsulNamespaces,
v.EnableNSMirroring)
}

func (v *serviceResolverValidator) List(ctx context.Context) ([]common.ConfigEntryResource, error) {
func (v *ServiceResolverValidator) List(ctx context.Context) ([]common.ConfigEntryResource, error) {
var svcResolverList ServiceResolverList
if err := v.Client.List(ctx, &svcResolverList); err != nil {
return nil, err
Expand All @@ -61,7 +67,7 @@ func (v *serviceResolverValidator) List(ctx context.Context) ([]common.ConfigEnt
return entries, nil
}

func (v *serviceResolverValidator) InjectDecoder(d *admission.Decoder) error {
func (v *ServiceResolverValidator) InjectDecoder(d *admission.Decoder) error {
v.decoder = d
return nil
}
2 changes: 1 addition & 1 deletion controllers/configentry_controller_ent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ func TestConfigEntryController_deletesGlobalConfigEntry_consulNamespaces(tt *tes
MeshGateway: capi.MeshGatewayConfig{
Mode: "local",
},
}, &capi.WriteOptions{Namespace: c.ExpConsulNS})
}, &capi.WriteOptions{Namespace: common.DefaultConsulNamespace})
req.NoError(err)
req.True(written)
}
Expand Down
24 changes: 21 additions & 3 deletions subcommand/controller/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,29 @@ func (c *Command) Run(args []string) int {
// Note: The path here should be identical to the one on the kubebuilder
// annotation in each webhook file.
mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicedefaults",
&webhook.Admission{Handler: v1alpha1.NewServiceDefaultsValidator(mgr.GetClient(), consulClient, ctrl.Log.WithName("webhooks").WithName(common.ServiceDefaults))})
&webhook.Admission{Handler: &v1alpha1.ServiceDefaultsValidator{
Client: mgr.GetClient(),
ConsulClient: consulClient,
Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceDefaults),
EnableConsulNamespaces: c.flagEnableNamespaces,
EnableNSMirroring: c.flagEnableNSMirroring,
}})
mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceresolver",
&webhook.Admission{Handler: v1alpha1.NewServiceResolverValidator(mgr.GetClient(), consulClient, ctrl.Log.WithName("webhooks").WithName(common.ServiceResolver))})
&webhook.Admission{Handler: &v1alpha1.ServiceResolverValidator{
Client: mgr.GetClient(),
ConsulClient: consulClient,
Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceResolver),
EnableConsulNamespaces: c.flagEnableNamespaces,
EnableNSMirroring: c.flagEnableNSMirroring,
}})
mgr.GetWebhookServer().Register("/mutate-v1alpha1-proxydefaults",
&webhook.Admission{Handler: &v1alpha1.ProxyDefaultsValidator{Client: mgr.GetClient(), ConsulClient: consulClient, Logger: ctrl.Log.WithName("webhooks").WithName(common.ProxyDefaults)}})
&webhook.Admission{Handler: &v1alpha1.ProxyDefaultsValidator{
Client: mgr.GetClient(),
ConsulClient: consulClient,
Logger: ctrl.Log.WithName("webhooks").WithName(common.ProxyDefaults),
EnableConsulNamespaces: c.flagEnableNamespaces,
EnableNSMirroring: c.flagEnableNSMirroring,
}})
}
// +kubebuilder:scaffold:builder

Expand Down

0 comments on commit 635a221

Please sign in to comment.