blob: f59ebac492a26174b41a766e9aed26f739b8dff9 [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 controller
import (
"context"
"fmt"
"strings"
"testing"
"time"
)
import (
meshconfig "istio.io/api/mesh/v1alpha1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
mcsapi "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/features"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/model"
"github.com/apache/dubbo-go-pixiu/pkg/config/mesh"
"github.com/apache/dubbo-go-pixiu/pkg/kube"
"github.com/apache/dubbo-go-pixiu/pkg/kube/mcs"
"github.com/apache/dubbo-go-pixiu/pkg/test/util/retry"
)
var serviceExportTimeout = retry.Timeout(time.Second * 2)
func TestServiceExportController(t *testing.T) {
client := kube.NewFakeClient()
// Configure the environment with cluster-local hosts.
m := meshconfig.MeshConfig{
ServiceSettings: []*meshconfig.MeshConfig_ServiceSettings{
{
Settings: &meshconfig.MeshConfig_ServiceSettings_Settings{
ClusterLocal: true,
},
Hosts: []string{"*.unexportable-ns.svc.cluster.local", "unexportable-svc.*.svc.cluster.local"},
},
},
}
env := model.Environment{Watcher: mesh.NewFixedWatcher(&m)}
env.Init()
sc := newAutoServiceExportController(autoServiceExportOptions{
Client: client,
ClusterID: "",
DomainSuffix: env.DomainSuffix,
ClusterLocal: env.ClusterLocal(),
})
stop := make(chan struct{})
t.Cleanup(func() {
close(stop)
})
client.RunAndWait(stop)
sc.Run(stop)
t.Run("exportable", func(t *testing.T) {
createSimpleService(t, client, "exportable-ns", "foo")
assertServiceExport(t, client, "exportable-ns", "foo", true)
})
t.Run("unexportable", func(t *testing.T) {
createSimpleService(t, client, "unexportable-ns", "foo")
assertServiceExport(t, client, "unexportable-ns", "foo", false)
})
t.Run("no overwrite", func(t *testing.T) {
// manually create serviceexport
export := mcsapi.ServiceExport{
TypeMeta: metav1.TypeMeta{
Kind: "ServiceExport",
APIVersion: features.MCSAPIVersion,
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "exportable-ns",
Name: "manual-export",
},
Status: mcsapi.ServiceExportStatus{
Conditions: []mcsapi.ServiceExportCondition{
{
Type: mcsapi.ServiceExportValid,
},
},
},
}
_, err := client.Dynamic().Resource(mcs.ServiceExportGVR).Namespace("exportable-ns").Create(
context.TODO(), toUnstructured(&export), metav1.CreateOptions{})
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
// create the associated service
// no need for assertions, just trying to ensure no errors
createSimpleService(t, client, "exportable-ns", "manual-export")
// assert that we didn't wipe out the pre-existing serviceexport status
assertServiceExportHasCondition(t, client, "exportable-ns", "manual-export",
mcsapi.ServiceExportValid)
})
}
func createSimpleService(t *testing.T, client kubernetes.Interface, ns string, name string) {
t.Helper()
if _, err := client.CoreV1().Services(ns).Create(context.TODO(), &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
}, metav1.CreateOptions{}); err != nil {
t.Fatal(err)
}
}
func assertServiceExport(t *testing.T, client kube.Client, ns, name string, shouldBePresent bool) {
t.Helper()
retry.UntilSuccessOrFail(t, func() error {
got, err := client.Dynamic().Resource(mcs.ServiceExportGVR).Namespace(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil && !strings.Contains(err.Error(), "not found") {
return fmt.Errorf("unexpected error %v", err)
}
isPresent := got != nil
if isPresent != shouldBePresent {
return fmt.Errorf("unexpected serviceexport state. IsPresent: %v, ShouldBePresent: %v, name: %v, namespace: %v", isPresent, shouldBePresent, name, ns)
}
return nil
}, serviceExportTimeout)
}
func assertServiceExportHasCondition(t *testing.T, client kube.Client, ns, name string, condition mcsapi.ServiceExportConditionType) {
t.Helper()
retry.UntilSuccessOrFail(t, func() error {
gotU, err := client.Dynamic().Resource(mcs.ServiceExportGVR).Namespace(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("unexpected error %v", err)
}
got := &mcsapi.ServiceExport{}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(gotU.Object, got); err != nil {
return err
}
if got.Status.Conditions == nil || len(got.Status.Conditions) == 0 || got.Status.Conditions[0].Type != condition {
return fmt.Errorf("condition incorrect or not found")
}
return nil
}, serviceExportTimeout)
}