blob: 97da22b848a3e9ff4c4ac547e7f6cc7bacbb1fef [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 tag
import (
"fmt"
"path/filepath"
"testing"
)
import (
"istio.io/api/label"
admit_v1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/test/env"
)
var (
defaultRevisionCanonicalWebhook = admit_v1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "istio-sidecar-injector",
Labels: map[string]string{label.IoIstioRev.Name: "dubbo"},
},
Webhooks: []admit_v1.MutatingWebhook{
{
Name: fmt.Sprintf("namespace.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
Service: &admit_v1.ServiceReference{
Namespace: "dubbo-system",
Name: "istiod",
},
CABundle: []byte("ca"),
},
},
{
Name: fmt.Sprintf("object.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
Service: &admit_v1.ServiceReference{
Namespace: "dubbo-system",
Name: "istiod",
},
CABundle: []byte("ca"),
},
},
},
}
samplePath = "/sample/path"
revisionCanonicalWebhook = admit_v1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "istio-sidecar-injector-revision",
Labels: map[string]string{label.IoIstioRev.Name: "revision"},
},
Webhooks: []admit_v1.MutatingWebhook{
{
Name: fmt.Sprintf("namespace.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
Service: &admit_v1.ServiceReference{
Namespace: "dubbo-system",
Name: "istiod-revision",
Path: &samplePath,
},
CABundle: []byte("ca"),
},
},
{
Name: fmt.Sprintf("object.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
Service: &admit_v1.ServiceReference{
Namespace: "dubbo-system",
Name: "istiod-revision",
},
CABundle: []byte("ca"),
},
},
},
}
remoteInjectionURL = "https://random.host.com/inject/cluster/cluster1/net/net1"
revisionCanonicalWebhookRemote = admit_v1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "istio-sidecar-injector-revision",
Labels: map[string]string{label.IoIstioRev.Name: "revision"},
},
Webhooks: []admit_v1.MutatingWebhook{
{
Name: fmt.Sprintf("namespace.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
URL: &remoteInjectionURL,
CABundle: []byte("ca"),
},
},
{
Name: fmt.Sprintf("object.%s", istioInjectionWebhookSuffix),
ClientConfig: admit_v1.WebhookClientConfig{
URL: &remoteInjectionURL,
CABundle: []byte("ca"),
},
},
},
}
remoteValidationURL = "https://random.host.com/validate"
)
func TestGenerateValidatingWebhook(t *testing.T) {
tcs := []struct {
name string
webhook admit_v1.MutatingWebhookConfiguration
whURL string
whSVC string
whCA string
}{
{
name: "webhook-pointing-to-service",
webhook: revisionCanonicalWebhook,
whURL: "",
whSVC: "istiod-revision",
whCA: "ca",
},
{
name: "webhook-pointing-to-url",
webhook: revisionCanonicalWebhookRemote,
whURL: remoteValidationURL,
whSVC: "",
whCA: "ca",
},
}
scheme := runtime.NewScheme()
codecFactory := serializer.NewCodecFactory(scheme)
deserializer := codecFactory.UniversalDeserializer()
for _, tc := range tcs {
webhookConfig, err := tagWebhookConfigFromCanonicalWebhook(tc.webhook, "default", "dubbo-system")
if err != nil {
t.Fatalf("webhook parsing failed with error: %v", err)
}
webhookYAML, err := generateValidatingWebhook(fixWhConfig(webhookConfig), filepath.Join(env.IstioSrc, "manifests"))
if err != nil {
t.Fatalf("tag webhook YAML generation failed with error: %v", err)
}
vwhObject, _, err := deserializer.Decode([]byte(webhookYAML), nil, &admit_v1.ValidatingWebhookConfiguration{})
if err != nil {
t.Fatalf("could not parse webhook from generated YAML: %s", vwhObject)
}
wh := vwhObject.(*admit_v1.ValidatingWebhookConfiguration)
for _, webhook := range wh.Webhooks {
validationWhConf := webhook.ClientConfig
if tc.whSVC != "" {
if validationWhConf.Service == nil {
t.Fatalf("expected validation service %s, got nil", tc.whSVC)
}
if validationWhConf.Service.Name != tc.whSVC {
t.Fatalf("expected validation service %s, got %s", tc.whSVC, validationWhConf.Service.Name)
}
}
if tc.whURL != "" {
if validationWhConf.URL == nil {
t.Fatalf("expected validation URL %s, got nil", tc.whURL)
}
if *validationWhConf.URL != tc.whURL {
t.Fatalf("expected validation URL %s, got %s", tc.whURL, *validationWhConf.URL)
}
}
if tc.whCA != "" {
if string(validationWhConf.CABundle) != tc.whCA {
t.Fatalf("expected CA bundle %q, got %q", tc.whCA, validationWhConf.CABundle)
}
}
}
}
}
func TestGenerateMutatingWebhook(t *testing.T) {
tcs := []struct {
name string
webhook admit_v1.MutatingWebhookConfiguration
tagName string
whURL string
whSVC string
whCA string
numWebhooks int
}{
{
name: "webhook-pointing-to-service",
webhook: revisionCanonicalWebhook,
tagName: "canary",
whURL: "",
whSVC: "istiod-revision",
whCA: "ca",
numWebhooks: 2,
},
{
name: "webhook-pointing-to-url",
webhook: revisionCanonicalWebhookRemote,
tagName: "canary",
whURL: remoteInjectionURL,
whSVC: "",
whCA: "ca",
numWebhooks: 2,
},
{
name: "webhook-pointing-to-default-revision",
webhook: defaultRevisionCanonicalWebhook,
tagName: "canary",
whURL: "",
whSVC: "istiod",
whCA: "ca",
numWebhooks: 2,
},
{
name: "webhook-pointing-to-default-revision",
webhook: defaultRevisionCanonicalWebhook,
tagName: "default",
whURL: "",
whSVC: "istiod",
whCA: "ca",
numWebhooks: 4,
},
}
scheme := runtime.NewScheme()
codecFactory := serializer.NewCodecFactory(scheme)
deserializer := codecFactory.UniversalDeserializer()
for _, tc := range tcs {
webhookConfig, err := tagWebhookConfigFromCanonicalWebhook(tc.webhook, tc.tagName, "dubbo-system")
if err != nil {
t.Fatalf("webhook parsing failed with error: %v", err)
}
webhookYAML, err := generateMutatingWebhook(webhookConfig, "", filepath.Join(env.IstioSrc, "manifests"), false)
if err != nil {
t.Fatalf("tag webhook YAML generation failed with error: %v", err)
}
whObject, _, err := deserializer.Decode([]byte(webhookYAML), nil, &admit_v1.MutatingWebhookConfiguration{})
if err != nil {
t.Fatalf("could not parse webhook from generated YAML: %s", webhookYAML)
}
wh := whObject.(*admit_v1.MutatingWebhookConfiguration)
// expect both namespace.sidecar-injector.istio.io and object.sidecar-injector.istio.io webhooks
if len(wh.Webhooks) != tc.numWebhooks {
t.Errorf("expected %d webhook(s) in MutatingWebhookConfiguration, found %d",
tc.numWebhooks, len(wh.Webhooks))
}
tag, exists := wh.ObjectMeta.Labels[IstioTagLabel]
if !exists {
t.Errorf("expected tag webhook to have %s label, did not find", IstioTagLabel)
}
if tag != tc.tagName {
t.Errorf("expected tag webhook to have istio.io/tag=%s, found %s instead", tc.tagName, tag)
}
// ensure all webhooks have the correct client config
for _, webhook := range wh.Webhooks {
injectionWhConf := webhook.ClientConfig
if tc.whSVC != "" {
if injectionWhConf.Service == nil {
t.Fatalf("expected injection service %s, got nil", tc.whSVC)
}
if injectionWhConf.Service.Name != tc.whSVC {
t.Fatalf("expected injection service %s, got %s", tc.whSVC, injectionWhConf.Service.Name)
}
}
if tc.whURL != "" {
if injectionWhConf.URL == nil {
t.Fatalf("expected injection URL %s, got nil", tc.whURL)
}
if *injectionWhConf.URL != tc.whURL {
t.Fatalf("expected injection URL %s, got %s", tc.whURL, *injectionWhConf.URL)
}
}
if tc.whCA != "" {
if string(injectionWhConf.CABundle) != tc.whCA {
t.Fatalf("expected CA bundle %q, got %q", tc.whCA, injectionWhConf.CABundle)
}
}
}
}
}