Skip to content

Commit

Permalink
Fix InitialRegistrationTime in case of reregistration (#1456)
Browse files Browse the repository at this point in the history
* Fix InitialRegistrationTime in case of reregistration

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>

* Add registry metadata

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>

* Use metadata for setregistrationtime

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>

* linter fix

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>

---------

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>
  • Loading branch information
glazychev-art authored May 18, 2023
1 parent ad70c1f commit 63043b2
Show file tree
Hide file tree
Showing 15 changed files with 963 additions and 4 deletions.
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

0 comments on commit 63043b2

Please sign in to comment.