blob: dd8f836d37617edc7c9e037c84bdd3bd445a2d8a [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package webhooks
import (
"bytes"
"context"
"strings"
"testing"
)
import (
"istio.io/api/label"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/keycertbundle"
"github.com/apache/dubbo-go-pixiu/pkg/kube"
"github.com/apache/dubbo-go-pixiu/pkg/test/util/retry"
)
var caBundle0 = []byte(`-----BEGIN CERTIFICATE-----
MIIC9DCCAdygAwIBAgIJAIFe3lWPaalKMA0GCSqGSIb3DQEBCwUAMA4xDDAKBgNV
BAMMA19jYTAgFw0xNzEyMjIxODA0MjRaGA8yMjkxMTAwNzE4MDQyNFowDjEMMAoG
A1UEAwwDX2NhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBdxj+Hi
8h0TkId1f64TprLydwgzzLwXAs3wpmXz+BfnW1oMQPNyN7vojW6VzqJGGYLsc1OB
MgwObU/VeFNc6YUCmu6mfFJwoPfXMPnhmGuSwf/kjXomlejAYjxClU3UFVWQht54
xNLjTi2M1ZOnwNbECOhXC3Tw3G8mCtfanMAO0UXM5yObbPa8yauUpJKkpoxWA7Ed
qiuUD9qRxluFPqqw/z86V8ikmvnyjQE9960j+8StlAbRs82ArtnrhRgkDO0Smtf7
4QZsb/hA1KNMm73bOGS6+SVU+eH8FgVOzcTQYFRpRT3Mhi6dKZe9twIO8mpZK4wk
uygRxBM32Ag9QQIDAQABo1MwUTAdBgNVHQ4EFgQUc8tvoNNBHyIkoVV8XCXy63Ya
BEQwHwYDVR0jBBgwFoAUc8tvoNNBHyIkoVV8XCXy63YaBEQwDwYDVR0TAQH/BAUw
AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVmaUkkYESfcfgnuPeZ4sTNs2nk2Y+Xpd
lxkMJhChb8YQtlCe4uiLvVe7er1sXcBLNCm/+2K9AT71gnxBSeS5mEOzWmCPErhy
RmYtSxeRyXAaUWVYLs/zMlBQ0Iz4dpY+FVVbMjIurelVwHF0NBk3VtU5U3lHyKdZ
j4C2rMjvTxmkyIcR1uBEeVvuGU8R70nZ1yfo3vDwmNGMcLwW+4QK+WcfwfjLXhLs
5550arfEYdTzYFMxY60HJT/LvbGrjxY0PQUWWDbPiRfsdRjOFduAbM0/EVRda/Oo
Fg72WnHeojDUhqEz4UyFZbnRJ4x6leQhnrIcVjWX4FFFktiO9rqqfw==
-----END CERTIFICATE-----`)
func TestMutatingWebhookPatch(t *testing.T) {
testRevision := "test-revision"
wrongRevision := "wrong-revision"
testRevisionLabel := map[string]string{label.IoIstioRev.Name: testRevision}
wrongRevisionLabel := map[string]string{label.IoIstioRev.Name: wrongRevision}
watcher := &keycertbundle.Watcher{}
watcher.SetAndNotify(nil, nil, caBundle0)
ts := []struct {
name string
configs admissionregistrationv1.MutatingWebhookConfigurationList
revision string
configName string
webhookName string
pemData []byte
err string
}{
{
"WebhookConfigNotFound",
admissionregistrationv1.MutatingWebhookConfigurationList{},
testRevision,
"config1",
"webhook1",
caBundle0,
errNotFound.Error(),
},
{
"WebhookEntryNotFound",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
Labels: testRevisionLabel,
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
errNoWebhookWithName.Error(),
},
{
"SuccessfullyPatched",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
Labels: testRevisionLabel,
},
Webhooks: []admissionregistrationv1.MutatingWebhook{
{
Name: "webhook1",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
"",
},
{
"Prefix",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
Labels: testRevisionLabel,
},
Webhooks: []admissionregistrationv1.MutatingWebhook{
{
Name: "prefix.webhook1",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
"",
},
{
"NoRevisionWebhookNotUpdated",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
},
Webhooks: []admissionregistrationv1.MutatingWebhook{
{
Name: "webhook1",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
errNotFound.Error(),
},
{
"WrongRevisionWebhookNotUpdated",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
Labels: wrongRevisionLabel,
},
Webhooks: []admissionregistrationv1.MutatingWebhook{
{
Name: "webhook1",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
errNotFound.Error(),
},
{
"MultipleWebhooks",
admissionregistrationv1.MutatingWebhookConfigurationList{
Items: []admissionregistrationv1.MutatingWebhookConfiguration{
{
ObjectMeta: metav1.ObjectMeta{
Name: "config1",
Labels: testRevisionLabel,
},
Webhooks: []admissionregistrationv1.MutatingWebhook{
{
Name: "webhook1",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
{
Name: "should not be changed",
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
},
},
},
},
testRevision,
"config1",
"webhook1",
caBundle0,
"",
},
}
for _, tc := range ts {
t.Run(tc.name, func(t *testing.T) {
client := kube.NewFakeClient()
for _, wh := range tc.configs.Items {
if _, err := client.AdmissionregistrationV1().
MutatingWebhookConfigurations().Create(context.Background(), wh.DeepCopy(), metav1.CreateOptions{}); err != nil {
t.Fatal(err)
}
}
watcher := keycertbundle.NewWatcher()
watcher.SetAndNotify(nil, nil, tc.pemData)
whPatcher, err := NewWebhookCertPatcher(client, tc.revision, tc.webhookName, watcher)
if err != nil {
t.Fatal(err)
}
stop := make(chan struct{})
t.Cleanup(func() {
close(stop)
})
go whPatcher.informer.Run(stop)
client.RunAndWait(stop)
retry.UntilOrFail(t, whPatcher.informer.HasSynced)
err = whPatcher.patchMutatingWebhookConfig(
client.AdmissionregistrationV1().MutatingWebhookConfigurations(),
tc.configName)
if (err != nil) != (tc.err != "") {
t.Fatalf("Wrong error: got %v want %v", err, tc.err)
}
if err != nil {
if !strings.Contains(err.Error(), tc.err) {
t.Fatalf("Got %q, want %q", err, tc.err)
}
} else {
obj, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(context.Background(), tc.configName, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
for _, w := range obj.Webhooks {
if strings.HasSuffix(w.Name, tc.webhookName) {
if !bytes.Equal(w.ClientConfig.CABundle, tc.pemData) {
t.Fatalf("Incorrect CA bundle: expect %s got %s", tc.pemData, w.ClientConfig.CABundle)
}
}
if !strings.HasSuffix(w.Name, tc.webhookName) {
if bytes.Equal(w.ClientConfig.CABundle, tc.pemData) {
t.Fatalf("Non-matching webhook \"%s\" CA bundle updated to %v", w.Name, w.ClientConfig.CABundle)
}
}
}
}
})
}
}