diff --git a/topo/node/node.go b/topo/node/node.go index 1a84aaf1..91bed61a 100644 --- a/topo/node/node.go +++ b/topo/node/node.go @@ -364,7 +364,7 @@ func (n *Impl) CreateService(ctx context.Context) error { sp.NodePort = int32(v.NodePort) } if v.Outside != 0 { - sp.TargetPort = intstr.FromInt(int(v.Outside)) + sp.Port = int32(v.Outside) } servicePorts = append(servicePorts, sp) } diff --git a/topo/node/node_test.go b/topo/node/node_test.go index 2303b70b..967fe227 100644 --- a/topo/node/node_test.go +++ b/topo/node/node_test.go @@ -4,6 +4,15 @@ import ( "context" "testing" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/h-fam/errdiff" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + kfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/rest" + topopb "github.com/openconfig/kne/proto/topo" ) @@ -50,3 +59,153 @@ func TestReset(t *testing.T) { t.Errorf("Not-Resettable node type asserted to resetter") } } + +func TestService(t *testing.T) { + tests := []struct { + desc string + node *topopb.Node + kClient *kfake.Clientset + wantCreateErr string + wantServiceErr string + want []*corev1.Service + }{{ + desc: "no services", + node: &topopb.Node{Name: "dev1", Type: topopb.Node_Type(1001)}, + kClient: kfake.NewSimpleClientset(), + wantServiceErr: `"service-dev1" not found`, + }, { + desc: "services valid", + node: &topopb.Node{ + Name: "dev1", + Type: topopb.Node_Type(1001), + Services: map[uint32]*topopb.Service{ + 22: { + Name: "ssh", + Inside: 22, + }, + }, + }, + kClient: kfake.NewSimpleClientset(), + want: []*corev1.Service{{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "service-dev1", + Namespace: "test", + Labels: map[string]string{"pod": "dev1"}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{ + Name: "ssh", + Protocol: "TCP", + Port: 22, + TargetPort: intstr.FromInt(22), + NodePort: 0, + }}, + Selector: map[string]string{"app": "dev1"}, + Type: "LoadBalancer", + }, + }}, + }, { + desc: "services valid multiple mappings", + node: &topopb.Node{ + Name: "dev2", + Type: topopb.Node_Type(1001), + Services: map[uint32]*topopb.Service{ + 9339: { + Name: "gnmi", + Inside: 9339, + Outside: 9339, + }, + 9337: { + Name: "gnoi", + Inside: 9339, + Outside: 9337, + }, + }, + }, + kClient: kfake.NewSimpleClientset(), + want: []*corev1.Service{{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "service-dev2", + Namespace: "test", + Labels: map[string]string{"pod": "dev2"}, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{ + Name: "gnmi", + Protocol: "TCP", + Port: 9339, + TargetPort: intstr.FromInt(9339), + NodePort: 0, + }, { + Name: "gnoi", + Protocol: "TCP", + Port: 9337, + TargetPort: intstr.FromInt(9339), + NodePort: 0, + }}, + Selector: map[string]string{"app": "dev2"}, + Type: "LoadBalancer", + }, + }}, + }, { + desc: "failed create duplicate", + node: &topopb.Node{ + Name: "dev1", + Type: topopb.Node_Type(1001), + Services: map[uint32]*topopb.Service{ + 22: { + Name: "ssh", + Inside: 22, + }, + }, + }, + kClient: kfake.NewSimpleClientset(&corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "service-dev1", + Namespace: "test", + }, + }), + wantCreateErr: `"service-dev1" already exists`, + }} + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + n := &Impl{ + Namespace: "test", + KubeClient: tt.kClient, + RestConfig: &rest.Config{}, + Proto: tt.node, + BasePath: "", + Kubecfg: "", + } + err := n.CreateService(context.Background()) + if s := errdiff.Check(err, tt.wantCreateErr); s != "" { + t.Fatalf("CreateService() failed: %s", s) + } + if tt.wantServiceErr != "" { + return + } + + got, err := n.Services(context.Background()) + if s := errdiff.Check(err, tt.wantServiceErr); s != "" { + t.Fatalf("Services() failed: %s", s) + } + if tt.wantCreateErr != "" { + return + } + if s := cmp.Diff(tt.want, got, + cmpopts.SortSlices(func(a, b corev1.ServicePort) bool { + return a.Name < b.Name + })); s != "" { + t.Fatalf("Services() failed: %s", s) + } + }) + } +}