Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix InitialRegistrationTime in case of reregistration #1456

Merged
merged 4 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/registry/chains/client/ns_client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021-2022 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -32,6 +34,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/registry/common/null"
"github.com/networkservicemesh/sdk/pkg/registry/common/retry"
"github.com/networkservicemesh/sdk/pkg/registry/core/chain"
"github.com/networkservicemesh/sdk/pkg/registry/utils/metadata"
)

// NewNetworkServiceRegistryClient creates a new NewNetworkServiceRegistryClient that can be used for NS registration.
Expand All @@ -48,6 +51,7 @@ func NewNetworkServiceRegistryClient(ctx context.Context, opts ...Option) regist
append(
[]registry.NetworkServiceRegistryClient{
begin.NewNetworkServiceRegistryClient(),
metadata.NewNetworkServiceClient(),
retry.NewNetworkServiceRegistryClient(ctx),
clientOpts.authorizeNSRegistryClient,
heal.NewNetworkServiceRegistryClient(ctx),
Expand Down
4 changes: 4 additions & 0 deletions pkg/registry/chains/client/nse_client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021-2022 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -33,6 +35,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/registry/common/refresh"
"github.com/networkservicemesh/sdk/pkg/registry/common/retry"
"github.com/networkservicemesh/sdk/pkg/registry/core/chain"
"github.com/networkservicemesh/sdk/pkg/registry/utils/metadata"
)

// NewNetworkServiceEndpointRegistryClient creates a new NewNetworkServiceEndpointRegistryClient that can be used for NSE registration.
Expand All @@ -49,6 +52,7 @@ func NewNetworkServiceEndpointRegistryClient(ctx context.Context, opts ...Option
append(
[]registry.NetworkServiceEndpointRegistryClient{
begin.NewNetworkServiceEndpointRegistryClient(),
metadata.NewNetworkServiceEndpointClient(),
retry.NewNetworkServiceEndpointRegistryClient(ctx),
heal.NewNetworkServiceEndpointRegistryClient(ctx),
refresh.NewNetworkServiceEndpointRegistryClient(ctx),
Expand Down
5 changes: 5 additions & 0 deletions pkg/registry/chains/memory/server.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2020-2022 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -42,6 +44,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/registry/common/setregistrationtime"
"github.com/networkservicemesh/sdk/pkg/registry/core/chain"
"github.com/networkservicemesh/sdk/pkg/registry/switchcase"
"github.com/networkservicemesh/sdk/pkg/registry/utils/metadata"
"github.com/networkservicemesh/sdk/pkg/tools/interdomain"
"github.com/networkservicemesh/sdk/pkg/tools/token"
)
Expand Down Expand Up @@ -139,6 +142,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options
updatepath.NewNetworkServiceEndpointRegistryServer(tokenGenerator),
opts.authorizeNSERegistryServer,
begin.NewNetworkServiceEndpointRegistryServer(),
metadata.NewNetworkServiceEndpointServer(),
switchcase.NewNetworkServiceEndpointRegistryServer(switchcase.NSEServerCase{
Condition: func(c context.Context, nse *registry.NetworkServiceEndpoint) bool {
if interdomain.Is(nse.GetName()) {
Expand Down Expand Up @@ -181,6 +185,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options
grpcmetadata.NewNetworkServiceRegistryServer(),
updatepath.NewNetworkServiceRegistryServer(tokenGenerator),
opts.authorizeNSRegistryServer,
metadata.NewNetworkServiceServer(),
setpayload.NewNetworkServiceRegistryServer(),
switchcase.NewNetworkServiceRegistryServer(
switchcase.NSServerCase{
Expand Down
50 changes: 50 additions & 0 deletions pkg/registry/common/setregistrationtime/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2023 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 setregistrationtime

import (
"context"

"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"

"google.golang.org/protobuf/reflect/protoreflect"

"github.com/networkservicemesh/sdk/pkg/registry/utils/metadata"
)

type key struct{}

// store sets the initialRegistrationTime stored in per NSE metadata.
func store(ctx context.Context, initialRegistrationTime protoreflect.ProtoMessage) {
metadata.Map(ctx, false).Store(key{}, proto.Clone(initialRegistrationTime))
}

// load returns the initialRegistrationTime stored in per NSE metadata,
func load(ctx context.Context) (value *timestamppb.Timestamp, ok bool) {
rawValue, ok := metadata.Map(ctx, false).Load(key{})
if !ok {
return
}
value, ok = rawValue.(*timestamppb.Timestamp)
return value, ok
}

// deleteTime deletes the initialRegistrationTime stored in per NSE metadata,
func deleteTime(ctx context.Context) {
metadata.Map(ctx, false).Delete(key{})
}
15 changes: 12 additions & 3 deletions pkg/registry/common/setregistrationtime/nse_server.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -27,7 +29,8 @@ import (
"github.com/networkservicemesh/sdk/pkg/tools/clock"
)

type setregtimeNSEServer struct{}
type setregtimeNSEServer struct {
}

// NewNetworkServiceEndpointRegistryServer creates a new NetworkServiceServer chain element that sets initial
// registration time.
Expand All @@ -36,8 +39,13 @@ func NewNetworkServiceEndpointRegistryServer() registry.NetworkServiceEndpointRe
}

func (r *setregtimeNSEServer) Register(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*registry.NetworkServiceEndpoint, error) {
if nse.InitialRegistrationTime == nil {
nse.InitialRegistrationTime = timestamppb.New(clock.FromContext(ctx).Now())
if v, ok := load(ctx); ok {
nse.InitialRegistrationTime = v
} else {
if nse.InitialRegistrationTime == nil {
nse.InitialRegistrationTime = timestamppb.New(clock.FromContext(ctx).Now())
}
store(ctx, nse.InitialRegistrationTime)
}

return next.NetworkServiceEndpointRegistryServer(ctx).Register(ctx, nse)
Expand All @@ -48,5 +56,6 @@ func (r *setregtimeNSEServer) Find(q *registry.NetworkServiceEndpointQuery, s re
}

func (r *setregtimeNSEServer) Unregister(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*empty.Empty, error) {
deleteTime(ctx)
return next.NetworkServiceEndpointRegistryServer(ctx).Unregister(ctx, nse)
}
15 changes: 14 additions & 1 deletion pkg/registry/common/setregistrationtime/nse_server_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// Copyright (c) 2023 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -32,6 +34,7 @@ import (
"github.com/networkservicemesh/sdk/pkg/registry/common/setregistrationtime"
"github.com/networkservicemesh/sdk/pkg/registry/core/next"
"github.com/networkservicemesh/sdk/pkg/registry/core/streamchannel"
"github.com/networkservicemesh/sdk/pkg/registry/utils/metadata"
)

func testNSE() *registry.NetworkServiceEndpoint {
Expand All @@ -43,6 +46,7 @@ func testNSE() *registry.NetworkServiceEndpoint {

func TestRegTimeServer_Register(t *testing.T) {
s := next.NewNetworkServiceEndpointRegistryServer(
metadata.NewNetworkServiceEndpointServer(),
setregistrationtime.NewNetworkServiceEndpointRegistryServer(),
memory.NewNetworkServiceEndpointRegistryServer(),
)
Expand All @@ -65,12 +69,21 @@ func TestRegTimeServer_Register(t *testing.T) {
require.Len(t, nses, 1)
require.True(t, proto.Equal(nses[0].InitialRegistrationTime, registeredNse.InitialRegistrationTime))

// 3. Refresh
// 3.1 Refresh
reg, err = s.Register(ctx, reg.Clone())
require.NoError(t, err)
require.NotNil(t, reg.InitialRegistrationTime)
require.True(t, proto.Equal(reg.InitialRegistrationTime, registeredNse.InitialRegistrationTime))

// 3.2 Refresh with empty field
regClone := reg.Clone()
regClone.InitialRegistrationTime = nil
clockMock.Add(time.Second)
reg, err = s.Register(ctx, regClone)
require.NoError(t, err)
require.NotNil(t, reg.InitialRegistrationTime)
require.True(t, proto.Equal(reg.InitialRegistrationTime, registeredNse.InitialRegistrationTime))

// 4. Unregister
_, err = s.Unregister(ctx, reg.Clone())
require.NoError(t, err)
Expand Down
82 changes: 82 additions & 0 deletions pkg/registry/utils/inject/injecterror/ns_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) 2023 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 injecterror

import (
"context"

"github.com/golang/protobuf/ptypes/empty"

"github.com/networkservicemesh/api/pkg/api/registry"
"github.com/pkg/errors"

"github.com/networkservicemesh/sdk/pkg/registry/core/next"
)

type injectErrorNSServer struct {
registerErrorSupplier, findErrorSupplier, unregisterErrorSupplier *errorSupplier
}

// NewNetworkServiceRegistryServer returns a server chain element returning error on Register/Find/Unregister on given times
func NewNetworkServiceRegistryServer(opts ...Option) registry.NetworkServiceRegistryServer {
o := &options{
err: errors.New("error originates in injectErrorNSServer"),
registerErrorTimes: []int{-1},
findErrorTimes: []int{-1},
unregisterErrorTimes: []int{-1},
}

for _, opt := range opts {
opt(o)
}

return &injectErrorNSServer{
registerErrorSupplier: &errorSupplier{
err: o.err,
errorTimes: o.registerErrorTimes,
},
findErrorSupplier: &errorSupplier{
err: o.err,
errorTimes: o.findErrorTimes,
},
unregisterErrorSupplier: &errorSupplier{
err: o.err,
errorTimes: o.unregisterErrorTimes,
},
}
}

func (c *injectErrorNSServer) Register(ctx context.Context, in *registry.NetworkService) (*registry.NetworkService, error) {
if err := c.registerErrorSupplier.supply(); err != nil {
return nil, err
}
return next.NetworkServiceRegistryServer(ctx).Register(ctx, in)
}

func (c *injectErrorNSServer) Find(query *registry.NetworkServiceQuery, server registry.NetworkServiceRegistry_FindServer) error {
if err := c.findErrorSupplier.supply(); err != nil {
return err
}
return next.NetworkServiceRegistryServer(server.Context()).Find(query, server)
}

func (c *injectErrorNSServer) Unregister(ctx context.Context, in *registry.NetworkService) (*empty.Empty, error) {
if err := c.unregisterErrorSupplier.supply(); err != nil {
return nil, err
}
return next.NetworkServiceRegistryServer(ctx).Unregister(ctx, in)
}
77 changes: 77 additions & 0 deletions pkg/registry/utils/metadata/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) 2023 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 metadata

import (
"context"
"sync"

"github.com/edwarnicke/genericsync"
"github.com/networkservicemesh/api/pkg/api/networkservice"
)

type metaDataKey struct{}

type metaData struct {
client sync.Map
server sync.Map
}

func store(parent context.Context, id string, mdMap *genericsync.Map[string, *metaData]) context.Context {
if _, ok := parent.Value(metaDataKey{}).(*metaData); !ok {
md, _ := mdMap.LoadOrStore(id, &metaData{})
return context.WithValue(parent, metaDataKey{}, md)
}
return parent
}

func load(parent context.Context, id string, mdMap *genericsync.Map[string, *metaData]) context.Context {
if _, ok := parent.Value(metaDataKey{}).(*metaData); !ok {
if md, mdOk := mdMap.Load(id); mdOk {
return context.WithValue(parent, metaDataKey{}, md)
}
}
return parent
}

func del(parent context.Context, id string, mdMap *genericsync.Map[string, *metaData]) context.Context {
if _, ok := parent.Value(metaDataKey{}).(*metaData); !ok {
if md, ok := mdMap.LoadAndDelete(id); ok {
return context.WithValue(parent, metaDataKey{}, md)
}
return context.WithValue(parent, metaDataKey{}, new(metaData))
}
return parent
}

// Map - Return the client (or server) per Connection.Id metadata *sync.Map
func Map(parent context.Context, isClient bool) *sync.Map {
m, ok := parent.Value(metaDataKey{}).(*metaData)
if !ok || m == nil {
panic("please add metadata chain element to your chain")
}
if isClient {
return &m.client
}
return &m.server
}

// IsClient - returns true if in implements networkservice.NetworkServiceClient
func IsClient(in interface{}) bool {
_, ok := in.(networkservice.NetworkServiceClient)
return ok
}
18 changes: 18 additions & 0 deletions pkg/registry/utils/metadata/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2023 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 metadata provides per nsName/nseName metadata
package metadata
Loading