diff --git a/go.mod b/go.mod index f09da326..a7b9a0b0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ferryproxy/ferry go 1.18 require ( - github.com/ferryproxy/api v0.4.2 + github.com/ferryproxy/api v0.4.3-0.20220929110018-87b27802e21a github.com/ferryproxy/client-go v0.4.0 github.com/go-logr/logr v1.2.3 github.com/go-logr/zapr v1.2.3 diff --git a/go.sum b/go.sum index d86d9105..c7f4e6f4 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/ferryproxy/api v0.4.2 h1:2SBq/ljIzL6TeyoiM3OjO0Bnx0J2f5g+CUjoLWWyano= -github.com/ferryproxy/api v0.4.2/go.mod h1:vFqYueEfIwpU2o3Y8/ryKKn5S3WBR4wVgHgh21zwpeQ= +github.com/ferryproxy/api v0.4.3-0.20220929110018-87b27802e21a h1:FwMc7CdF8u+EWEnJMiZXEeDu3pqsjSfLn65Iun6iuuE= +github.com/ferryproxy/api v0.4.3-0.20220929110018-87b27802e21a/go.mod h1:vFqYueEfIwpU2o3Y8/ryKKn5S3WBR4wVgHgh21zwpeQ= github.com/ferryproxy/client-go v0.4.0 h1:pTlCUc7Q77d99yNru01WbKe8Ie8sBSpDO/h4ZmMW5gk= github.com/ferryproxy/client-go v0.4.0/go.mod h1:A0DBMIJFYM4j+qvgHxTamZH3m56xfmuDnC+8E2gOtto= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= diff --git a/pkg/controllers/route/mapping_controller.go b/pkg/controllers/route/mapping_controller.go index 183360e3..79c45ce9 100644 --- a/pkg/controllers/route/mapping_controller.go +++ b/pkg/controllers/route/mapping_controller.go @@ -18,7 +18,6 @@ package route import ( "context" - "fmt" "strings" "sync" "time" @@ -38,8 +37,6 @@ import ( ) type HubInterface interface { - GetService(hubName string, namespace, name string) (*corev1.Service, bool) - ListServices(name string) []*corev1.Service GetHub(name string) *v1alpha2.Hub GetHubGateway(hubName string, forHub string) v1alpha2.HubSpecGateway GetAuthorized(name string) string @@ -420,15 +417,7 @@ func (m *MappingController) Close() { } func (m *MappingController) updatePort(f *v1alpha2.Route) error { - svc, ok := m.hubInterface.GetService(f.Spec.Export.HubName, f.Spec.Export.Service.Namespace, f.Spec.Export.Service.Name) - if !ok { - return fmt.Errorf("not found export service") - } - - for _, port := range svc.Spec.Ports { - if port.Protocol != corev1.ProtocolTCP { - continue - } + for _, port := range f.Spec.Import.Ports { _, err := m.hubInterface.GetPortPeer(f.Spec.Import.HubName, f.Spec.Export.HubName, f.Spec.Export.Service.Namespace, f.Spec.Export.Service.Name, port.Port) if err != nil { @@ -439,14 +428,7 @@ func (m *MappingController) updatePort(f *v1alpha2.Route) error { } func (m *MappingController) deletePort(f *v1alpha2.Route) error { - svc, ok := m.hubInterface.GetService(f.Spec.Export.HubName, f.Spec.Export.Service.Namespace, f.Spec.Export.Service.Name) - if !ok { - return fmt.Errorf("not found export service") - } - for _, port := range svc.Spec.Ports { - if port.Protocol != corev1.ProtocolTCP { - continue - } + for _, port := range f.Spec.Import.Ports { _, err := m.hubInterface.DeletePortPeer(f.Spec.Import.HubName, f.Spec.Export.HubName, f.Spec.Export.Service.Namespace, f.Spec.Export.Service.Name, port.Port) if err == nil { diff --git a/pkg/controllers/route_policy/mirror_tunnel.go b/pkg/controllers/route_policy/mirror_tunnel.go index a33fd526..106f63e8 100644 --- a/pkg/controllers/route_policy/mirror_tunnel.go +++ b/pkg/controllers/route_policy/mirror_tunnel.go @@ -57,6 +57,12 @@ func buildMirrorTunnelRoute(hub *v1alpha2.Hub, importHubName string) *v1alpha2.R Namespace: "ferry-tunnel-system", Name: "ferry-tunnel", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Name: "http", + Port: 8080, + }, + }, }, Import: v1alpha2.RouteSpecRule{ HubName: importHubName, @@ -64,6 +70,12 @@ func buildMirrorTunnelRoute(hub *v1alpha2.Hub, importHubName string) *v1alpha2.R Namespace: "ferry-tunnel-system", Name: hub.Name + "-ferry-tunnel", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Name: "http", + Port: 8080, + }, + }, }, }, } diff --git a/pkg/controllers/route_policy/route_policy_controller.go b/pkg/controllers/route_policy/route_policy_controller.go index e18c3f46..ade99e54 100644 --- a/pkg/controllers/route_policy/route_policy_controller.go +++ b/pkg/controllers/route_policy/route_policy_controller.go @@ -365,6 +365,16 @@ func policiesToRoutes(hubInterface HubInterface, policies []*v1alpha2.RoutePolic policy := match.Policy + var ports []v1alpha2.RouteSpecRulePort + for _, port := range svc.Spec.Ports { + if port.Protocol == "" || port.Protocol == corev1.ProtocolTCP { + ports = append(ports, v1alpha2.RouteSpecRulePort{ + Name: port.Name, + Port: port.Port, + }) + } + } + suffix := hash(fmt.Sprintf("%s|%s|%s|%s|%s|%s", exportHubName, exportNamespace, exportName, importHubName, importNamespace, importName)) @@ -390,6 +400,7 @@ func policiesToRoutes(hubInterface HubInterface, policies []*v1alpha2.RoutePolic Name: importName, Namespace: importNamespace, }, + Ports: ports, }, Export: v1alpha2.RouteSpecRule{ HubName: exportHubName, @@ -397,6 +408,7 @@ func policiesToRoutes(hubInterface HubInterface, policies []*v1alpha2.RoutePolic Name: exportName, Namespace: exportNamespace, }, + Ports: ports, }, }, }) diff --git a/pkg/ferryctl/control_plane/init_crd.yaml b/pkg/ferryctl/control_plane/init_crd.yaml index 933b0440..9b28227d 100644 --- a/pkg/ferryctl/control_plane/init_crd.yaml +++ b/pkg/ferryctl/control_plane/init_crd.yaml @@ -554,6 +554,23 @@ spec: hubName: description: HubName is specifies the name of the Hub type: string + ports: + description: The list of ports that are exposed by export service. + items: + description: RouteSpecRulePort contains information on service's + port. + properties: + name: + description: The name of this port within the service. + type: string + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + required: + - port + type: object + type: array service: description: Service is the service properties: @@ -577,6 +594,23 @@ spec: hubName: description: HubName is specifies the name of the Hub type: string + ports: + description: The list of ports that are exposed by export service. + items: + description: RouteSpecRulePort contains information on service's + port. + properties: + name: + description: The name of this port within the service. + type: string + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + required: + - port + type: object + type: array service: description: Service is the service properties: diff --git a/pkg/router/manual.go b/pkg/router/manual.go index aa6978ed..e6f6060d 100644 --- a/pkg/router/manual.go +++ b/pkg/router/manual.go @@ -19,7 +19,6 @@ package router import ( "github.com/ferryproxy/api/apis/traffic/v1alpha2" "github.com/ferryproxy/ferry/pkg/utils/objref" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -86,29 +85,6 @@ func (f *dateSource) GetPortPeer(importHubName string, cluster, namespace, name return f.bindPort, nil } -func (f *dateSource) ListServices(name string) []*corev1.Service { - if name != f.exportHubName { - return nil - } - svc := &corev1.Service{ - - ObjectMeta: metav1.ObjectMeta{ - Name: f.exportName, - Namespace: f.exportNamespace, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Port: f.port, - Protocol: corev1.ProtocolTCP, - }, - }, - }, - } - return []*corev1.Service{ - svc, - } -} func (f *dateSource) GetHubGateway(hubName string, forHub string) v1alpha2.HubSpecGateway { if hubName == f.importHubName { return f.importGateway @@ -156,6 +132,11 @@ func (f *Manual) BuildResource() (out map[string][]objref.KMetadata, err error) Name: f.dateSource.importName, Namespace: f.dateSource.importNamespace, }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: f.dateSource.port, + }, + }, }, Export: v1alpha2.RouteSpecRule{ HubName: f.dateSource.exportHubName, @@ -163,6 +144,11 @@ func (f *Manual) BuildResource() (out map[string][]objref.KMetadata, err error) Name: f.dateSource.exportName, Namespace: f.dateSource.exportNamespace, }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: f.dateSource.port, + }, + }, }, }, }, diff --git a/pkg/router/router.go b/pkg/router/router.go index 61c8bc60..28ae3507 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -30,7 +30,6 @@ import ( ) type HubInterface interface { - ListServices(name string) []*corev1.Service GetHubGateway(hubName string, forHub string) v1alpha2.HubSpecGateway GetAuthorized(name string) string GetPortPeer(importHubName string, cluster, namespace, name string, port int32) (int32, error) @@ -66,16 +65,8 @@ type Router struct { hubsChain *HubsChain } -func (d *Router) BuildResource(rules []*v1alpha2.Route, ways []string) (out map[string][]objref.KMetadata, err error) { - mappings := map[objref.ObjectRef][]*v1alpha2.Route{} - - for _, rule := range rules { - exportRef := objref.ObjectRef{Name: rule.Spec.Export.Service.Name, Namespace: rule.Spec.Export.Service.Namespace} - mappings[exportRef] = append(mappings[exportRef], rule) - } - +func (d *Router) BuildResource(routes []*v1alpha2.Route, ways []string) (out map[string][]objref.KMetadata, err error) { out = map[string][]objref.KMetadata{} - svcs := d.hubInterface.ListServices(d.exportHubName) labelsForRules := maps.Merge(d.labels, map[string]string{ consts.TunnelConfigKey: consts.TunnelConfigRulesValue, @@ -90,79 +81,78 @@ func (d *Router) BuildResource(rules []*v1alpha2.Route, ways []string) (out map[ consts.TunnelConfigKey: consts.TunnelConfigDiscoverValue, }) - for _, svc := range svcs { - origin := objref.KObj(svc) - for _, rule := range mappings[origin] { - destination := objref.ObjectRef{Name: rule.Spec.Import.Service.Name, Namespace: rule.Spec.Import.Service.Namespace} - - peerPortMapping := map[int32]int32{} - - for _, port := range svc.Spec.Ports { - - peerPort, err := d.hubInterface.GetPortPeer(d.importHubName, d.exportHubName, origin.Namespace, origin.Name, port.Port) - if err != nil { - return nil, err - } - peerPortMapping[port.Port] = peerPort - - tunnelName := fmt.Sprintf("%s-tunnel-%d-%d", rule.Name, port.Port, peerPort) - hubsBound, err := d.hubsChain.Build(tunnelName, origin, destination, port.Port, peerPort, ways) - if err != nil { - return nil, err - } - resources, err := ConvertOutboundToResourcers(tunnelName, consts.FerryTunnelNamespace, labelsForRules, hubsBound) - if err != nil { - return nil, err - } - for k, res := range resources { - out[k] = append(out[k], res...) - } - - allowName := fmt.Sprintf("%s-allows-%d-%d", rule.Name, port.Port, peerPort) - resources, err = ConvertInboundToResourcers(allowName, consts.FerryTunnelNamespace, labelsForAllow, hubsBound) - if err != nil { - return nil, err - } - for k, res := range resources { - out[k] = append(out[k], res...) - } - - authNameSuffix := "authorized" - resources, err = ConvertInboundAuthorizedToResourcers(authNameSuffix, consts.FerryTunnelNamespace, labelsForAuth, hubsBound, d.hubInterface.GetAuthorized) - if err != nil { - return nil, err - } - for k, res := range resources { - out[k] = append(out[k], res...) - } - } + for _, route := range routes { + destination := objref.ObjectRef{Name: route.Spec.Import.Service.Name, Namespace: route.Spec.Import.Service.Namespace} + origin := objref.ObjectRef{Name: route.Spec.Export.Service.Name, Namespace: route.Spec.Export.Service.Namespace} - serviceName := fmt.Sprintf("%s-service", rule.Name) + peerPortMapping := map[int32]int32{} + + for _, port := range route.Spec.Export.Ports { + + peerPort, err := d.hubInterface.GetPortPeer(d.importHubName, d.exportHubName, origin.Namespace, origin.Name, port.Port) + if err != nil { + return nil, err + } + peerPortMapping[port.Port] = peerPort - ports := buildPorts(peerPortMapping, &svc.Spec) + tunnelName := fmt.Sprintf("%s-tunnel-%d-%d", route.Name, port.Port, peerPort) + hubsBound, err := d.hubsChain.Build(tunnelName, origin, destination, port.Port, peerPort, ways) + if err != nil { + return nil, err + } + resources, err := ConvertOutboundToResourcers(tunnelName, consts.FerryTunnelNamespace, labelsForRules, hubsBound) + if err != nil { + return nil, err + } + for k, res := range resources { + out[k] = append(out[k], res...) + } - svcConfig := discovery.Service{ - ExportHubName: d.exportHubName, - ExportServiceNamespace: origin.Namespace, - ExportServiceName: origin.Name, - ImportServiceNamespace: destination.Namespace, - ImportServiceName: destination.Name, - Ports: ports, + allowName := fmt.Sprintf("%s-allows-%d-%d", route.Name, port.Port, peerPort) + resources, err = ConvertInboundToResourcers(allowName, consts.FerryTunnelNamespace, labelsForAllow, hubsBound) + if err != nil { + return nil, err } - data, err := svcConfig.ToMap() + for k, res := range resources { + out[k] = append(out[k], res...) + } + + authNameSuffix := "authorized" + resources, err = ConvertInboundAuthorizedToResourcers(authNameSuffix, consts.FerryTunnelNamespace, labelsForAuth, hubsBound, d.hubInterface.GetAuthorized) if err != nil { return nil, err } - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: serviceName, - Namespace: consts.FerryTunnelNamespace, - Labels: labelsForDiscover, - }, - Data: data, + for k, res := range resources { + out[k] = append(out[k], res...) } - out[d.importHubName] = append(out[d.importHubName], configMap) } + + serviceName := fmt.Sprintf("%s-service", route.Name) + + ports := buildPorts(peerPortMapping, route.Spec.Import.Ports) + + svcConfig := discovery.Service{ + ExportHubName: d.exportHubName, + ExportServiceNamespace: origin.Namespace, + ExportServiceName: origin.Name, + ImportServiceNamespace: destination.Namespace, + ImportServiceName: destination.Name, + Ports: ports, + } + data, err := svcConfig.ToMap() + if err != nil { + return nil, err + } + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceName, + Namespace: consts.FerryTunnelNamespace, + Labels: labelsForDiscover, + }, + Data: data, + } + out[d.importHubName] = append(out[d.importHubName], configMap) + } for name := range out { @@ -171,17 +161,14 @@ func (d *Router) BuildResource(rules []*v1alpha2.Route, ways []string) (out map[ return out, nil } -func buildPorts(peerPortMapping map[int32]int32, spec *corev1.ServiceSpec) []discovery.MappingPort { +func buildPorts(peerPortMapping map[int32]int32, importPorts []v1alpha2.RouteSpecRulePort) []discovery.MappingPort { ports := []discovery.MappingPort{} - for _, port := range spec.Ports { - if port.Protocol != corev1.ProtocolTCP { - continue - } + for _, port := range importPorts { svcPort := peerPortMapping[port.Port] ports = append(ports, discovery.MappingPort{ Name: port.Name, Port: port.Port, - Protocol: string(port.Protocol), + Protocol: "TCP", TargetPort: svcPort, }) } diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go index 4b1daf6c..cbd69175 100644 --- a/pkg/router/router_test.go +++ b/pkg/router/router_test.go @@ -39,23 +39,6 @@ func TestRouter(t *testing.T) { { name: "self", args: fakeRouter{ - Services: []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "svc1", - Namespace: "test", - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - Protocol: corev1.ProtocolTCP, - }, - }, - }, - }, - }, Hubs: []*v1alpha2.Hub{ { ObjectMeta: metav1.ObjectMeta{ @@ -82,6 +65,11 @@ func TestRouter(t *testing.T) { Name: "svc1-new", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, Export: v1alpha2.RouteSpecRule{ HubName: "self", @@ -89,6 +77,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, }, }, @@ -111,7 +104,7 @@ func TestRouter(t *testing.T) { "export_service_namespace": "test", "import_service_name": "svc1-new", "import_service_namespace": "test", - "ports": `[{"name":"http","protocol":"TCP","port":80,"targetPort":10001}]`, + "ports": `[{"protocol":"TCP","port":80,"targetPort":10001}]`, }, }, &corev1.ConfigMap{ @@ -143,23 +136,6 @@ func TestRouter(t *testing.T) { { name: "export reachable", args: fakeRouter{ - Services: []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "svc1", - Namespace: "test", - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - Protocol: corev1.ProtocolTCP, - }, - }, - }, - }, - }, Hubs: []*v1alpha2.Hub{ { ObjectMeta: metav1.ObjectMeta{ @@ -213,6 +189,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, Export: v1alpha2.RouteSpecRule{ HubName: "export", @@ -220,6 +201,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, }, }, @@ -279,7 +265,7 @@ func TestRouter(t *testing.T) { "export_service_namespace": "test", "import_service_name": "svc1", "import_service_namespace": "test", - "ports": `[{"name":"http","protocol":"TCP","port":80,"targetPort":10001}]`, + "ports": `[{"protocol":"TCP","port":80,"targetPort":10001}]`, }, }, &corev1.ConfigMap{ @@ -314,23 +300,6 @@ func TestRouter(t *testing.T) { { name: "import reachable", args: fakeRouter{ - Services: []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "svc1", - Namespace: "test", - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - Protocol: corev1.ProtocolTCP, - }, - }, - }, - }, - }, Hubs: []*v1alpha2.Hub{ { ObjectMeta: metav1.ObjectMeta{ @@ -384,6 +353,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, Export: v1alpha2.RouteSpecRule{ HubName: "export", @@ -391,6 +365,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, }, }, @@ -447,7 +426,7 @@ func TestRouter(t *testing.T) { "export_service_namespace": "test", "import_service_name": "svc1", "import_service_namespace": "test", - "ports": `[{"name":"http","protocol":"TCP","port":80,"targetPort":10001}]`, + "ports": `[{"protocol":"TCP","port":80,"targetPort":10001}]`, }, }, }, @@ -484,23 +463,6 @@ func TestRouter(t *testing.T) { { name: "proxy reachable", args: fakeRouter{ - Services: []*corev1.Service{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "svc1", - Namespace: "test", - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - Protocol: corev1.ProtocolTCP, - }, - }, - }, - }, - }, Hubs: []*v1alpha2.Hub{ { ObjectMeta: metav1.ObjectMeta{ @@ -557,6 +519,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, Export: v1alpha2.RouteSpecRule{ HubName: "export", @@ -564,6 +531,11 @@ func TestRouter(t *testing.T) { Name: "svc1", Namespace: "test", }, + Ports: []v1alpha2.RouteSpecRulePort{ + { + Port: 80, + }, + }, }, }, }, @@ -611,7 +583,7 @@ func TestRouter(t *testing.T) { "export_service_namespace": "test", "import_service_name": "svc1", "import_service_namespace": "test", - "ports": `[{"name":"http","protocol":"TCP","port":80,"targetPort":10001}]`, + "ports": `[{"protocol":"TCP","port":80,"targetPort":10001}]`, }, }, &corev1.ConfigMap{ @@ -720,9 +692,8 @@ func toJson(c interface{}) string { } type fakeRouter struct { - Services []*corev1.Service - Hubs []*v1alpha2.Hub - Routes []*v1alpha2.Route + Hubs []*v1alpha2.Hub + Routes []*v1alpha2.Route } func (f *fakeRouter) BuildResource() (out map[string][]objref.KMetadata, err error) { @@ -732,7 +703,6 @@ func (f *fakeRouter) BuildResource() (out map[string][]objref.KMetadata, err err } fake := &fakeHubInterface{ - services: f.Services, hubs: hubs, port: 10000, portCache: map[string]int{},