From 4b70bbe70cc004c5d25840897c1dbfac70a4098a Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 29 Dec 2022 12:34:05 +0700 Subject: [PATCH] Add defaultexpire chain element Signed-off-by: Artem Glazychev --- pkg/networkservice/chains/nsmgr/server.go | 2 + .../chains/nsmgr/single_test.go | 2 + pkg/registry/chains/memory/server.go | 12 +++ pkg/registry/common/defaultexpire/doc.go | 18 ++++ .../common/defaultexpire/nse_server.go | 61 +++++++++++++ .../common/defaultexpire/nse_server_test.go | 85 +++++++++++++++++++ pkg/tools/sandbox/builder.go | 39 ++++++--- pkg/tools/sandbox/types.go | 3 +- 8 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 pkg/registry/common/defaultexpire/doc.go create mode 100644 pkg/registry/common/defaultexpire/nse_server.go create mode 100644 pkg/registry/common/defaultexpire/nse_server_test.go diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index e1db71565..26987ef37 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -49,6 +49,7 @@ import ( registryclientinfo "github.com/networkservicemesh/sdk/pkg/registry/common/clientinfo" "github.com/networkservicemesh/sdk/pkg/registry/common/clienturl" registryconnect "github.com/networkservicemesh/sdk/pkg/registry/common/connect" + "github.com/networkservicemesh/sdk/pkg/registry/common/defaultexpire" "github.com/networkservicemesh/sdk/pkg/registry/common/dial" "github.com/networkservicemesh/sdk/pkg/registry/common/expire" "github.com/networkservicemesh/sdk/pkg/registry/common/grpcmetadata" @@ -276,6 +277,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opts.authorizeNSERegistryServer, begin.NewNetworkServiceEndpointRegistryServer(), registryclientinfo.NewNetworkServiceEndpointRegistryServer(), + defaultexpire.NewNetworkServiceEndpointRegistryServer(ctx, time.Minute), expire.NewNetworkServiceEndpointRegistryServer(ctx), registryrecvfd.NewNetworkServiceEndpointRegistryServer(), // Allow to receive a passed files registrysendfd.NewNetworkServiceEndpointRegistryServer(), diff --git a/pkg/networkservice/chains/nsmgr/single_test.go b/pkg/networkservice/chains/nsmgr/single_test.go index 1186a50a5..83466f3fa 100644 --- a/pkg/networkservice/chains/nsmgr/single_test.go +++ b/pkg/networkservice/chains/nsmgr/single_test.go @@ -519,6 +519,7 @@ func Test_FailedRegistryAuthorization(t *testing.T) { registrySupplier := func( ctx context.Context, tokenGenerator token.GeneratorFunc, + expiryDuration time.Duration, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry { registryName := sandbox.UniqueName("registry-memory") @@ -688,6 +689,7 @@ func Test_Expire(t *testing.T) { registrySupplier := func( ctx context.Context, tokenGenerator token.GeneratorFunc, + expiryDuration time.Duration, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry { return memory.NewServer( diff --git a/pkg/registry/chains/memory/server.go b/pkg/registry/chains/memory/server.go index bddf005ee..a69d90802 100644 --- a/pkg/registry/chains/memory/server.go +++ b/pkg/registry/chains/memory/server.go @@ -20,6 +20,7 @@ package memory import ( "context" "net/url" + "time" "google.golang.org/grpc" @@ -34,6 +35,7 @@ import ( "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/defaultexpire" "github.com/networkservicemesh/sdk/pkg/registry/common/dial" "github.com/networkservicemesh/sdk/pkg/registry/common/expire" "github.com/networkservicemesh/sdk/pkg/registry/common/memory" @@ -50,6 +52,7 @@ type serverOptions struct { authorizeNSERegistryServer registry.NetworkServiceEndpointRegistryServer authorizeNSRegistryClient registry.NetworkServiceRegistryClient authorizeNSERegistryClient registry.NetworkServiceEndpointRegistryClient + defaultExpireDuration time.Duration proxyRegistryURL *url.URL dialOptions []grpc.DialOption } @@ -97,6 +100,13 @@ func WithAuthorizeNSERegistryClient(authorizeNSERegistryClient registry.NetworkS } } +// WithDefaultExpireDuration sets a default expire duration for the server +func WithDefaultExpireDuration(expireDuration time.Duration) Option { + return func(o *serverOptions) { + o.defaultExpireDuration = expireDuration + } +} + // WithProxyRegistryURL sets URL to reach the proxy registry func WithProxyRegistryURL(proxyRegistryURL *url.URL) Option { return func(o *serverOptions) { @@ -118,6 +128,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options authorizeNSERegistryServer: registryauthorize.NewNetworkServiceEndpointRegistryServer(registryauthorize.Any()), authorizeNSRegistryClient: registryauthorize.NewNetworkServiceRegistryClient(registryauthorize.Any()), authorizeNSERegistryClient: registryauthorize.NewNetworkServiceEndpointRegistryClient(registryauthorize.Any()), + defaultExpireDuration: time.Minute, proxyRegistryURL: nil, } for _, opt := range options { @@ -161,6 +172,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options Condition: func(c context.Context, nse *registry.NetworkServiceEndpoint) bool { return true }, Action: chain.NewNetworkServiceEndpointRegistryServer( setregistrationtime.NewNetworkServiceEndpointRegistryServer(), + defaultexpire.NewNetworkServiceEndpointRegistryServer(ctx, time.Minute), expire.NewNetworkServiceEndpointRegistryServer(ctx), memory.NewNetworkServiceEndpointRegistryServer(), ), diff --git a/pkg/registry/common/defaultexpire/doc.go b/pkg/registry/common/defaultexpire/doc.go new file mode 100644 index 000000000..3cb31b994 --- /dev/null +++ b/pkg/registry/common/defaultexpire/doc.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 Cisco and/or its affiliates. +// +// 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 defaultexpire provides registry server chain elements for setting the default ExpirationTime if it has not been set. +package defaultexpire diff --git a/pkg/registry/common/defaultexpire/nse_server.go b/pkg/registry/common/defaultexpire/nse_server.go new file mode 100644 index 000000000..66cbfcc00 --- /dev/null +++ b/pkg/registry/common/defaultexpire/nse_server.go @@ -0,0 +1,61 @@ +// Copyright (c) 2022 Cisco and/or its affiliates. +// +// 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 defaultexpire + +import ( + "context" + "time" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/networkservicemesh/api/pkg/api/registry" + + "github.com/networkservicemesh/sdk/pkg/registry/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/clock" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +type defaultexpireNSEServer struct { + ctx context.Context + defaultNSEExpiration time.Duration +} + +// NewNetworkServiceEndpointRegistryServer creates a new NetworkServiceServer chain element that sets the default +// expiration time. +func NewNetworkServiceEndpointRegistryServer(ctx context.Context, defaultNSEExpiration time.Duration) registry.NetworkServiceEndpointRegistryServer { + return &defaultexpireNSEServer{ + ctx: ctx, + defaultNSEExpiration: defaultNSEExpiration, + } +} + +func (s *defaultexpireNSEServer) Register(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*registry.NetworkServiceEndpoint, error) { + if nse.GetExpirationTime() == nil { + nse.ExpirationTime = timestamppb.New(clock.FromContext(ctx).Now().Add(s.defaultNSEExpiration).Local()) + log.FromContext(ctx).Infof("default expiration time %v was set for %v", s.defaultNSEExpiration, nse.GetName()) + } + return next.NetworkServiceEndpointRegistryServer(ctx).Register(ctx, nse) +} + +func (s *defaultexpireNSEServer) Find(query *registry.NetworkServiceEndpointQuery, server registry.NetworkServiceEndpointRegistry_FindServer) error { + return next.NetworkServiceEndpointRegistryServer(server.Context()).Find(query, server) +} + +func (s *defaultexpireNSEServer) Unregister(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*empty.Empty, error) { + return next.NetworkServiceEndpointRegistryServer(ctx).Unregister(ctx, nse) +} diff --git a/pkg/registry/common/defaultexpire/nse_server_test.go b/pkg/registry/common/defaultexpire/nse_server_test.go new file mode 100644 index 000000000..7da67c232 --- /dev/null +++ b/pkg/registry/common/defaultexpire/nse_server_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2022 Cisco and/or its affiliates. +// +// 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 defaultexpire_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/networkservicemesh/api/pkg/api/registry" + + "github.com/networkservicemesh/sdk/pkg/registry/common/defaultexpire" + "github.com/networkservicemesh/sdk/pkg/registry/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/clock" + "github.com/networkservicemesh/sdk/pkg/tools/clockmock" +) + +func TestDefaultExpireNSEServer(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + ctx = clock.WithClock(ctx, clockmock.New(ctx)) + + var samples = []struct { + name string + nse *registry.NetworkServiceEndpoint + }{ + { + name: "With NSE expiration", + nse: ®istry.NetworkServiceEndpoint{ + Name: "nse", + NetworkServiceNames: []string{"ns"}, + ExpirationTime: timestamppb.New(clock.FromContext(ctx).Now().Add(time.Minute).Local()), + }, + }, + { + name: "Without NSE expiration", + nse: ®istry.NetworkServiceEndpoint{ + Name: "nse", + NetworkServiceNames: []string{"ns"}, + }, + }, + } + + for _, sample := range samples { + t.Run(sample.name, func(t *testing.T) { + // nolint:scopelint + testDefaultExpireNSEServer(ctx, t, sample.nse) + }) + } +} + +func testDefaultExpireNSEServer(ctx context.Context, t *testing.T, nse *registry.NetworkServiceEndpoint) { + s := next.NewNetworkServiceEndpointRegistryServer( + defaultexpire.NewNetworkServiceEndpointRegistryServer(ctx, time.Hour), + ) + + registeredNSE, err := s.Register(ctx, nse.Clone()) + require.NoError(t, err) + + if nse.GetExpirationTime() != nil { + require.Equal(t, nse.GetExpirationTime(), registeredNSE.GetExpirationTime()) + } else { + require.Equal(t, clock.FromContext(ctx).Now().Local().Add(time.Hour), registeredNSE.GetExpirationTime().AsTime().Local()) + } +} diff --git a/pkg/tools/sandbox/builder.go b/pkg/tools/sandbox/builder.go index dc425aa8c..1191d3dc8 100644 --- a/pkg/tools/sandbox/builder.go +++ b/pkg/tools/sandbox/builder.go @@ -24,6 +24,7 @@ import ( "os" "runtime" "testing" + "time" "github.com/stretchr/testify/require" "google.golang.org/grpc" @@ -52,19 +53,21 @@ type Builder struct { supplyRegistryProxy SupplyRegistryProxyFunc setupNode SetupNodeFunc - name string - dnsResolver dnsresolve.Resolver - generateTokenFunc token.GeneratorFunc + name string + dnsResolver dnsresolve.Resolver + generateTokenFunc token.GeneratorFunc + defaultRegistryExpiryDuration time.Duration useUnixSockets bool domain *Domain } -func newRegistryMemoryServer(ctx context.Context, tokenGenerator token.GeneratorFunc, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry { +func newRegistryMemoryServer(ctx context.Context, tokenGenerator token.GeneratorFunc, defaultExpiryDuration time.Duration, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry { return memory.NewServer( ctx, tokenGenerator, + memory.WithDefaultExpireDuration(defaultExpiryDuration), memory.WithProxyRegistryURL(proxyRegistryURL), memory.WithDialOptions(options...)) } @@ -72,16 +75,17 @@ func newRegistryMemoryServer(ctx context.Context, tokenGenerator token.Generator // NewBuilder creates new SandboxBuilder func NewBuilder(ctx context.Context, t *testing.T) *Builder { b := &Builder{ - t: t, - ctx: ctx, - nodesCount: 1, - supplyNSMgr: nsmgr.NewServer, - supplyNSMgrProxy: nsmgrproxy.NewServer, - supplyRegistry: newRegistryMemoryServer, - supplyRegistryProxy: proxydns.NewServer, - name: "cluster.local", - dnsResolver: NewFakeResolver(), - generateTokenFunc: GenerateTestToken, + t: t, + ctx: ctx, + nodesCount: 1, + supplyNSMgr: nsmgr.NewServer, + supplyNSMgrProxy: nsmgrproxy.NewServer, + supplyRegistry: newRegistryMemoryServer, + supplyRegistryProxy: proxydns.NewServer, + name: "cluster.local", + dnsResolver: NewFakeResolver(), + generateTokenFunc: GenerateTestToken, + defaultRegistryExpiryDuration: time.Minute, } b.setupNode = func(ctx context.Context, node *Node, _ int) { @@ -147,6 +151,12 @@ func (b *Builder) SetTokenGenerateFunc(f token.GeneratorFunc) *Builder { return b } +// SetRegistryDefaultExpiryDuration sets default expire +func (b *Builder) SetRegistryDefaultExpiryDuration(duration time.Duration) *Builder { + b.defaultRegistryExpiryDuration = duration + return b +} + // UseUnixSockets sets 1 node and mark it to use unix socket to listen on. func (b *Builder) UseUnixSockets() *Builder { require.NotEqual(b.t, "windows", runtime.GOOS, "Unix sockets are not available for windows") @@ -265,6 +275,7 @@ func (b *Builder) newRegistry() *RegistryEntry { entry.Registry = b.supplyRegistry( ctx, b.generateTokenFunc, + b.defaultRegistryExpiryDuration, nsmgrProxyURL, DialOptions(WithTokenGenerator(b.generateTokenFunc))..., ) diff --git a/pkg/tools/sandbox/types.go b/pkg/tools/sandbox/types.go index 571713b01..2d632bf24 100644 --- a/pkg/tools/sandbox/types.go +++ b/pkg/tools/sandbox/types.go @@ -19,6 +19,7 @@ package sandbox import ( "context" "net/url" + "time" registryapi "github.com/networkservicemesh/api/pkg/api/registry" "google.golang.org/grpc" @@ -40,7 +41,7 @@ type SupplyNSMgrProxyFunc func(ctx context.Context, regURL, proxyURL *url.URL, t type SupplyNSMgrFunc func(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...nsmgr.Option) nsmgr.Nsmgr // SupplyRegistryFunc supplies Registry -type SupplyRegistryFunc func(ctx context.Context, tokenGenerator token.GeneratorFunc, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry +type SupplyRegistryFunc func(ctx context.Context, tokenGenerator token.GeneratorFunc, defaultExpiryDuration time.Duration, proxyRegistryURL *url.URL, options ...grpc.DialOption) registry.Registry // SupplyRegistryProxyFunc supplies registry proxy type SupplyRegistryProxyFunc func(ctx context.Context, tokenGenerator token.GeneratorFunc, dnsResolver dnsresolve.Resolver, options ...proxydns.Option) registry.Registry