-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- adds validation webhooks for PeeringAcceptor and Peering dialer controllers - fixes panic by doing a nil check on the PeeringAcceptor SecretRef()
- Loading branch information
1 parent
023007f
commit faa3ecf
Showing
14 changed files
with
822 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func TestPeeringAcceptor_Validate(t *testing.T) { | ||
cases := map[string]struct { | ||
acceptor *PeeringAcceptor | ||
expectedErrMsgs []string | ||
}{ | ||
"valid": { | ||
acceptor: &PeeringAcceptor{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "api", | ||
}, | ||
Spec: PeeringAcceptorSpec{ | ||
Peer: &Peer{ | ||
Secret: &Secret{ | ||
Name: "api-token", | ||
Key: "data", | ||
Backend: SecretBackendTypeKubernetes, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"no peer specified": { | ||
acceptor: &PeeringAcceptor{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "api", | ||
}, | ||
Spec: PeeringAcceptorSpec{}, | ||
}, | ||
expectedErrMsgs: []string{ | ||
`spec.peer: Invalid value: "null": peer must be specified`, | ||
}, | ||
}, | ||
"no secret specified": { | ||
acceptor: &PeeringAcceptor{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "api", | ||
}, | ||
Spec: PeeringAcceptorSpec{ | ||
Peer: &Peer{}, | ||
}, | ||
}, | ||
expectedErrMsgs: []string{ | ||
`spec.peer.secret: Invalid value: "null": secret must be specified`, | ||
}, | ||
}, | ||
"invalid secret backend": { | ||
acceptor: &PeeringAcceptor{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "api", | ||
}, | ||
Spec: PeeringAcceptorSpec{ | ||
Peer: &Peer{ | ||
Secret: &Secret{ | ||
Backend: "invalid", | ||
}, | ||
}, | ||
}, | ||
}, | ||
expectedErrMsgs: []string{ | ||
`spec.peer.secret.backend: Invalid value: "invalid": backend must be "kubernetes"`, | ||
}, | ||
}, | ||
} | ||
|
||
for name, testCase := range cases { | ||
t.Run(name, func(t *testing.T) { | ||
err := testCase.acceptor.Validate() | ||
if len(testCase.expectedErrMsgs) != 0 { | ||
require.Error(t, err) | ||
for _, s := range testCase.expectedErrMsgs { | ||
require.Contains(t, err.Error(), s) | ||
} | ||
} else { | ||
require.NoError(t, err) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/go-logr/logr" | ||
capi "github.com/hashicorp/consul/api" | ||
admissionv1 "k8s.io/api/admission/v1" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||
) | ||
|
||
// +kubebuilder:object:generate=false | ||
|
||
type PeeringAcceptorWebhook struct { | ||
client.Client | ||
ConsulClient *capi.Client | ||
Logger logr.Logger | ||
decoder *admission.Decoder | ||
//ConsulMeta common.ConsulMeta | ||
} | ||
|
||
// NOTE: The path value in the below line is the path to the webhook. | ||
// If it is updated, run code-gen, update subcommand/controller/command.go | ||
// and the consul-helm value for the path to the webhook. | ||
// | ||
// NOTE: The below line cannot be combined with any other comment. If it is | ||
// it will break the code generation. | ||
// | ||
// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-peeringacceptors,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=peeringacceptors,versions=v1alpha1,name=mutate-peeringacceptors.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 | ||
|
||
func (v *PeeringAcceptorWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { | ||
var acceptor PeeringAcceptor | ||
var acceptorList PeeringAcceptorList | ||
err := v.decoder.Decode(req, &acceptor) | ||
if err != nil { | ||
return admission.Errored(http.StatusBadRequest, err) | ||
} | ||
|
||
// Call validate first to ensure all the fields are validated before checking for secret name duplicates. | ||
if err := acceptor.Validate(); err != nil { | ||
return admission.Errored(http.StatusBadRequest, err) | ||
} | ||
|
||
if req.Operation == admissionv1.Create { | ||
v.Logger.Info("validate create", "name", acceptor.KubernetesName()) | ||
|
||
if err := v.Client.List(ctx, &acceptorList); err != nil { | ||
return admission.Errored(http.StatusInternalServerError, err) | ||
} | ||
|
||
for _, item := range acceptorList.Items { | ||
// If any peering acceptor resource has the same secret name as this one, reject it. | ||
if item.Namespace == acceptor.Namespace && item.Secret().Name == acceptor.Secret().Name { | ||
return admission.Errored(http.StatusBadRequest, | ||
fmt.Errorf("an existing PeeringAcceptor resource has the same secret name `name: %s, namespace: %s`", acceptor.Secret().Name, acceptor.Namespace)) | ||
} | ||
} | ||
} | ||
|
||
return admission.Allowed(fmt.Sprintf("valid %s request", acceptor.KubeKind())) | ||
} | ||
|
||
func (v *PeeringAcceptorWebhook) InjectDecoder(d *admission.Decoder) error { | ||
v.decoder = d | ||
return nil | ||
} |
Oops, something went wrong.