diff --git a/pkg/networkservice/chains/nsmgr/heal_test.go b/pkg/networkservice/chains/nsmgr/heal_test.go index dc15157d9..aba6a1d70 100644 --- a/pkg/networkservice/chains/nsmgr/heal_test.go +++ b/pkg/networkservice/chains/nsmgr/heal_test.go @@ -579,7 +579,9 @@ func testNSMGRCloseHeal(t *testing.T, withNSEExpiration bool) { if withNSEExpiration { // 3.1 Wait for the endpoint expiration time.Sleep(time.Second) - c := client.NewNetworkServiceEndpointRegistryClient(ctx, domain.Nodes[0].NSMgr.URL, client.WithDialOptions(sandbox.DialOptions(sandbox.WithTokenGenerator(sandbox.GenerateTestToken))...)) + c := client.NewNetworkServiceEndpointRegistryClient(ctx, + client.WithClientURL(domain.Nodes[0].NSMgr.URL), + client.WithDialOptions(sandbox.DialOptions(sandbox.WithTokenGenerator(sandbox.GenerateTestToken))...)) stream, err := c.Find(ctx, ®istry.NetworkServiceEndpointQuery{ NetworkServiceEndpoint: ®istry.NetworkServiceEndpoint{ diff --git a/pkg/networkservice/chains/nsmgr/suite_test.go b/pkg/networkservice/chains/nsmgr/suite_test.go index 5c1489f39..e484f1fdd 100644 --- a/pkg/networkservice/chains/nsmgr/suite_test.go +++ b/pkg/networkservice/chains/nsmgr/suite_test.go @@ -161,7 +161,8 @@ func (s *nsmgrSuite) Test_SelectsRestartingEndpointUsecase() { }) require.NoError(t, err) - nseRegistryClient := registryclient.NewNetworkServiceEndpointRegistryClient(ctx, sandbox.CloneURL(s.domain.Nodes[0].NSMgr.URL), + nseRegistryClient := registryclient.NewNetworkServiceEndpointRegistryClient(ctx, + registryclient.WithClientURL(sandbox.CloneURL(s.domain.Nodes[0].NSMgr.URL)), registryclient.WithDialOptions(sandbox.DialOptions()...)) nseReg, err = nseRegistryClient.Register(ctx, nseReg) diff --git a/pkg/registry/chains/client/ns_client.go b/pkg/registry/chains/client/ns_client.go index dc06db29e..37c00c1dc 100644 --- a/pkg/registry/chains/client/ns_client.go +++ b/pkg/registry/chains/client/ns_client.go @@ -18,24 +18,25 @@ package client import ( "context" - "net/url" "time" "github.com/networkservicemesh/api/pkg/api/registry" "github.com/networkservicemesh/sdk/pkg/registry/common/begin" "github.com/networkservicemesh/sdk/pkg/registry/common/clientconn" - "github.com/networkservicemesh/sdk/pkg/registry/common/clienturl" "github.com/networkservicemesh/sdk/pkg/registry/common/connect" "github.com/networkservicemesh/sdk/pkg/registry/common/dial" "github.com/networkservicemesh/sdk/pkg/registry/common/heal" + "github.com/networkservicemesh/sdk/pkg/registry/common/null" "github.com/networkservicemesh/sdk/pkg/registry/common/retry" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" ) // NewNetworkServiceRegistryClient creates a new NewNetworkServiceRegistryClient that can be used for NS registration. -func NewNetworkServiceRegistryClient(ctx context.Context, connectTo *url.URL, opts ...Option) registry.NetworkServiceRegistryClient { - clientOpts := new(clientOptions) +func NewNetworkServiceRegistryClient(ctx context.Context, opts ...Option) registry.NetworkServiceRegistryClient { + clientOpts := &clientOptions{ + nsClientURLResolver: null.NewNetworkServiceRegistryClient(), + } for _, opt := range opts { opt(clientOpts) } @@ -46,7 +47,7 @@ func NewNetworkServiceRegistryClient(ctx context.Context, connectTo *url.URL, op begin.NewNetworkServiceRegistryClient(), retry.NewNetworkServiceRegistryClient(ctx), heal.NewNetworkServiceRegistryClient(ctx), - clienturl.NewNetworkServiceRegistryClient(connectTo), + clientOpts.nsClientURLResolver, clientconn.NewNetworkServiceRegistryClient(), dial.NewNetworkServiceRegistryClient(ctx, dial.WithDialOptions(clientOpts.dialOptions...), diff --git a/pkg/registry/chains/client/nse_client.go b/pkg/registry/chains/client/nse_client.go index 1157eb12f..ec1e1e015 100644 --- a/pkg/registry/chains/client/nse_client.go +++ b/pkg/registry/chains/client/nse_client.go @@ -19,24 +19,25 @@ package client import ( "context" - "net/url" "github.com/networkservicemesh/api/pkg/api/registry" "github.com/networkservicemesh/sdk/pkg/registry/common/begin" "github.com/networkservicemesh/sdk/pkg/registry/common/clientconn" - "github.com/networkservicemesh/sdk/pkg/registry/common/clienturl" "github.com/networkservicemesh/sdk/pkg/registry/common/connect" "github.com/networkservicemesh/sdk/pkg/registry/common/dial" "github.com/networkservicemesh/sdk/pkg/registry/common/heal" + "github.com/networkservicemesh/sdk/pkg/registry/common/null" "github.com/networkservicemesh/sdk/pkg/registry/common/refresh" "github.com/networkservicemesh/sdk/pkg/registry/common/retry" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" ) // NewNetworkServiceEndpointRegistryClient creates a new NewNetworkServiceEndpointRegistryClient that can be used for NSE registration. -func NewNetworkServiceEndpointRegistryClient(ctx context.Context, connectTo *url.URL, opts ...Option) registry.NetworkServiceEndpointRegistryClient { - clientOpts := new(clientOptions) +func NewNetworkServiceEndpointRegistryClient(ctx context.Context, opts ...Option) registry.NetworkServiceEndpointRegistryClient { + clientOpts := &clientOptions{ + nseClientURLResolver: null.NewNetworkServiceEndpointRegistryClient(), + } for _, opt := range opts { opt(clientOpts) } @@ -48,7 +49,7 @@ func NewNetworkServiceEndpointRegistryClient(ctx context.Context, connectTo *url retry.NewNetworkServiceEndpointRegistryClient(ctx), heal.NewNetworkServiceEndpointRegistryClient(ctx), refresh.NewNetworkServiceEndpointRegistryClient(ctx), - clienturl.NewNetworkServiceEndpointRegistryClient(connectTo), + clientOpts.nseClientURLResolver, clientconn.NewNetworkServiceEndpointRegistryClient(), dial.NewNetworkServiceEndpointRegistryClient(ctx, dial.WithDialOptions(clientOpts.dialOptions...), diff --git a/pkg/registry/chains/client/option.go b/pkg/registry/chains/client/option.go index c1049a0d0..e5c7858de 100644 --- a/pkg/registry/chains/client/option.go +++ b/pkg/registry/chains/client/option.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Doc.ai and/or its affiliates. +// Copyright (c) 2021-2022 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -17,13 +17,40 @@ package client import ( - "github.com/networkservicemesh/api/pkg/api/registry" + "net/url" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/registry" + + "github.com/networkservicemesh/sdk/pkg/registry/common/clienturl" ) // Option is an option pattern for NewNetworkServiceRegistryClient, NewNetworkServiceEndpointRegistryClient type Option func(clientOpts *clientOptions) +// WithClientURL sets client URL +func WithClientURL(u *url.URL) Option { + return func(clientOpts *clientOptions) { + clientOpts.nsClientURLResolver = clienturl.NewNetworkServiceRegistryClient(u) + clientOpts.nseClientURLResolver = clienturl.NewNetworkServiceEndpointRegistryClient(u) + } +} + +// WithNSClientURLResolver sets ns client URL resolver +func WithNSClientURLResolver(c registry.NetworkServiceRegistryClient) Option { + return func(clientOpts *clientOptions) { + clientOpts.nsClientURLResolver = c + } +} + +// WithNSEClientURLResolver sets nse client URL resolver +func WithNSEClientURLResolver(c registry.NetworkServiceEndpointRegistryClient) Option { + return func(clientOpts *clientOptions) { + clientOpts.nseClientURLResolver = c + } +} + // WithNSAdditionalFunctionality sets additional functionality func WithNSAdditionalFunctionality(additionalFunctionality ...registry.NetworkServiceRegistryClient) Option { return func(clientOpts *clientOptions) { @@ -46,6 +73,8 @@ func WithDialOptions(dialOptions ...grpc.DialOption) Option { } type clientOptions struct { + nsClientURLResolver registry.NetworkServiceRegistryClient + nseClientURLResolver registry.NetworkServiceEndpointRegistryClient nsAdditionalFunctionality []registry.NetworkServiceRegistryClient nseAdditionalFunctionality []registry.NetworkServiceEndpointRegistryClient dialOptions []grpc.DialOption diff --git a/pkg/registry/common/dnsresolve/ns_client.go b/pkg/registry/common/dnsresolve/ns_client.go new file mode 100644 index 000000000..5fbb10d6a --- /dev/null +++ b/pkg/registry/common/dnsresolve/ns_client.go @@ -0,0 +1,127 @@ +// Copyright (c) 2022 Cisco Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 dnsresolve + +import ( + "context" + "errors" + "net" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/registry" + + "github.com/networkservicemesh/sdk/pkg/registry/core/next" + + "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" + "github.com/networkservicemesh/sdk/pkg/tools/interdomain" +) + +type dnsNSResolveClient struct { + resolver Resolver + registryService string +} + +// NewNetworkServiceRegistryClient creates new NetworkServiceRegistryClient that can resolve passed domain to clienturl +func NewNetworkServiceRegistryClient(opts ...Option) registry.NetworkServiceRegistryClient { + var clientOptions = &options{ + resolver: net.DefaultResolver, + registryService: DefaultRegistryService, + } + + for _, opt := range opts { + opt(clientOptions) + } + + r := &dnsNSResolveClient{ + resolver: clientOptions.resolver, + registryService: clientOptions.registryService, + } + + return r +} + +func (d *dnsNSResolveClient) Register(ctx context.Context, ns *registry.NetworkService, opts ...grpc.CallOption) (*registry.NetworkService, error) { + domain := interdomain.Domain(ns.Name) + url, err := resolveDomain(ctx, d.registryService, domain, d.resolver) + if err != nil { + return nil, err + } + ctx = clienturlctx.WithClientURL(ctx, url) + ns.Name = interdomain.Target(ns.Name) + resp, err := next.NetworkServiceRegistryClient(ctx).Register(ctx, ns, opts...) + if err != nil { + return nil, err + } + + resp.Name = interdomain.Join(resp.Name, domain) + + return resp, err +} + +type dnsNSResolveFindClient struct { + registry.NetworkServiceRegistry_FindClient + domain string +} + +func (c *dnsNSResolveFindClient) Recv() (*registry.NetworkServiceResponse, error) { + resp, err := c.NetworkServiceRegistry_FindClient.Recv() + if err != nil { + return resp, err + } + resp.NetworkService.Name = interdomain.Join(resp.NetworkService.Name, c.domain) + + return resp, err +} + +func (d *dnsNSResolveClient) Find(ctx context.Context, q *registry.NetworkServiceQuery, opts ...grpc.CallOption) (registry.NetworkServiceRegistry_FindClient, error) { + domain := interdomain.Domain(q.NetworkService.Name) + if domain == "" { + return nil, errors.New("domain cannot be empty") + } + url, err := resolveDomain(ctx, d.registryService, domain, d.resolver) + if err != nil { + return nil, err + } + ctx = clienturlctx.WithClientURL(ctx, url) + q.NetworkService.Name = interdomain.Target(q.NetworkService.Name) + + resp, err := next.NetworkServiceRegistryClient(ctx).Find(ctx, q, opts...) + if err != nil { + return nil, err + } + + return &dnsNSResolveFindClient{ + NetworkServiceRegistry_FindClient: resp, + domain: domain, + }, nil +} + +func (d *dnsNSResolveClient) Unregister(ctx context.Context, ns *registry.NetworkService, opts ...grpc.CallOption) (*empty.Empty, error) { + domain := interdomain.Domain(ns.Name) + url, err := resolveDomain(ctx, d.registryService, domain, d.resolver) + if err != nil { + return nil, err + } + ctx = clienturlctx.WithClientURL(ctx, url) + ns.Name = interdomain.Target(ns.Name) + defer func() { + ns.Name = interdomain.Join(ns.Name, domain) + }() + return next.NetworkServiceRegistryClient(ctx).Unregister(ctx, ns, opts...) +} diff --git a/pkg/registry/common/dnsresolve/ns_server.go b/pkg/registry/common/dnsresolve/ns_server.go index b904741b2..847b93c4a 100644 --- a/pkg/registry/common/dnsresolve/ns_server.go +++ b/pkg/registry/common/dnsresolve/ns_server.go @@ -65,6 +65,9 @@ func (d *dnsNSResolveServer) Register(ctx context.Context, ns *registry.NetworkS ctx = clienturlctx.WithClientURL(ctx, url) ns.Name = interdomain.Target(ns.Name) resp, err := next.NetworkServiceRegistryServer(ctx).Register(ctx, ns) + if err != nil { + return nil, err + } resp.Name = interdomain.Join(resp.Name, domain) diff --git a/pkg/registry/common/dnsresolve/nse_client.go b/pkg/registry/common/dnsresolve/nse_client.go new file mode 100644 index 000000000..1a26e56f7 --- /dev/null +++ b/pkg/registry/common/dnsresolve/nse_client.go @@ -0,0 +1,136 @@ +// Copyright (c) 2022 Cisco Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 dnsresolve + +import ( + "context" + "net" + + "github.com/networkservicemesh/api/pkg/api/registry" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/grpc" + + "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" + "github.com/networkservicemesh/sdk/pkg/tools/interdomain" + + "github.com/networkservicemesh/sdk/pkg/registry/core/next" +) + +type dnsNSEResolveClient struct { + resolver Resolver + registryService string +} + +// NewNetworkServiceEndpointRegistryClient creates new NetworkServiceEndpointRegistryClient that can resolve passed domain to clienturl +func NewNetworkServiceEndpointRegistryClient(opts ...Option) registry.NetworkServiceEndpointRegistryClient { + var clientOptions = &options{ + resolver: net.DefaultResolver, + registryService: DefaultRegistryService, + } + + for _, opt := range opts { + opt(clientOptions) + } + + r := &dnsNSEResolveClient{ + resolver: clientOptions.resolver, + registryService: clientOptions.registryService, + } + + return r +} + +func (d *dnsNSEResolveClient) Register(ctx context.Context, nse *registry.NetworkServiceEndpoint, opts ...grpc.CallOption) (*registry.NetworkServiceEndpoint, error) { + var domain = resolveNSE(nse) + var u, err = resolveDomain(ctx, d.registryService, domain, d.resolver) + + if err != nil { + return nil, err + } + + ctx = clienturlctx.WithClientURL(ctx, u) + + translateNSE(nse, interdomain.Target) + + resp, err := next.NetworkServiceEndpointRegistryClient(ctx).Register(ctx, nse, opts...) + + if err != nil { + return nil, err + } + + translateNSE(resp, func(s string) string { + return interdomain.Join(s, domain) + }) + + return resp, err +} + +type dnsNSEResolveFindClient struct { + registry.NetworkServiceEndpointRegistry_FindClient + domain string +} + +func (c *dnsNSEResolveFindClient) Recv() (*registry.NetworkServiceEndpointResponse, error) { + resp, err := c.NetworkServiceEndpointRegistry_FindClient.Recv() + if err != nil { + return resp, err + } + + translateNSE(resp.NetworkServiceEndpoint, func(str string) string { + return interdomain.Join(str, c.domain) + }) + + return resp, err +} + +func (d *dnsNSEResolveClient) Find(ctx context.Context, q *registry.NetworkServiceEndpointQuery, opts ...grpc.CallOption) (registry.NetworkServiceEndpointRegistry_FindClient, error) { + var domain = resolveNSE(q.NetworkServiceEndpoint) + var nsmgrProxyURL, err = resolveDomain(ctx, d.registryService, domain, d.resolver) + + if err != nil { + return nil, err + } + + ctx = clienturlctx.WithClientURL(ctx, nsmgrProxyURL) + translateNSE(q.NetworkServiceEndpoint, interdomain.Target) + + resp, err := next.NetworkServiceEndpointRegistryClient(ctx).Find(ctx, q, opts...) + if err != nil { + return nil, err + } + + return &dnsNSEResolveFindClient{ + NetworkServiceEndpointRegistry_FindClient: resp, + domain: domain, + }, nil +} + +func (d *dnsNSEResolveClient) Unregister(ctx context.Context, nse *registry.NetworkServiceEndpoint, opts ...grpc.CallOption) (*empty.Empty, error) { + var domain = resolveNSE(nse) + var u, err = resolveDomain(ctx, d.registryService, domain, d.resolver) + + if err != nil { + return nil, err + } + + ctx = clienturlctx.WithClientURL(ctx, u) + + translateNSE(nse, interdomain.Target) + + return next.NetworkServiceEndpointRegistryServer(ctx).Unregister(ctx, nse) +} diff --git a/pkg/registry/common/heal/find_test.go b/pkg/registry/common/heal/find_test.go index 34c556f56..20c942e03 100644 --- a/pkg/registry/common/heal/find_test.go +++ b/pkg/registry/common/heal/find_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Doc.ai and/or its affiliates. +// Copyright (c) 2021-2022 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -64,7 +64,8 @@ func TestHealClient_FindTest(t *testing.T) { // 1. Create NS, NSE find clients findCtx, findCancel := context.WithCancel(ctx) - nsRegistryClient := registryclient.NewNetworkServiceRegistryClient(ctx, sandbox.CloneURL(domain.Nodes[0].NSMgr.URL), + nsRegistryClient := registryclient.NewNetworkServiceRegistryClient(ctx, + registryclient.WithClientURL(sandbox.CloneURL(domain.Nodes[0].NSMgr.URL)), registryclient.WithDialOptions(sandbox.DialOptions()...)) nsRespStream, err := nsRegistryClient.Find(findCtx, ®istry.NetworkServiceQuery{ @@ -73,7 +74,8 @@ func TestHealClient_FindTest(t *testing.T) { }) require.NoError(t, err) - nseRegistryClient := registryclient.NewNetworkServiceEndpointRegistryClient(ctx, sandbox.CloneURL(domain.Nodes[0].NSMgr.URL), + nseRegistryClient := registryclient.NewNetworkServiceEndpointRegistryClient(ctx, + registryclient.WithClientURL(sandbox.CloneURL(domain.Nodes[0].NSMgr.URL)), registryclient.WithDialOptions(sandbox.DialOptions()...)) nseRespStream, err := nseRegistryClient.Find(findCtx, ®istry.NetworkServiceEndpointQuery{ diff --git a/pkg/registry/common/retry/ns_client.go b/pkg/registry/common/retry/ns_client.go index 14454d016..c0cf26ccc 100644 --- a/pkg/registry/common/retry/ns_client.go +++ b/pkg/registry/common/retry/ns_client.go @@ -59,7 +59,7 @@ func (r *retryNSClient) Register(ctx context.Context, in *registry.NetworkServic for ctx.Err() == nil && r.chainCtx.Err() == nil { registerCtx, cancel := c.WithTimeout(ctx, r.tryTimeout) - resp, err := next.NetworkServiceRegistryClient(registerCtx).Register(registerCtx, in, opts...) + resp, err := next.NetworkServiceRegistryClient(registerCtx).Register(registerCtx, in.Clone(), opts...) cancel() if err != nil { diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index 8b56050f8..9af355122 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -122,12 +122,15 @@ func (n *Node) NewForwarder( URL: serveURL, } nseClient := chain.NewNetworkServiceEndpointRegistryClient( - registryclient.NewNetworkServiceEndpointRegistryClient(ctx, CloneURL(n.NSMgr.URL), + registryclient.NewNetworkServiceEndpointRegistryClient(ctx, + registryclient.WithClientURL(CloneURL(n.NSMgr.URL)), registryclient.WithNSEAdditionalFunctionality(recvfd.NewNetworkServiceEndpointRegistryClient()), registryclient.WithDialOptions(dialOptions...), ), ) - nsClient := registryclient.NewNetworkServiceRegistryClient(ctx, CloneURL(n.NSMgr.URL), registryclient.WithDialOptions(dialOptions...)) + nsClient := registryclient.NewNetworkServiceRegistryClient(ctx, + registryclient.WithClientURL(CloneURL(n.NSMgr.URL)), + registryclient.WithDialOptions(dialOptions...)) entry.restartableServer = newRestartableServer(ctx, n.t, entry.URL, func(ctx context.Context) { entry.Endpoint = endpoint.NewServer(ctx, generatorFunc, endpoint.WithName(entry.Name), @@ -158,7 +161,7 @@ func (n *Node) NewForwarder( entry.NetworkServiceEndpointRegistryClient = registryclient.NewNetworkServiceEndpointRegistryClient( ctx, - CloneURL(n.NSMgr.URL), + registryclient.WithClientURL(CloneURL(n.NSMgr.URL)), registryclient.WithDialOptions(dialOptions...), ) @@ -206,7 +209,7 @@ func (n *Node) NewEndpoint( entry.NetworkServiceEndpointRegistryClient = registryclient.NewNetworkServiceEndpointRegistryClient( ctx, - CloneURL(n.NSMgr.URL), + registryclient.WithClientURL(CloneURL(n.NSMgr.URL)), registryclient.WithDialOptions(dialOptions...), registryclient.WithNSEAdditionalFunctionality(sendfd.NewNetworkServiceEndpointRegistryClient()), ) diff --git a/pkg/tools/sandbox/types.go b/pkg/tools/sandbox/types.go index e17aba236..fbe690de4 100644 --- a/pkg/tools/sandbox/types.go +++ b/pkg/tools/sandbox/types.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -100,6 +100,7 @@ func (d *Domain) NewNSRegistryClient(ctx context.Context, generatorFunc token.Ge return nil } - return registryclient.NewNetworkServiceRegistryClient(ctx, registryURL, + return registryclient.NewNetworkServiceRegistryClient(ctx, + registryclient.WithClientURL(registryURL), registryclient.WithDialOptions(DialOptions(WithTokenGenerator(generatorFunc))...)) }