diff --git a/cmd/gwctl/main.go b/cmd/gwctl/main.go index f8ab4536..a520301a 100644 --- a/cmd/gwctl/main.go +++ b/cmd/gwctl/main.go @@ -60,7 +60,6 @@ func createCmd() *cobra.Command { createCmd.AddCommand(subcommand.PeerCreateCmd()) createCmd.AddCommand(subcommand.ExportCreateCmd()) createCmd.AddCommand(subcommand.ImportCreateCmd()) - createCmd.AddCommand(subcommand.BindingCreateCmd()) createCmd.AddCommand(subcommand.PolicyCreateCmd()) return createCmd } @@ -76,7 +75,6 @@ func deleteCmd() *cobra.Command { deleteCmd.AddCommand(subcommand.PeerDeleteCmd()) deleteCmd.AddCommand(subcommand.ExportDeleteCmd()) deleteCmd.AddCommand(subcommand.ImportDeleteCmd()) - deleteCmd.AddCommand(subcommand.BindingDeleteCmd()) deleteCmd.AddCommand(subcommand.PolicyDeleteCmd()) return deleteCmd } @@ -108,7 +106,6 @@ func getCmd() *cobra.Command { getCmd.AddCommand(subcommand.PeerGetCmd()) getCmd.AddCommand(subcommand.ExportGetCmd()) getCmd.AddCommand(subcommand.ImportGetCmd()) - getCmd.AddCommand(subcommand.BindingGetCmd()) getCmd.AddCommand(subcommand.PolicyGetCmd()) getCmd.AddCommand(subcommand.MetricsGetCmd()) getCmd.AddCommand(subcommand.AllGetCmd()) diff --git a/cmd/gwctl/subcommand/binding.go b/cmd/gwctl/subcommand/binding.go deleted file mode 100644 index db30706c..00000000 --- a/cmd/gwctl/subcommand/binding.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2023 The ClusterLink 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 subcommand - -import ( - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/pflag" - - "github.com/clusterlink-net/clusterlink/cmd/gwctl/config" - cmdutil "github.com/clusterlink-net/clusterlink/cmd/util" - "github.com/clusterlink-net/clusterlink/pkg/api" -) - -// bindingCreateOptions is the command line options for 'create binding'. -type bindingCreateOptions struct { - myID string - importID string - peer string -} - -// BindingCreateCmd - create a binding command. -func BindingCreateCmd() *cobra.Command { - o := bindingCreateOptions{} - cmd := &cobra.Command{ - Use: "binding", - Short: "Create binding for a imported service to remote peer", - Long: `Create binding for a imported service to remote peer`, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run() - }, - } - - o.addFlags(cmd.Flags()) - cmdutil.MarkFlagsRequired(cmd, []string{"import", "peer"}) - - return cmd -} - -// addFlags registers flags for the CLI. -func (o *bindingCreateOptions) addFlags(fs *pflag.FlagSet) { - fs.StringVar(&o.myID, "myid", "", "gwctl ID") - fs.StringVar(&o.importID, "import", "", "Imported service name to bind") - fs.StringVar(&o.peer, "peer", "", "Remote peer to import the service from") -} - -// run performs the execution of 'create binding' subcommand. -func (o *bindingCreateOptions) run() error { - g, err := config.GetClientFromID(o.myID) - if err != nil { - return err - } - - err = g.Bindings.Create(&api.Binding{ - Spec: api.BindingSpec{ - Import: o.importID, - Peer: o.peer, - }, - }) - if err != nil { - return err - } - - fmt.Printf("Binding created successfully\n") - return nil -} - -// bindingDeleteOptions is the command line options for 'delete binding'. -type bindingDeleteOptions struct { - myID string - importID string - peer string -} - -// BindingDeleteCmd - Delete a binding service command. -func BindingDeleteCmd() *cobra.Command { - o := bindingDeleteOptions{} - cmd := &cobra.Command{ - Use: "binding", - Short: "Deletes binding of a imported service to a remote peer", - Long: `Deletes binding of a imported service to a remote peer`, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run() - }, - } - - o.addFlags(cmd.Flags()) - cmdutil.MarkFlagsRequired(cmd, []string{"import"}) - - return cmd -} - -// addFlags registers flags for the CLI. -func (o *bindingDeleteOptions) addFlags(fs *pflag.FlagSet) { - fs.StringVar(&o.myID, "myid", "", "gwctl ID") - fs.StringVar(&o.importID, "import", "", "Imported service name to unbind") - fs.StringVar(&o.peer, "peer", "", "Remote peer to stop importing from") -} - -// run performs the execution of the 'delete binding' subcommand. -func (o *bindingDeleteOptions) run() error { - g, err := config.GetClientFromID(o.myID) - if err != nil { - return err - } - - err = g.Bindings.Delete(&api.Binding{ - Spec: api.BindingSpec{ - Import: o.importID, - Peer: o.peer, - }, - }) - if err != nil { - return err - } - - fmt.Printf("Binding was deleted successfully\n") - return nil -} - -// bindingGetOptions is the command line options for 'delete binding'. -type bindingGetOptions struct { - myID string - importID string -} - -// BindingGetCmd - get a binding of imported service command. -func BindingGetCmd() *cobra.Command { - o := bindingGetOptions{} - cmd := &cobra.Command{ - Use: "binding", - Short: "Get the peer list corresponding to an import", - Long: `Get the peer list corresponding to an import`, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run() - }, - } - - o.addFlags(cmd.Flags()) - cmdutil.MarkFlagsRequired(cmd, []string{"import"}) - - return cmd -} - -// addFlags registers flags for the CLI. -func (o *bindingGetOptions) addFlags(fs *pflag.FlagSet) { - fs.StringVar(&o.myID, "myid", "", "gwctl ID") - fs.StringVar(&o.importID, "import", "", "Imported service name to bind") -} - -// run performs the execution of the 'get binding' subcommand. -func (o *bindingGetOptions) run() error { - g, err := config.GetClientFromID(o.myID) - if err != nil { - return err - } - - bArr, err := g.Bindings.Get(o.importID) - if err != nil { - return err - } - - fmt.Printf("Binding of the imported service %s:\n", o.importID) - for i, b := range *bArr.(*[]api.Binding) { - fmt.Printf("%d. Peer : %s \n", i+1, b.Spec.Peer) - } - return nil -} diff --git a/cmd/gwctl/subcommand/gwctl.go b/cmd/gwctl/subcommand/gwctl.go index a419b7d4..2a93c05f 100644 --- a/cmd/gwctl/subcommand/gwctl.go +++ b/cmd/gwctl/subcommand/gwctl.go @@ -163,10 +163,9 @@ func (o *allGetOptions) run() error { } objects := map[string]*rest.Client{ - "Peers": g.Peers, - "Exports": g.Exports, - "Imports": g.Imports, - "Bindings": g.Bindings, + "Peers": g.Peers, + "Exports": g.Exports, + "Imports": g.Imports, } for name, o := range objects { diff --git a/cmd/gwctl/subcommand/import.go b/cmd/gwctl/subcommand/import.go index 66bdc169..20fbd239 100644 --- a/cmd/gwctl/subcommand/import.go +++ b/cmd/gwctl/subcommand/import.go @@ -27,10 +27,10 @@ import ( // importOptions is the command line options for 'create import' or 'update import'. type importOptions struct { - myID string - name string - host string - port uint16 + myID string + name string + port uint16 + peers []string } // ImportCreateCmd - create an imported service. @@ -73,8 +73,8 @@ func ImportUpdateCmd() *cobra.Command { func (o *importOptions) addFlags(fs *pflag.FlagSet) { fs.StringVar(&o.myID, "myid", "", "gwctl ID") fs.StringVar(&o.name, "name", "", "Imported service name") - fs.StringVar(&o.host, "host", "", "Imported service endpoint (IP/DNS), if unspecified, uses the service name") fs.Uint16Var(&o.port, "port", 0, "Imported service port") + fs.StringSliceVar(&o.peers, "peer", []string{}, "Remote peer to import the service from") } // run performs the execution of the 'create import' or 'update import' subcommand. @@ -92,10 +92,8 @@ func (o *importOptions) run(isUpdate bool) error { err = importOperation(&api.Import{ Name: o.name, Spec: api.ImportSpec{ - Service: api.Endpoint{ - Host: o.host, - Port: o.port, - }, + Port: o.port, + Peers: o.peers, }, }) if err != nil { @@ -192,7 +190,9 @@ func (o *importGetOptions) run() error { } fmt.Printf("Imported services:\n") for i, s := range *sArr.(*[]api.Import) { - fmt.Printf("%d. Imported Name: %s. Endpoint %v\n", i+1, s.Name, s.Spec.Service) + fmt.Printf( + "%d. Imported Name: %s. Port %v. TargetPort %v. Peers %v.\n", + i+1, s.Name, s.Spec.Port, s.Spec.TargetPort, s.Spec.Peers) } } else { imp, err := importClient.Imports.Get(o.name) diff --git a/demos/bookinfo/test.py b/demos/bookinfo/test.py index a2572d17..beeb73b1 100644 --- a/demos/bookinfo/test.py +++ b/demos/bookinfo/test.py @@ -113,12 +113,7 @@ def bookInfoDemo(cl1:cluster, cl2:cluster, cl3:cluster, testOutputFolder,logLeve # Import service cl1.useCluster() printHeader(f"\n\nStart import svc {reviewSvc}") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {reviewSvc} --host {reviewSvc} --port {srcK8sSvcPort} ') - - # Binding - printHeader(f"\n\nStart binding svc {reviewSvc}") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {reviewSvc} --peer {cl2.name}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {reviewSvc} --peer {cl3.name}') + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {reviewSvc} --port {srcK8sSvcPort} --peer {cl2.name} --peer {cl3.name}') # Get services cl1.useCluster() diff --git a/demos/iperf3/kind/README.md b/demos/iperf3/kind/README.md index 915d1c5b..4e91008c 100644 --- a/demos/iperf3/kind/README.md +++ b/demos/iperf3/kind/README.md @@ -150,7 +150,7 @@ First, we specify which service we want to import and specify the local k8s endp When running Kind cluster on macOS run instead the following: kubectl config use-context kind-peer1 - kubectl exec -i $GWCTL1-- gwctl create import --myid peer1 --name iperf3-server --host iperf3-server --port 5000 + kubectl exec -i $GWCTL1-- gwctl create import --myid peer1 --name iperf3-server --port 5000 Second, we specify the peer we want to import the service: diff --git a/demos/iperf3/test.py b/demos/iperf3/test.py index b4a6ff27..ea53e636 100644 --- a/demos/iperf3/test.py +++ b/demos/iperf3/test.py @@ -75,9 +75,7 @@ def iperf3Test(cl1:cluster, cl2:cluster, testOutputFolder,logLevel="info" ,datap #Import destination service printHeader(f"\n\nStart Importing {destSvc} service to {cl1.name}") - runcmd(f'gwctl --myid {cl1.name} create import --name {destSvc} --host {destSvc} --port {destPort}') - printHeader(f"\n\nStart binding {destSvc} service to {cl1.name}") - runcmd(f'gwctl --myid {cl1.name} create binding --import {destSvc} --peer {cl2.name}') + runcmd(f'gwctl --myid {cl1.name} create import --name {destSvc} --port {destPort} --peer {cl2.name}') #Add policy printHeader("Applying policies") diff --git a/demos/qotd/kind/test.py b/demos/qotd/kind/test.py index 95da6407..859b9710 100755 --- a/demos/qotd/kind/test.py +++ b/demos/qotd/kind/test.py @@ -133,30 +133,23 @@ # Import and binding Services cl1.useCluster() - printHeader(f"\n\nStart import and binding svc {quoteApp.name} to cl1 from cl2 ") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {quoteApp.name} --host {quoteApp.name} --port {quoteApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {quoteApp.name} --peer {cl2.name}') - printHeader(f"\n\nStart import and binding svc {authorApp.name} to cl1 from cl2") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {authorApp.name} --host {authorApp.name} --port {authorApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {authorApp.name} --peer {cl2.name}') - printHeader(f"\n\nStart import and binding svc {dbApp.name} to cl1 from cl2") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {dbApp.name} --host {dbApp.name} --port {dbApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {dbApp.name} --peer {cl2.name}') - printHeader(f"\n\nStart import and binding svc {imageApp.name} to cl1 from cl2") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {imageApp.name} --host {imageApp.name} --port {imageApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {imageApp.name} --peer {cl2.name}') + printHeader(f"\n\nStart import svc {quoteApp.name} to cl1 from cl2 ") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {quoteApp.name} --port {quoteApp.port} --peer {cl2.name}') + printHeader(f"\n\nStart import svc {authorApp.name} to cl1 from cl2") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {authorApp.name} --port {authorApp.port} --peer {cl2.name}') + printHeader(f"\n\nStart import svc {dbApp.name} to cl1 from cl2") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {dbApp.name} --port {dbApp.port} --peer {cl2.name}') + printHeader(f"\n\nStart import svc {imageApp.name} to cl1 from cl2") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {imageApp.name} --port {imageApp.port} --peer {cl2.name}') - printHeader(f"\n\nStart import and binding svc {pdfApp.name} to cl1 from cl3") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {pdfApp.name} --host {pdfApp.name} --port {pdfApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {pdfApp.name} --peer {cl3.name}') - printHeader(f"\n\nStart import and binding svc {ratingApp.name} to cl1 from cl3") - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {ratingApp.name} --host {ratingApp.name} --port {ratingApp.port}') - runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create binding --import {ratingApp.name} --peer {cl3.name}') + printHeader(f"\n\nStart import svc {pdfApp.name} to cl1 from cl3") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {pdfApp.name} --port {pdfApp.port} --peer {cl3.name}') + printHeader(f"\n\nStart import svc {ratingApp.name} to cl1 from cl3") + runcmd(f'kubectl exec -i {gwctl1Pod} -- gwctl create import --name {ratingApp.name} --port {ratingApp.port} --peer {cl3.name}') cl3.useCluster() - printHeader(f"\n\nStart import and binding svc {quoteApp.name} in cl3") - runcmd(f'kubectl exec -i {gwctl3Pod} -- gwctl create import --name {quoteApp.name} --host {quoteApp.name} --port {quoteApp.port}') - runcmd(f'kubectl exec -i {gwctl3Pod} -- gwctl create binding --import {quoteApp.name} --peer {cl2.name}') + printHeader(f"\n\nStart import svc {quoteApp.name} in cl3") + runcmd(f'kubectl exec -i {gwctl3Pod} -- gwctl create import --name {quoteApp.name} --port {quoteApp.port} --peer {cl2.name}') # Set policies printHeader(f"\n\nApplying policy file {allowAllPolicy}") diff --git a/demos/speedtest/kind/service_import.py b/demos/speedtest/kind/service_import.py index a5ed893b..89885526 100755 --- a/demos/speedtest/kind/service_import.py +++ b/demos/speedtest/kind/service_import.py @@ -47,15 +47,9 @@ #Import service printHeader(f"\n\nStart import svc {destSvc}") cl1.useCluster() - runcmd(f'gwctl create import --myid {cl1.name} --name {destSvc} --host {destSvc} --port 3000') + runcmd(f'gwctl create import --myid {cl1.name} --name {destSvc} --port 3000 --peer {cl2.name}') cl3.useCluster() - runcmd(f'gwctl create import --myid {cl3.name} --name {destSvc} --host {destSvc} --port 3000') - #Set K8s network services - printHeader(f"\n\nStart binding service {destSvc}") - cl1.useCluster() - runcmd(f'gwctl create binding --myid {cl1.name} --import {destSvc} --peer {cl2.name}') - cl3.useCluster() - runcmd(f'gwctl create binding --myid {cl3.name} --import {destSvc} --peer {cl2.name}') + runcmd(f'gwctl create import --myid {cl3.name} --name {destSvc} --port 3000 --peer {cl2.name}') printHeader("\n\nStart get service cl1") runcmd(f'gwctl get import --myid {cl1.name} ') diff --git a/pkg/api/types.go b/pkg/api/types.go index 0dfa3962..e89b3d09 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -82,34 +82,17 @@ type Import struct { Name string // Spec represents the attributes of the import service. Spec ImportSpec - // Status field contains the import service status. - Status ImportStatus } // ImportSpec contains all the import service attributes. type ImportSpec struct { - // Service endpoint for the import, as seen by clients in that site. - Service Endpoint -} - -// ImportStatus contains the import service status. -type ImportStatus struct { - // Listener endpoint created for the imported service. - Listener Endpoint -} - -// Binding of an imported service to a remotely exposed service from a specific Peer. -type Binding struct { - // Spec represents the attributes of the binding. - Spec BindingSpec -} - -// BindingSpec contains all the binding attributes. -type BindingSpec struct { - // Import service name. - Import string - // Peer providing the imported service. - Peer string + // Port of the imported service. + Port uint16 + // TargetPort of the imported service. + // This is the internal (non user-facing) listening port used by the dataplane pods. + TargetPort uint16 + // Peers to import from. + Peers []string } // Policy is an opaque object, to be processed by the Policy Engine. diff --git a/pkg/client/client.go b/pkg/client/client.go index 7443cf7e..34e51fc8 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -33,8 +33,6 @@ type Client struct { Exports *rest.Client // Imports client. Imports *rest.Client - // Bindings client. - Bindings *rest.Client // Access policies client. AccessPolicies *rest.Client // Load-balancing policies client. @@ -64,12 +62,6 @@ func New(host string, port uint16, tlsConfig *tls.Config) *Client { SampleObject: api.Import{}, SampleList: []api.Import{}, }), - Bindings: rest.NewClient(&rest.Config{ - Client: client, - BasePath: "/bindings", - SampleObject: []api.Binding{}, - SampleList: []api.Binding{}, - }), AccessPolicies: rest.NewClient(&rest.Config{ Client: client, BasePath: "/policies", diff --git a/pkg/controlplane/authz/manager.go b/pkg/controlplane/authz/manager.go index a1ce9735..abc29c3b 100644 --- a/pkg/controlplane/authz/manager.go +++ b/pkg/controlplane/authz/manager.go @@ -140,21 +140,23 @@ func (m *Manager) DeletePeer(name string) { func (m *Manager) AddImport(imp *v1alpha1.Import) { m.logger.Infof("Adding import '%s/%s'.", imp.Namespace, imp.Name) - for _, source := range imp.Spec.Sources { - // TODO: switch policyDecider from api.Binding to v1alpha1.Import - _ = m.policyDecider.AddBinding( - &api.Binding{ - Spec: api.BindingSpec{ - Import: imp.Name, - Peer: source.Peer, - }, - }) + // TODO: switch policyDecider from api.Import to v1alpha1.Import + peers := make([]string, len(imp.Spec.Sources)) + for i, source := range imp.Spec.Sources { + peers[i] = source.Peer } + _ = m.policyDecider.AddImport(&api.Import{ + Name: imp.Name, + Spec: api.ImportSpec{ + Peers: peers, + }, + }) } // DeleteImport removes the listening socket of a previously imported service. func (m *Manager) DeleteImport(name types.NamespacedName) error { m.logger.Infof("Deleting import '%v'.", name) + // TODO: call policyDecider.DeleteImport return nil } diff --git a/pkg/controlplane/control/manager.go b/pkg/controlplane/control/manager.go index de4ee0d6..34026125 100644 --- a/pkg/controlplane/control/manager.go +++ b/pkg/controlplane/control/manager.go @@ -87,6 +87,7 @@ func (m *Manager) AddImport(ctx context.Context, imp *v1alpha1.Import) error { // then use existing service target port instead of allocating a new port if !create && len(oldService.Spec.Ports) == 1 && imp.Spec.TargetPort == 0 { imp.Spec.TargetPort = uint16(oldService.Spec.Ports[0].TargetPort.IntVal) + newService.Spec.Ports[0].TargetPort = intstr.FromInt32(int32(imp.Spec.TargetPort)) } newPort := imp.Spec.TargetPort == 0 diff --git a/pkg/controlplane/rest/binding.go b/pkg/controlplane/rest/binding.go deleted file mode 100644 index a3a2468e..00000000 --- a/pkg/controlplane/rest/binding.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2023 The ClusterLink 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 rest - -import ( - "encoding/json" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/clusterlink-net/clusterlink/pkg/api" - "github.com/clusterlink-net/clusterlink/pkg/apis/clusterlink.net/v1alpha1" - "github.com/clusterlink-net/clusterlink/pkg/controlplane/store" -) - -type bindingHandler struct { - manager *Manager -} - -func bindingsToAPI(bindings []*store.Binding) []*api.Binding { - apiBindings := make([]*api.Binding, len(bindings)) - for i, binding := range bindings { - apiBindings[i] = &api.Binding{Spec: binding.BindingSpec} - } - return apiBindings -} - -// CreateBinding creates a binding of an imported service to a remote exported service. -func (m *Manager) CreateBinding(binding *store.Binding) error { - m.logger.Infof("Creating binding '%s'->'%s'.", binding.Import, binding.Peer) - - m.authzManager.AddImport(&v1alpha1.Import{ - ObjectMeta: metav1.ObjectMeta{Name: binding.Import}, - Spec: v1alpha1.ImportSpec{ - Sources: []v1alpha1.ImportSource{ - { - Peer: binding.Peer, - ExportName: binding.Import, - }, - }, - }, - }) - - if m.initialized { - if err := m.bindings.Create(binding); err != nil { - return err - } - } - - return nil -} - -// UpdateBinding updates a binding of an imported service to a remote exported service. -func (m *Manager) UpdateBinding(binding *store.Binding) error { - m.logger.Infof("Updating binding '%s'->'%s'.", binding.Import, binding.Peer) - - m.authzManager.AddImport(&v1alpha1.Import{ - ObjectMeta: metav1.ObjectMeta{Name: binding.Import}, - Spec: v1alpha1.ImportSpec{ - Sources: []v1alpha1.ImportSource{ - { - Peer: binding.Peer, - ExportName: binding.Import, - }, - }, - }, - }) - - err := m.bindings.Update(binding, func(old *store.Binding) *store.Binding { - return binding - }) - if err != nil { - return err - } - - return nil -} - -// GetBindings returns all bindings for a given imported service. -func (m *Manager) GetBindings(imp string) []*store.Binding { - m.logger.Infof("Getting bindings for import '%s'.", imp) - return m.bindings.Get(imp) -} - -// DeleteBinding removes a binding of an imported service to a remote exported service. -func (m *Manager) DeleteBinding(binding *store.Binding) (*store.Binding, error) { - m.logger.Infof("Deleting binding '%s'->'%s'.", binding.Import, binding.Peer) - - // TODO: m.authzManager.Delete* - - return m.bindings.Delete(binding) -} - -// GetAllBindings returns the list of all bindings. -func (m *Manager) GetAllBindings() []*store.Binding { - m.logger.Info("Listing all bindings.") - return m.bindings.GetAll() -} - -// Decode a binding. -func (h *bindingHandler) Decode(data []byte) (any, error) { - var binding api.Binding - if err := json.Unmarshal(data, &binding); err != nil { - return nil, fmt.Errorf("cannot decode binding: %w", err) - } - - if binding.Spec.Import == "" { - return nil, fmt.Errorf("empty import name") - } - - if binding.Spec.Peer == "" { - return nil, fmt.Errorf("empty peer name") - } - - return store.NewBinding(&binding), nil -} - -// Create a binding. -func (h *bindingHandler) Create(object any) error { - return h.manager.CreateBinding(object.(*store.Binding)) -} - -// Create a binding. -func (h *bindingHandler) Update(object any) error { - return h.manager.UpdateBinding(object.(*store.Binding)) -} - -// Get a binding. -func (h *bindingHandler) Get(name string) (any, error) { - binding := bindingsToAPI(h.manager.GetBindings(name)) - if binding == nil { - return nil, nil - } - return binding, nil -} - -// Delete a binding. -func (h *bindingHandler) Delete(object any) (any, error) { - return h.manager.DeleteBinding(object.(*store.Binding)) -} - -// List all bindings. -func (h *bindingHandler) List() (any, error) { - return bindingsToAPI(h.manager.GetAllBindings()), nil -} diff --git a/pkg/controlplane/rest/import.go b/pkg/controlplane/rest/import.go index 8a4e4a27..cefd8a9a 100644 --- a/pkg/controlplane/rest/import.go +++ b/pkg/controlplane/rest/import.go @@ -31,14 +31,22 @@ type importHandler struct { } func toK8SImport(imp *store.Import, namespace string) *v1alpha1.Import { + sources := make([]v1alpha1.ImportSource, len(imp.Peers)) + for i, pr := range imp.Peers { + sources[i].Peer = pr + sources[i].ExportName = imp.Name + sources[i].ExportNamespace = namespace + } + return &v1alpha1.Import{ ObjectMeta: metav1.ObjectMeta{ Name: imp.Name, Namespace: namespace, }, Spec: v1alpha1.ImportSpec{ - Port: imp.ImportSpec.Service.Port, - TargetPort: imp.Port, + Port: imp.Port, + TargetPort: imp.TargetPort, + Sources: sources, }, } } @@ -51,11 +59,6 @@ func importToAPI(imp *store.Import) *api.Import { return &api.Import{ Name: imp.Name, Spec: imp.ImportSpec, - Status: api.ImportStatus{ - Listener: api.Endpoint{ // Endpoint.Host is not set - Port: imp.Port, - }, - }, } } @@ -75,7 +78,7 @@ func (m *Manager) CreateImport(imp *store.Import) error { return err } - imp.Port = k8sImp.Spec.TargetPort + imp.TargetPort = k8sImp.Spec.TargetPort err = m.imports.Update(imp.Name, func(old *store.Import) *store.Import { return imp @@ -90,6 +93,8 @@ func (m *Manager) CreateImport(imp *store.Import) error { return err } + m.authzManager.AddImport(k8sImp) + return nil } @@ -110,7 +115,7 @@ func (m *Manager) UpdateImport(imp *store.Import) error { return err } - imp.Port = k8sImp.Spec.TargetPort + imp.TargetPort = k8sImp.Spec.TargetPort err = m.imports.Update(imp.Name, func(old *store.Import) *store.Import { return imp @@ -124,6 +129,8 @@ func (m *Manager) UpdateImport(imp *store.Import) error { return err } + m.authzManager.AddImport(k8sImp) + return nil } @@ -159,6 +166,11 @@ func (m *Manager) DeleteImport(name string) (*store.Import, error) { return nil, err } + err = m.authzManager.DeleteImport(namespacedName) + if err != nil { + return nil, err + } + return imp, nil } @@ -179,12 +191,12 @@ func (h *importHandler) Decode(data []byte) (any, error) { return nil, fmt.Errorf("empty import name") } - if imp.Spec.Service.Host == "" { - return nil, fmt.Errorf("missing service name") + if imp.Spec.Port == 0 { + return nil, fmt.Errorf("missing service port") } - if imp.Spec.Service.Port == 0 { - return nil, fmt.Errorf("missing service port") + if len(imp.Spec.Peers) == 0 { + return nil, fmt.Errorf("missing peers") } return store.NewImport(&imp), nil diff --git a/pkg/controlplane/rest/manager.go b/pkg/controlplane/rest/manager.go index 06b4ff3d..759023f4 100644 --- a/pkg/controlplane/rest/manager.go +++ b/pkg/controlplane/rest/manager.go @@ -32,7 +32,6 @@ type Manager struct { peers *cpstore.Peers exports *cpstore.Exports imports *cpstore.Imports - bindings *cpstore.Bindings acPolicies *cpstore.AccessPolicies lbPolicies *cpstore.LBPolicies @@ -68,13 +67,6 @@ func (m *Manager) init() error { } } - // add bindings - for _, binding := range m.GetAllBindings() { - if err := m.CreateBinding(binding); err != nil { - return err - } - } - // add access policies for _, policy := range m.GetAllAccessPolicies() { if err := m.CreateAccessPolicy(policy); err != nil { @@ -122,12 +114,6 @@ func NewManager( } logger.Infof("Loaded %d imports.", imports.Len()) - bindings, err := cpstore.NewBindings(storeManager) - if err != nil { - return nil, fmt.Errorf("cannot load bindings from store: %w", err) - } - logger.Infof("Loaded %d bindings.", bindings.Len()) - acPolicies, err := cpstore.NewAccessPolicies(storeManager) if err != nil { return nil, fmt.Errorf("cannot load access policies from store: %w", err) @@ -145,7 +131,6 @@ func NewManager( peers: peers, exports: exports, imports: imports, - bindings: bindings, acPolicies: acPolicies, lbPolicies: lbPolicies, xdsManager: xdsManager, diff --git a/pkg/controlplane/rest/server.go b/pkg/controlplane/rest/server.go index a731b637..875dc8f9 100644 --- a/pkg/controlplane/rest/server.go +++ b/pkg/controlplane/rest/server.go @@ -37,12 +37,6 @@ func RegisterHandlers(manager *Manager, srv *rest.Server) { DeleteByValue: false, }) - srv.AddObjectHandlers(&rest.ServerObjectSpec{ - BasePath: "/bindings", - Handler: &bindingHandler{manager: manager}, - DeleteByValue: true, - }) - srv.AddObjectHandlers(&rest.ServerObjectSpec{ BasePath: "/policies", Handler: &accessPolicyHandler{manager: manager}, diff --git a/pkg/controlplane/store/bindings.go b/pkg/controlplane/store/bindings.go deleted file mode 100644 index 5979109a..00000000 --- a/pkg/controlplane/store/bindings.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2023 The ClusterLink 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 store - -import ( - "fmt" - "sync" - - "github.com/sirupsen/logrus" - - "github.com/clusterlink-net/clusterlink/pkg/store" -) - -// Bindings is a cached persistent store of bindings. -type Bindings struct { - lock sync.RWMutex - cache map[string]map[string]*Binding - store store.ObjectStore - - logger *logrus.Entry -} - -// bindingName returns a unique name identifying the given binding. -func bindingName(binding *Binding) string { - return fmt.Sprintf("%d.%s.%s", len(binding.Import), binding.Import, binding.Peer) -} - -// Create a binding. -func (s *Bindings) Create(binding *Binding) error { - s.logger.Infof("Creating: '%s'->'%s'.", binding.Import, binding.Peer) - - if binding.Version > bindingStructVersion { - return fmt.Errorf("incompatible binding version %d, expected: %d", - binding.Version, bindingStructVersion) - } - - // persist to store - if err := s.store.Create(bindingName(binding), binding); err != nil { - return err - } - - s.lock.Lock() - defer s.lock.Unlock() - - // store in cache - valMap, ok := s.cache[binding.Import] - if !ok { - valMap = make(map[string]*Binding) - s.cache[binding.Import] = valMap - } - - valMap[binding.Peer] = binding - return nil -} - -// Update a binding. -func (s *Bindings) Update(binding *Binding, mutator func(*Binding) *Binding) error { - s.logger.Infof("Updating: '%s'->'%s'.", binding.Import, binding.Peer) - - // persist to store - err := s.store.Update(bindingName(binding), func(a any) any { - binding = mutator(a.(*Binding)) - return binding - }) - if err != nil { - return err - } - - s.lock.Lock() - defer s.lock.Unlock() - - // store in cache - valMap, ok := s.cache[binding.Import] - if !ok { - valMap = make(map[string]*Binding) - s.cache[binding.Import] = valMap - } - - valMap[binding.Peer] = binding - return nil -} - -// Get all bindings for an import. -func (s *Bindings) Get(imp string) []*Binding { - s.logger.Debugf("Getting all bindings for import '%s'.", imp) - - s.lock.RLock() - defer s.lock.RUnlock() - - var bindings []*Binding - if valMap, ok := s.cache[imp]; ok { - bindings = make([]*Binding, 0) - for _, val := range valMap { - bindings = append(bindings, val) - } - } - - return bindings -} - -// Delete a binding. -func (s *Bindings) Delete(binding *Binding) (*Binding, error) { - s.logger.Infof("Deleting: '%s'->'%s'.", binding.Import, binding.Peer) - - // delete from store - if err := s.store.Delete(bindingName(binding)); err != nil { - return nil, err - } - - s.lock.Lock() - defer s.lock.Unlock() - - // delete from cache - valMap, ok := s.cache[binding.Import] - if !ok { - return nil, nil - } - - val, ok := valMap[binding.Peer] - if !ok { - return nil, nil - } - - delete(valMap, binding.Peer) - - if len(valMap) == 0 { - delete(s.cache, binding.Import) - } - - return val, nil -} - -// GetAll returns all bindings in the cache. -func (s *Bindings) GetAll() []*Binding { - s.logger.Debug("Getting all bindings.") - - s.lock.RLock() - defer s.lock.RUnlock() - - var bindings []*Binding - for _, m := range s.cache { - for _, s := range m { - bindings = append(bindings, s) - } - } - - return bindings -} - -// Len returns the number of cached bindings. -func (s *Bindings) Len() int { - s.lock.RLock() - defer s.lock.RUnlock() - - length := 0 - for _, m := range s.cache { - length += len(m) - } - - return length -} - -// init loads the cache with items from the backing store. -func (s *Bindings) init() error { - s.logger.Info("Initializing.") - - // get all bindings from backing store - bindings, err := s.store.GetAll() - if err != nil { - return err - } - - s.lock.Lock() - defer s.lock.Unlock() - - // store all bindings to the cache - for _, object := range bindings { - if binding, ok := object.(*Binding); ok { - valMap, ok := s.cache[binding.Import] - if !ok { - valMap = make(map[string]*Binding) - s.cache[binding.Import] = valMap - } - - valMap[binding.Peer] = binding - } - } - - return nil -} - -// NewBindings returns a new cached store of bindings. -func NewBindings(manager store.Manager) (*Bindings, error) { - logger := logrus.WithField("component", "controlplane.store.bindings") - - bindings := &Bindings{ - cache: make(map[string]map[string]*Binding), - store: manager.GetObjectStore(bindingStoreName, Binding{}), - logger: logger, - } - - if err := bindings.init(); err != nil { - return nil, err - } - - return bindings, nil -} diff --git a/pkg/controlplane/store/types.go b/pkg/controlplane/store/types.go index 05b117f4..1af5871f 100644 --- a/pkg/controlplane/store/types.go +++ b/pkg/controlplane/store/types.go @@ -21,11 +21,9 @@ const ( peerStoreName = "peer" exportStoreName = "export" importStoreName = "import" - bindingStoreName = "binding" accessPolicyStoreName = "accessPolicy" lbPolicyStoreName = "lbPolicy" - bindingStructVersion = 1 exportStructVersion = 1 importStructVersion = 1 peerStructVersion = 1 @@ -76,8 +74,6 @@ type Import struct { Name string // Version of the struct when object was created. Version uint32 - // Port is the port where the imported service should listen on. - Port uint16 } // NewImport creates a new import. @@ -89,21 +85,6 @@ func NewImport(imp *api.Import) *Import { } } -// Binding of an imported service to a remote exported service. -type Binding struct { - api.BindingSpec - // Version of the struct when object was created. - Version uint32 -} - -// NewBinding creates a new binding. -func NewBinding(binding *api.Binding) *Binding { - return &Binding{ - BindingSpec: binding.Spec, - Version: bindingStructVersion, - } -} - // AccessPolicy to allow/deny specific connections. type AccessPolicy struct { api.Policy diff --git a/pkg/policyengine/PolicyDispatcher.go b/pkg/policyengine/PolicyDispatcher.go index 7fde85e9..327c99fc 100644 --- a/pkg/policyengine/PolicyDispatcher.go +++ b/pkg/policyengine/PolicyDispatcher.go @@ -48,8 +48,8 @@ type PolicyDecider interface { AddPeer(name string) DeletePeer(name string) - AddBinding(imp *api.Binding) policytypes.PolicyAction - DeleteBinding(imp *api.Binding) + AddImport(imp *api.Import) policytypes.PolicyAction + DeleteImport(imp *api.Import) AddExport(exp *api.Export) ([]string, error) // Returns a list of peers to which export is allowed DeleteExport(name string) @@ -177,13 +177,17 @@ func (pH *PolicyHandler) DeletePeer(name string) { plog.Infof("Removed Peer %s", name) } -func (pH *PolicyHandler) AddBinding(binding *api.Binding) policytypes.PolicyAction { - pH.loadBalancer.AddToServiceMap(binding.Spec.Import, binding.Spec.Peer) +func (pH *PolicyHandler) AddImport(imp *api.Import) policytypes.PolicyAction { + for _, pr := range imp.Spec.Peers { + pH.loadBalancer.AddToServiceMap(imp.Name, pr) + } return policytypes.ActionAllow } -func (pH *PolicyHandler) DeleteBinding(binding *api.Binding) { - pH.loadBalancer.RemoveDestService(binding.Spec.Import, binding.Spec.Peer) +func (pH *PolicyHandler) DeleteImport(imp *api.Import) { + for _, pr := range imp.Spec.Peers { + pH.loadBalancer.RemoveDestService(imp.Name, pr) + } } func (pH *PolicyHandler) AddExport(_ *api.Export) ([]string, error) { diff --git a/pkg/policyengine/PolicyDispatcher_test.go b/pkg/policyengine/PolicyDispatcher_test.go index f4360505..bc6f5960 100644 --- a/pkg/policyengine/PolicyDispatcher_test.go +++ b/pkg/policyengine/PolicyDispatcher_test.go @@ -266,12 +266,22 @@ func TestDisableEnablePeers(t *testing.T) { func addRemoteSvc(t *testing.T, svc, peer string, ph policyengine.PolicyDecider) { t.Helper() ph.AddPeer(peer) // just in case it was not already added - action := ph.AddBinding(&api.Binding{Spec: api.BindingSpec{Import: svc, Peer: peer}}) + action := ph.AddImport(&api.Import{ + Name: svc, + Spec: api.ImportSpec{ + Peers: []string{peer}, + }, + }) require.Equal(t, policytypes.ActionAllow, action) } func removeRemoteSvc(svc, peer string, ph policyengine.PolicyDecider) { - ph.DeleteBinding(&api.Binding{Spec: api.BindingSpec{Import: svc, Peer: peer}}) + ph.DeleteImport(&api.Import{ + Name: svc, + Spec: api.ImportSpec{ + Peers: []string{peer}, + }, + }) } func addPolicy(t *testing.T, policy *policytypes.ConnectivityPolicy, ph policyengine.PolicyDecider) { diff --git a/tests/e2e/k8s/test_basic.go b/tests/e2e/k8s/test_basic.go index e3696249..eee5ab74 100644 --- a/tests/e2e/k8s/test_basic.go +++ b/tests/e2e/k8s/test_basic.go @@ -43,7 +43,7 @@ func (s *TestSuite) TestConnectivityCRD() { Name: httpEchoService.Name, Port: 80, } - require.Nil(s.T(), cl[1].CreateImportCRD(importedService, cl[0], httpEchoService.Name)) + require.Nil(s.T(), cl[1].CreateImport(importedService, cl[0], httpEchoService.Name)) data, err := cl[1].AccessService(httpecho.GetEchoValue, importedService, true, nil) require.Nil(s.T(), err) @@ -64,9 +64,8 @@ func (s *TestSuite) TestConnectivity() { Name: "echo", Port: 80, } - require.Nil(s.T(), cl[1].CreateImport("echo", importedService)) + require.Nil(s.T(), cl[1].CreateImport(importedService, cl[0], httpEchoService.Name)) - require.Nil(s.T(), cl[1].CreateBinding("echo", cl[0])) require.Nil(s.T(), cl[1].CreatePolicy(util.PolicyAllowAll)) data, err := cl[1].AccessService(httpecho.GetEchoValue, importedService, true, nil) @@ -88,10 +87,8 @@ func (s *TestSuite) TestControlplaneCRUD() { imp := api.Import{ Name: "echo", Spec: api.ImportSpec{ - Service: api.Endpoint{ - Host: "echo", - Port: 1234, - }, + Port: 1234, + Peers: []string{cl[1].Name()}, }, } @@ -114,8 +111,8 @@ func (s *TestSuite) TestControlplaneCRUD() { require.NotNil(s.T(), client0.Imports.Create(&imp)) importedService := &util.Service{ - Name: imp.Spec.Service.Host, - Port: imp.Spec.Service.Port, + Name: imp.Name, + Port: imp.Spec.Port, } accessService := func(allowRetry bool, expectedError error) (string, error) { @@ -132,67 +129,15 @@ func (s *TestSuite) TestControlplaneCRUD() { require.Nil(s.T(), err) importFromServer := *objects.(*api.Import) require.Equal(s.T(), importFromServer.Name, imp.Name) - require.Equal(s.T(), importFromServer.Spec, imp.Spec) - require.Equal(s.T(), importFromServer.Status.Listener.Host, "") - require.NotZero(s.T(), importFromServer.Status.Listener.Port) + require.Equal(s.T(), importFromServer.Spec.Port, imp.Spec.Port) + require.Equal(s.T(), importFromServer.Spec.Peers, imp.Spec.Peers) + require.NotZero(s.T(), importFromServer.Spec.TargetPort) // list imports objects, err = client0.Imports.List() require.Nil(s.T(), err) require.ElementsMatch(s.T(), *objects.(*[]api.Import), []api.Import{importFromServer}) - // test binding API - binding := api.Binding{ - Spec: api.BindingSpec{ - Import: imp.Name, - Peer: cl[1].Name(), - }, - } - - // list bindings when empty - objects, err = client0.Bindings.List() - require.Nil(s.T(), err) - require.Empty(s.T(), objects.(*[]api.Binding)) - - // get non-existing binding - _, err = client0.Bindings.Get(binding.Spec.Import) - require.Nil(s.T(), err) - require.Empty(s.T(), objects.(*[]api.Binding)) - - // delete non-existing binding - require.NotNil(s.T(), client0.Bindings.Delete(&binding)) - // update non-existing binding - require.NotNil(s.T(), client0.Bindings.Update(&binding)) - // create binding - require.Nil(s.T(), client0.Bindings.Create(&binding)) - // create binding which already exists - require.NotNil(s.T(), client0.Bindings.Create(&binding)) - // update binding - require.Nil(s.T(), client0.Bindings.Update(&binding)) - - // verify no access - _, err = accessService(false, &services.ConnectionResetError{}) - require.ErrorIs(s.T(), err, &services.ConnectionResetError{}) - - // add another binding (for testing binding get vs list) - binding2 := api.Binding{ - Spec: api.BindingSpec{ - Import: "dummy", - Peer: "dummy", - }, - } - require.Nil(s.T(), client0.Bindings.Create(&binding2)) - - // get bindings - objects, err = client0.Bindings.Get(binding.Spec.Import) - require.Nil(s.T(), err) - require.ElementsMatch(s.T(), *objects.(*[]api.Binding), []api.Binding{binding}) - - // list bindings - objects, err = client0.Bindings.List() - require.Nil(s.T(), err) - require.ElementsMatch(s.T(), *objects.(*[]api.Binding), []api.Binding{binding, binding2}) - // test peer API peer := api.Peer{ Name: cl[1].Name(), @@ -386,13 +331,8 @@ func (s *TestSuite) TestControlplaneCRUD() { require.NotNil(s.T(), client0.LBPolicies.Create(&lbPolicy)) // create false binding to verify LB policy - binding3 := api.Binding{ - Spec: api.BindingSpec{ - Import: imp.Name, - Peer: cl[2].Name(), - }, - } - require.Nil(s.T(), client0.Bindings.Create(&binding3)) + imp.Spec.Peers = append(imp.Spec.Peers, cl[2].Name()) + require.Nil(s.T(), client0.Imports.Update(&imp)) // verify access str, err = accessService(false, nil) @@ -409,34 +349,16 @@ func (s *TestSuite) TestControlplaneCRUD() { require.Nil(s.T(), err) require.ElementsMatch(s.T(), *objects.(*[]api.Policy), []api.Policy{lbPolicy}) - // TODO: currently broken - // // update import port - // imp.Spec.Service.Port++ - // require.Nil(s.T(), client0.Imports.Update(&imp)) - // // verify no access to previous port - // _, err = accessService(true, &services.ConnectionRefusedError{}) - // require.ErrorIs(s.T(), err, &services.ConnectionRefusedError{}) - // // verify access to new port - // importedService.Port++ - // _, err = accessService(true, nil) - // require.Nil(s.T(), err) - // - // // update import host - // imp.Spec.Service.Host += "2" - // require.Nil(s.T(), client0.Imports.Update(&imp)) - // // verify no access to previous host - // _, err = accessService(true, &services.ServiceNotFoundError{}) - // require.ErrorIs(s.T(), err, &services.ServiceNotFoundError{}) - // // verify access to new host - // importedService.Name += "2" - // _, err = accessService(true, nil) - // require.Nil(s.T(), err) - // // get import after update - // objects, err = client0.Imports.Get(imp.Name) - // require.Nil(s.T(), err) - // require.Equal(s.T(), objects.(*api.Import).Spec, imp.Spec) - // require.Equal(s.T(), objects.(*api.Import).Status, importFromServer.Status) - // importFromServer = *objects.(*api.Import) + // update import port + imp.Spec.Port++ + require.Nil(s.T(), client0.Imports.Update(&imp)) + // verify no access to previous port + _, err = accessService(true, &services.ConnectionRefusedError{}) + require.ErrorIs(s.T(), err, &services.ConnectionRefusedError{}) + // verify access to new port + importedService.Port++ + _, err = accessService(true, nil) + require.Nil(s.T(), err) // update peer peer.Spec.Gateways[0].Port++ @@ -538,23 +460,6 @@ func (s *TestSuite) TestControlplaneCRUD() { require.Nil(s.T(), err) require.Equal(s.T(), str, cl[1].Name()) - // TODO: currently broken - // // delete binding - // require.Nil(s.T(), client0.Bindings.Delete(&binding)) - // // get binding after delete - // objects, err = client0.Bindings.Get(imp.Name) - // require.Nil(s.T(), err) - // require.ElementsMatch(s.T(), *objects.(*[]api.Binding), []api.Binding{binding3}) - // // verify no access after delete - // _, err = accessService(false, &services.ConnectionResetError{}) - // require.ErrorIs(s.T(), err, &services.ConnectionResetError{}) - // // re-create binding - // require.Nil(s.T(), client0.Bindings.Create(&binding)) - // // verify access after re-create - // str, err = accessService(false, nil) - // require.Nil(s.T(), err) - // require.Equal(s.T(), str, cl[1].Name()) - // delete peer require.Nil(s.T(), client0.Peers.Delete(peer.Name)) // get peer after delete @@ -626,11 +531,6 @@ func (s *TestSuite) TestControlplaneCRUD() { require.Nil(s.T(), err) require.ElementsMatch(s.T(), *objects.(*[]api.Import), []api.Import{importFromServer}) - // verify bindings after restart - objects, err = client0.Bindings.List() - require.Nil(s.T(), err) - require.ElementsMatch(s.T(), *objects.(*[]api.Binding), []api.Binding{binding, binding2, binding3}) - // verify peers after restart objects, err = client0.Peers.List() require.Nil(s.T(), err) diff --git a/tests/e2e/k8s/test_operator.go b/tests/e2e/k8s/test_operator.go index 623434b6..74febf83 100644 --- a/tests/e2e/k8s/test_operator.go +++ b/tests/e2e/k8s/test_operator.go @@ -67,8 +67,8 @@ func (s *TestSuite) TestOperator() { Name: "echo", Port: 80, } - require.Nil(s.T(), cl[1].CreateImport("echo", importedService)) - require.Nil(s.T(), cl[1].CreateBinding("echo", cl[0])) + require.Nil(s.T(), cl[1].CreateImport(importedService, cl[0], httpEchoService.Name)) + require.Nil(s.T(), cl[1].CreatePolicy(util.PolicyAllowAll)) data, err := cl[1].AccessService(httpecho.GetEchoValue, importedService, true, nil) diff --git a/tests/e2e/k8s/test_performance.go b/tests/e2e/k8s/test_performance.go index 68a833e1..f8e111d1 100644 --- a/tests/e2e/k8s/test_performance.go +++ b/tests/e2e/k8s/test_performance.go @@ -46,9 +46,8 @@ func (s *TestSuite) TestPerformance() { Namespace: cl[1].Namespace(), Port: 80, } - require.Nil(s.T(), cl[1].CreateImport("iperf3", importedService)) + require.Nil(s.T(), cl[1].CreateImport(importedService, cl[0], httpEchoService.Name)) - require.Nil(s.T(), cl[1].CreateBinding("iperf3", cl[0])) require.Nil(s.T(), cl[1].CreatePolicy(util.PolicyAllowAll)) bps, err := iperf3.RunClient(cl[1].Cluster(), importedService) diff --git a/tests/e2e/k8s/util/clusterlink.go b/tests/e2e/k8s/util/clusterlink.go index aeb64487..0f37924e 100644 --- a/tests/e2e/k8s/util/clusterlink.go +++ b/tests/e2e/k8s/util/clusterlink.go @@ -298,46 +298,60 @@ func (c *ClusterLink) DeleteExport(name string) error { return c.client.Exports.Delete(name) } -// TODO: merge this function with CreateImport. -func (c *ClusterLink) CreateImportCRD(service *Service, peer *ClusterLink, exportName string) error { - return c.cluster.Resources().Create( - context.Background(), - &v1alpha1.Import{ - ObjectMeta: metav1.ObjectMeta{ - Name: service.Name, - Namespace: c.namespace, - }, - Spec: v1alpha1.ImportSpec{ - Port: service.Port, - Sources: []v1alpha1.ImportSource{{ - Peer: peer.Name(), - ExportName: exportName, - ExportNamespace: peer.Namespace(), - }}, - }, - }) -} +func (c *ClusterLink) CreateImport(service *Service, peer *ClusterLink, exportName string) error { + if c.crdMode { + return c.cluster.Resources().Create( + context.Background(), + &v1alpha1.Import{ + ObjectMeta: metav1.ObjectMeta{ + Name: service.Name, + Namespace: c.namespace, + }, + Spec: v1alpha1.ImportSpec{ + Port: service.Port, + Sources: []v1alpha1.ImportSource{{ + Peer: peer.Name(), + ExportName: exportName, + ExportNamespace: peer.Namespace(), + }}, + }, + }) + } -func (c *ClusterLink) CreateImport(name string, service *Service) error { return c.client.Imports.Create(&api.Import{ - Name: name, + Name: service.Name, Spec: api.ImportSpec{ - Service: api.Endpoint{ - Host: service.Name, - Port: service.Port, - }, + Port: service.Port, + Peers: []string{peer.Name()}, }, }) } -func (c *ClusterLink) UpdateImport(name string, service *Service) error { +func (c *ClusterLink) UpdateImport(service *Service, peer *ClusterLink, exportName string) error { + if c.crdMode { + return c.cluster.Resources().Update( + context.Background(), + &v1alpha1.Import{ + ObjectMeta: metav1.ObjectMeta{ + Name: service.Name, + Namespace: c.namespace, + }, + Spec: v1alpha1.ImportSpec{ + Port: service.Port, + Sources: []v1alpha1.ImportSource{{ + Peer: peer.Name(), + ExportName: exportName, + ExportNamespace: peer.Namespace(), + }}, + }, + }) + } + return c.client.Imports.Update(&api.Import{ - Name: name, + Name: service.Name, Spec: api.ImportSpec{ - Service: api.Endpoint{ - Host: service.Name, - Port: service.Port, - }, + Port: service.Port, + Peers: []string{peer.Name()}, }, }) } @@ -364,51 +378,6 @@ func (c *ClusterLink) DeleteImport(name string) error { return c.client.Imports.Delete(name) } -func (c *ClusterLink) CreateBinding(imp string, peer *ClusterLink) error { - return c.client.Bindings.Create(&api.Binding{ - Spec: api.BindingSpec{ - Import: imp, - Peer: peer.Name(), - }, - }) -} - -func (c *ClusterLink) UpdateBinding(imp string, peer *ClusterLink) error { - return c.client.Bindings.Update(&api.Binding{ - Spec: api.BindingSpec{ - Import: imp, - Peer: peer.Name(), - }, - }) -} - -func (c *ClusterLink) GetBindings(name string) (*[]api.Binding, error) { - res, err := c.client.Bindings.Get(name) - if err != nil { - return nil, err - } - - return res.(*[]api.Binding), nil -} - -func (c *ClusterLink) GetAllBindings() (*[]api.Binding, error) { - res, err := c.client.Bindings.List() - if err != nil { - return nil, err - } - - return res.(*[]api.Binding), nil -} - -func (c *ClusterLink) DeleteBinding(imp string, peer *ClusterLink) error { - return c.client.Bindings.Delete(&api.Binding{ - Spec: api.BindingSpec{ - Import: imp, - Peer: peer.Name(), - }, - }) -} - func (c *ClusterLink) CreateAccessPolicy(accessPolicy *v1alpha1.AccessPolicy) error { if accessPolicy.Namespace == "" { accessPolicyCopy := *accessPolicy diff --git a/tests/k8s.sh b/tests/k8s.sh index 61aceb11..351c3767 100755 --- a/tests/k8s.sh +++ b/tests/k8s.sh @@ -75,8 +75,7 @@ function test_k8s { # import kubectl exec -i gwctl -- gwctl create peer --host cl-dataplane --port 443 --name peer1 - kubectl exec -i gwctl -- gwctl create import --name foo --host bla --port 9999 - kubectl exec -i gwctl -- gwctl create binding --import foo --peer peer1 + kubectl exec -i gwctl -- gwctl create import --name bla --port 9999 --peer peer1 kubectl cp $SCRIPT_DIR/../pkg/policyengine/policytypes/examples/allowAll.json gwctl:/tmp/allowAll.json kubectl exec -i gwctl -- gwctl create policy --type access --policyFile /tmp/allowAll.json