From 08d727dcd7fd9f9347030cadeef228d99fa10b47 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Tue, 5 Jul 2022 12:56:47 +0700 Subject: [PATCH 01/39] Add next MonitorConnections chain element. Signed-off-by: anastasia.malysheva --- .../common/monitor/next/client.go | 72 +++++++++++++++++++ .../common/monitor/next/context.go | 72 +++++++++++++++++++ .../common/monitor/next/server.go | 54 ++++++++++++++ .../common/monitor/next/tail_client.go | 36 ++++++++++ .../common/monitor/next/tail_server.go | 30 ++++++++ pkg/networkservice/core/next/tail_client.go | 2 +- 6 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 pkg/networkservice/common/monitor/next/client.go create mode 100644 pkg/networkservice/common/monitor/next/context.go create mode 100644 pkg/networkservice/common/monitor/next/server.go create mode 100644 pkg/networkservice/common/monitor/next/tail_client.go create mode 100644 pkg/networkservice/common/monitor/next/tail_server.go diff --git a/pkg/networkservice/common/monitor/next/client.go b/pkg/networkservice/common/monitor/next/client.go new file mode 100644 index 000000000..bf5aa77dd --- /dev/null +++ b/pkg/networkservice/common/monitor/next/client.go @@ -0,0 +1,72 @@ +// Copyright (c) 2022 Doc.ai 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 next + +import ( + "context" + + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +type nextMonitorConnectionClient struct { + clients []networkservice.MonitorConnectionClient + index int + nextParent networkservice.MonitorConnectionClient +} + +// MonitorConnectionClientWrapper - a function that wraps around a networkservice.MonitorConnectionClient +type MonitorConnectionClientWrapper func(networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient + +// MonitorConnectionClientChainer - a function that chains together a list of networkservice.MonitorConnectionClient +type MonitorConnectionClientChainer func(...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient + +// NewWrappedMonitorConnectionClient chains together clients with wrapper wrapped around each one +func NewWrappedMonitorConnectionClient(wrapper MonitorConnectionClientWrapper, clients ...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { + rv := &nextMonitorConnectionClient{clients: make([]networkservice.MonitorConnectionClient, 0, len(clients))} + for _, c := range clients { + rv.clients = append(rv.clients, wrapper(c)) + } + return rv +} + +// NewMonitorConnectionClient - chains together clients into a single networkservice.MonitorConnectionClient +func NewMonitorConnectionClient(clients ...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { + return NewWrappedMonitorConnectionClient(func(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { + return client + }, clients...) +} + +func (n *nextMonitorConnectionClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { + client, ctx := n.getClientAndContext(ctx) + return client.MonitorConnections(ctx, in, opts...) +} + +func (n *nextMonitorConnectionClient) getClientAndContext(ctx context.Context) (networkservice.MonitorConnectionClient, context.Context) { + nextParent := n.nextParent + if n.index == 0 { + nextParent = MonitorConnectionClient(ctx) + if len(n.clients) == 0 { + return nextParent, ctx + } + } + if n.index+1 < len(n.clients) { + return n.clients[n.index], withNextMonitorConnectionClient(ctx, &nextMonitorConnectionClient{nextParent: nextParent, clients: n.clients, index: n.index + 1}) + } + return n.clients[n.index], withNextMonitorConnectionClient(ctx, nextParent) +} diff --git a/pkg/networkservice/common/monitor/next/context.go b/pkg/networkservice/common/monitor/next/context.go new file mode 100644 index 000000000..12a62f35d --- /dev/null +++ b/pkg/networkservice/common/monitor/next/context.go @@ -0,0 +1,72 @@ +// Copyright (c) 2022 Doc.ai 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 next provides a mechanism for chained networkservice.MonitorConnection{Server,Client}s to call +// the next element in the chain. +package next + +import ( + "context" + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +type contextKeyType string + +const ( + nextMonitorConnectionServerKey contextKeyType = "NextMonitorConnectionServer" + nextMonitorConnectionClientKey contextKeyType = "NextMonitorConnectionClient" +) + +// withNextMonitorConnectionServer - +// Wraps 'parent' in a new Context that has the Server networkservice.MonitorConnectionServer to be called in the chain +// Should only be set in CompositeEndpoint.Request/Close +func withNextMonitorConnectionServer(parent context.Context, next networkservice.MonitorConnectionServer) context.Context { + if parent == nil { + parent = context.Background() + } + return context.WithValue(parent, nextMonitorConnectionServerKey, next) +} + +// MonitorConnectionServer - +// Returns the networkservice.MonitorConnectionServer to be called in the chain from the context.Context +func MonitorConnectionServer(ctx context.Context) networkservice.MonitorConnectionServer { + rv, ok := ctx.Value(nextMonitorConnectionServerKey).(networkservice.MonitorConnectionServer) + if ok && rv != nil { + return rv + } + return &tailMonitorConnectionsServer{} +} + +// withNextMonitorConnectionClient - +// Wraps 'parent' in a new Context that has the Client networkservice.MonitorConnectionClient to be called in the chain +// Should only be set in CompositeEndpoint.Request/Close iS IT? +func withNextMonitorConnectionClient(parent context.Context, next networkservice.MonitorConnectionClient) context.Context { + if parent == nil { + panic("cannot create context from nil parent") + } + return context.WithValue(parent, nextMonitorConnectionClientKey, next) +} + +// MonitorConnectionClient - +// Returns the networkservice.MonitorConnectionClient to be called in the chain from the context.Context +func MonitorConnectionClient(ctx context.Context) networkservice.MonitorConnectionClient { + rv, ok := ctx.Value(nextMonitorConnectionClientKey).(networkservice.MonitorConnectionClient) + if ok && rv != nil { + return rv + } + return &tailMonitorConnectionClient{} +} \ No newline at end of file diff --git a/pkg/networkservice/common/monitor/next/server.go b/pkg/networkservice/common/monitor/next/server.go new file mode 100644 index 000000000..1deb5b71c --- /dev/null +++ b/pkg/networkservice/common/monitor/next/server.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Doc.ai 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 next + +import ( + "context" + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +type nextMonitorConnectionServer struct { + servers []networkservice.MonitorConnectionServer + index int + nextParent networkservice.MonitorConnectionServer +} + +// MonitorConnectionsServerWrapper - a function that wraps around a networkservice.MonitorConnectionServer +type MonitorConnectionsServerWrapper func(networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer + +// MonitorConnectionsServerChainer - a function that chains together a list of networkservice.MonitorConnectionServers +type MonitorConnectionsServerChainer func(...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer + +func (n *nextMonitorConnectionServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { + server, _ := n.getServerAndContext(srv.Context()) + return server.MonitorConnections(in, srv) +} + +func (n *nextMonitorConnectionServer) getServerAndContext(ctx context.Context) (networkservice.MonitorConnectionServer, context.Context) { + nextParent := n.nextParent + if n.index == 0 { + nextParent = MonitorConnectionServer(ctx) + if len(n.servers) == 0 { + return nextParent, ctx + } + } + if n.index+1 < len(n.servers) { + return n.servers[n.index], withNextMonitorConnectionServer(ctx, &nextMonitorConnectionServer{nextParent: nextParent, servers: n.servers, index: n.index + 1}) + } + return n.servers[n.index], withNextMonitorConnectionServer(ctx, nextParent) +} diff --git a/pkg/networkservice/common/monitor/next/tail_client.go b/pkg/networkservice/common/monitor/next/tail_client.go new file mode 100644 index 000000000..d3f41caa1 --- /dev/null +++ b/pkg/networkservice/common/monitor/next/tail_client.go @@ -0,0 +1,36 @@ +// 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 next + +import ( + "context" + + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +// tailMonitorConnectionClient is a simple implementation of networkservice.MonitorConnectionClient that is called at the end of a chain +// to insure that we never call a method on a nil object + +type tailMonitorConnectionClient struct { + networkservice.MonitorConnection_MonitorConnectionsClient +} + +func (t *tailMonitorConnectionClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { + return t.MonitorConnection_MonitorConnectionsClient, nil +} \ No newline at end of file diff --git a/pkg/networkservice/common/monitor/next/tail_server.go b/pkg/networkservice/common/monitor/next/tail_server.go new file mode 100644 index 000000000..2e4fdf182 --- /dev/null +++ b/pkg/networkservice/common/monitor/next/tail_server.go @@ -0,0 +1,30 @@ +// 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 next + +import ( + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +// tailMonitorConnectionsServer is a simple implementation of networkservice.MonitorConnectionServer that is called at the end of a chain +// to insure that we never call a method on a nil object + +type tailMonitorConnectionsServer struct{} + +func (t *tailMonitorConnectionsServer) MonitorConnections(in *networkservice.MonitorScopeSelector, sv networkservice.MonitorConnection_MonitorConnectionsServer) error { + return nil +} diff --git a/pkg/networkservice/core/next/tail_client.go b/pkg/networkservice/core/next/tail_client.go index c7e763ad1..12505e9f5 100644 --- a/pkg/networkservice/core/next/tail_client.go +++ b/pkg/networkservice/core/next/tail_client.go @@ -25,7 +25,7 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" ) -// tailServer is a simple implementation of networkservice.NetworkServiceServer that is called at the end of a chain +// tailClient is a simple implementation of networkservice.NetworkServiceClient that is called at the end of a chain // to insure that we never call a method on a nil object type tailClient struct{} From aef3696890d30f67fdf3d7cffff9070609472203 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Tue, 5 Jul 2022 16:16:17 +0700 Subject: [PATCH 02/39] Add authorize MonitorConnections chain element and add call of next chain element to Monitor element. Signed-off-by: anastasia.malysheva --- .../common/monitor/authorize/client.go | 61 +++++++++++++++++++ .../common/monitor/authorize/common.go | 46 ++++++++++++++ .../common/monitor/authorize/options.go | 40 ++++++++++++ .../common/monitor/authorize/server.go | 57 +++++++++++++++++ .../monitor/monitor_connection_server.go | 8 ++- .../common/monitor/next/server.go | 15 +++++ pkg/networkservice/core/next/client.go | 4 +- pkg/networkservice/core/next/tail_client.go | 2 +- 8 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 pkg/networkservice/common/monitor/authorize/client.go create mode 100644 pkg/networkservice/common/monitor/authorize/common.go create mode 100644 pkg/networkservice/common/monitor/authorize/options.go create mode 100644 pkg/networkservice/common/monitor/authorize/server.go diff --git a/pkg/networkservice/common/monitor/authorize/client.go b/pkg/networkservice/common/monitor/authorize/client.go new file mode 100644 index 000000000..58e5f9901 --- /dev/null +++ b/pkg/networkservice/common/monitor/authorize/client.go @@ -0,0 +1,61 @@ +// Copyright (c) 2022 Doc.ai 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 authorize + +import ( + "context" + + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" +) + +type authorizeMonitorConnectionsClient struct { + policies policiesList +} + +// NewMonitorConnectionsClient - returns a new authorization NewMonitorConnectionsClient +// Authorize client checks rigiht side of path. +func NewMonitorConnectionsClient(opts ...Option) networkservice.MonitorConnectionClient { + var result = &authorizeMonitorConnectionsClient{ + policies: []Policy{}, + } + + for _, o := range opts { + o.apply(&result.policies) + } + + return result +} + +func (a *authorizeMonitorConnectionsClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { + srv, err := next.MonitorConnectionClient(ctx).MonitorConnections(ctx, in, opts...) + if err != nil { + return nil, err + } + pathSegments := in.GetPathSegments() + var path = &networkservice.Path{ + PathSegments: pathSegments[:len(pathSegments)-1], + } + if err := a.policies.check(ctx, path); err != nil { + return nil, err + } + + return srv, nil +} diff --git a/pkg/networkservice/common/monitor/authorize/common.go b/pkg/networkservice/common/monitor/authorize/common.go new file mode 100644 index 000000000..ac7354885 --- /dev/null +++ b/pkg/networkservice/common/monitor/authorize/common.go @@ -0,0 +1,46 @@ +// Copyright (c) 2022 Doc.ai 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 authorize + +import ( + "context" + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +// Policy represents authorization policy for monitor connection. +type Policy interface { + // Check checks authorization + Check(ctx context.Context, input interface{}) error +} + +type policiesList []Policy + +func (l *policiesList) check(ctx context.Context, srv *networkservice.Path) error { + if l == nil { + return nil + } + for _, policy := range *l { + if policy == nil { + continue + } + if err := policy.Check(ctx, srv); err != nil { + return err + } + } + return nil +} diff --git a/pkg/networkservice/common/monitor/authorize/options.go b/pkg/networkservice/common/monitor/authorize/options.go new file mode 100644 index 000000000..f421535d2 --- /dev/null +++ b/pkg/networkservice/common/monitor/authorize/options.go @@ -0,0 +1,40 @@ +// Copyright (c) 2022 Doc.ai 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 authorize + +// Option is authorization option for server +type Option interface { + apply(*policiesList) +} + +// Any authorizes any call of request/close +func Any() Option { + return WithPolicies(nil) +} + +// WithPolicies sets custom policies +func WithPolicies(p ...Policy) Option { + return optionFunc(func(l *policiesList) { + *l = p + }) +} + +type optionFunc func(*policiesList) + +func (f optionFunc) apply(a *policiesList) { + f(a) +} diff --git a/pkg/networkservice/common/monitor/authorize/server.go b/pkg/networkservice/common/monitor/authorize/server.go new file mode 100644 index 000000000..785f026f1 --- /dev/null +++ b/pkg/networkservice/common/monitor/authorize/server.go @@ -0,0 +1,57 @@ +// Copyright (c) 2022 Doc.ai 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 authorize provides authz checks for incoming or returning connections. +package authorize + +import ( + "google.golang.org/grpc/peer" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" +) + +type authorizeServer struct { + policies policiesList +} + +// NewMonitorConnectionsServer - returns a new authorization networkservicemesh.MonitorConnectionServer +// Authorize server checks left side of Path. +func NewMonitorConnectionsServer(opts ...Option) networkservice.MonitorConnectionServer { + // todo: add policies + var s = &authorizeServer{ + policies: []Policy{}, + } + for _, o := range opts { + o.apply(&s.policies) + } + return s +} + +func (a *authorizeServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { + // call smth to get ID of the Server/connection + ctx := srv.Context() + var leftSide = &networkservice.Path{ + PathSegments: in.GetPathSegments(), + } + if _, ok := peer.FromContext(ctx); ok { + if err := a.policies.check(ctx, leftSide); err != nil { + return err + } + } + return next.MonitorConnectionServer(ctx).MonitorConnections(in, srv) +} diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index d86db7b6c..2e82bd395 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -22,6 +22,9 @@ import ( "github.com/edwarnicke/serialize" "github.com/google/uuid" "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/authorize" ) type monitorConnectionServer struct { @@ -32,11 +35,12 @@ type monitorConnectionServer struct { } func newMonitorConnectionServer(chainCtx context.Context) networkservice.MonitorConnectionServer { - return &monitorConnectionServer{ + srv := &monitorConnectionServer{ chainCtx: chainCtx, connections: make(map[string]*networkservice.Connection), filters: make(map[string]*monitorFilter), } + return next.NewMonitorConnectionServer(authorize.NewMonitorConnectionsServer(), srv) } func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { diff --git a/pkg/networkservice/common/monitor/next/server.go b/pkg/networkservice/common/monitor/next/server.go index 1deb5b71c..949e62e56 100644 --- a/pkg/networkservice/common/monitor/next/server.go +++ b/pkg/networkservice/common/monitor/next/server.go @@ -34,6 +34,21 @@ type MonitorConnectionsServerWrapper func(networkservice.MonitorConnectionServer // MonitorConnectionsServerChainer - a function that chains together a list of networkservice.MonitorConnectionServers type MonitorConnectionsServerChainer func(...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer +func newWrappedMonitorConnectionServer(wrapper MonitorConnectionsServerWrapper, servers ...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { + rv := &nextMonitorConnectionServer{servers: make([]networkservice.MonitorConnectionServer, 0, len(servers))} + for _, c := range servers { + rv.servers = append(rv.servers, wrapper(c)) + } + return rv +} + +// NewMonitorConnectionServer - chains together servers into a single networkservice.MonitorConnectionServer +func NewMonitorConnectionServer(servers ...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { + return newWrappedMonitorConnectionServer(func(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { + return server + }, servers...) +} + func (n *nextMonitorConnectionServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { server, _ := n.getServerAndContext(srv.Context()) return server.MonitorConnections(in, srv) diff --git a/pkg/networkservice/core/next/client.go b/pkg/networkservice/core/next/client.go index 5e5302b99..6190e72c2 100644 --- a/pkg/networkservice/core/next/client.go +++ b/pkg/networkservice/core/next/client.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // -// 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 // diff --git a/pkg/networkservice/core/next/tail_client.go b/pkg/networkservice/core/next/tail_client.go index 12505e9f5..268076c0f 100644 --- a/pkg/networkservice/core/next/tail_client.go +++ b/pkg/networkservice/core/next/tail_client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // From 74054d94868398b9ac619832d12739e83e51a314 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Tue, 5 Jul 2022 17:19:21 +0700 Subject: [PATCH 03/39] Move next and auth monitor elements to tools dir. Signed-off-by: anastasia.malysheva --- .../common/monitor/monitor_connection_server.go | 4 ++-- .../common => tools}/monitor/authorize/client.go | 2 +- .../common => tools}/monitor/authorize/common.go | 0 .../common => tools}/monitor/authorize/options.go | 0 .../common => tools}/monitor/authorize/server.go | 2 +- pkg/{networkservice/common => tools}/monitor/next/client.go | 0 pkg/{networkservice/common => tools}/monitor/next/context.go | 0 pkg/{networkservice/common => tools}/monitor/next/server.go | 0 .../common => tools}/monitor/next/tail_client.go | 0 .../common => tools}/monitor/next/tail_server.go | 0 10 files changed, 4 insertions(+), 4 deletions(-) rename pkg/{networkservice/common => tools}/monitor/authorize/client.go (95%) rename pkg/{networkservice/common => tools}/monitor/authorize/common.go (100%) rename pkg/{networkservice/common => tools}/monitor/authorize/options.go (100%) rename pkg/{networkservice/common => tools}/monitor/authorize/server.go (95%) rename pkg/{networkservice/common => tools}/monitor/next/client.go (100%) rename pkg/{networkservice/common => tools}/monitor/next/context.go (100%) rename pkg/{networkservice/common => tools}/monitor/next/server.go (100%) rename pkg/{networkservice/common => tools}/monitor/next/tail_client.go (100%) rename pkg/{networkservice/common => tools}/monitor/next/tail_server.go (100%) diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index 2e82bd395..1eacebc53 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -23,8 +23,8 @@ import ( "github.com/google/uuid" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) type monitorConnectionServer struct { diff --git a/pkg/networkservice/common/monitor/authorize/client.go b/pkg/tools/monitor/authorize/client.go similarity index 95% rename from pkg/networkservice/common/monitor/authorize/client.go rename to pkg/tools/monitor/authorize/client.go index 58e5f9901..79ce63a36 100644 --- a/pkg/networkservice/common/monitor/authorize/client.go +++ b/pkg/tools/monitor/authorize/client.go @@ -23,7 +23,7 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type authorizeMonitorConnectionsClient struct { diff --git a/pkg/networkservice/common/monitor/authorize/common.go b/pkg/tools/monitor/authorize/common.go similarity index 100% rename from pkg/networkservice/common/monitor/authorize/common.go rename to pkg/tools/monitor/authorize/common.go diff --git a/pkg/networkservice/common/monitor/authorize/options.go b/pkg/tools/monitor/authorize/options.go similarity index 100% rename from pkg/networkservice/common/monitor/authorize/options.go rename to pkg/tools/monitor/authorize/options.go diff --git a/pkg/networkservice/common/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go similarity index 95% rename from pkg/networkservice/common/monitor/authorize/server.go rename to pkg/tools/monitor/authorize/server.go index 785f026f1..3f9518690 100644 --- a/pkg/networkservice/common/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -22,7 +22,7 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type authorizeServer struct { diff --git a/pkg/networkservice/common/monitor/next/client.go b/pkg/tools/monitor/next/client.go similarity index 100% rename from pkg/networkservice/common/monitor/next/client.go rename to pkg/tools/monitor/next/client.go diff --git a/pkg/networkservice/common/monitor/next/context.go b/pkg/tools/monitor/next/context.go similarity index 100% rename from pkg/networkservice/common/monitor/next/context.go rename to pkg/tools/monitor/next/context.go diff --git a/pkg/networkservice/common/monitor/next/server.go b/pkg/tools/monitor/next/server.go similarity index 100% rename from pkg/networkservice/common/monitor/next/server.go rename to pkg/tools/monitor/next/server.go diff --git a/pkg/networkservice/common/monitor/next/tail_client.go b/pkg/tools/monitor/next/tail_client.go similarity index 100% rename from pkg/networkservice/common/monitor/next/tail_client.go rename to pkg/tools/monitor/next/tail_client.go diff --git a/pkg/networkservice/common/monitor/next/tail_server.go b/pkg/tools/monitor/next/tail_server.go similarity index 100% rename from pkg/networkservice/common/monitor/next/tail_server.go rename to pkg/tools/monitor/next/tail_server.go From adb08295e7ec05f7691cc6be50ca269edc213a2f Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 8 Jul 2022 15:32:50 +0700 Subject: [PATCH 04/39] add usage of monitor elements, new policy and add logs to monitorAuthorize elements Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/heal/eventloop.go | 6 +- .../monitor/monitor_connection_server.go | 2 +- .../core/adapters/monitor_client_to_server.go | 5 +- .../core/adapters/monitor_server_to_client.go | 6 +- .../core/eventchannel/monitor_client.go | 8 ++- pkg/tools/monitor/authorize/client.go | 55 +++++++++++++++---- pkg/tools/monitor/authorize/server.go | 48 +++++++++++++--- pkg/tools/opa/opainput.go | 9 ++- pkg/tools/opa/policies.go | 11 ++++ .../opa/policies/service_connection.rego | 30 ++++++++++ 10 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 pkg/tools/opa/policies/service_connection.rego diff --git a/pkg/networkservice/common/heal/eventloop.go b/pkg/networkservice/common/heal/eventloop.go index eda3fad58..d228863c9 100644 --- a/pkg/networkservice/common/heal/eventloop.go +++ b/pkg/networkservice/common/heal/eventloop.go @@ -29,6 +29,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/begin" "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type eventLoop struct { @@ -62,8 +64,8 @@ func newEventLoop(ctx context.Context, cc grpc.ClientConnInterface, conn *networ }, }, } - - client, err := networkservice.NewMonitorConnectionClient(cc).MonitorConnections(eventLoopCtx, selector) + mClient := next.NewMonitorConnectionClient(authorize.NewMonitorConnectionsClient(), networkservice.NewMonitorConnectionClient(cc)) + client, err := mClient.MonitorConnections(eventLoopCtx, selector) if err != nil { eventLoopCancel() return nil, errors.WithStack(err) diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index 1eacebc53..986df7e3f 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -23,8 +23,8 @@ import ( "github.com/google/uuid" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorConnectionServer struct { diff --git a/pkg/networkservice/core/adapters/monitor_client_to_server.go b/pkg/networkservice/core/adapters/monitor_client_to_server.go index 80f38ee0c..699d4e5aa 100644 --- a/pkg/networkservice/core/adapters/monitor_client_to_server.go +++ b/pkg/networkservice/core/adapters/monitor_client_to_server.go @@ -18,6 +18,8 @@ package adapters import ( "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorClientToServer struct { @@ -27,9 +29,10 @@ type monitorClientToServer struct { // NewMonitorClientToServer - returns a MonitorConnectionServer that is wrapped around the provided MonitorConnectionClient // events that are received by the MonitorConnectionClient are sent to the MonitorConnectionServer func NewMonitorClientToServer(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionServer { - return &monitorClientToServer{ + srv := &monitorClientToServer{ client: client, } + return next.NewMonitorConnectionServer(authorize.NewMonitorConnectionsServer(), srv) } func (m monitorClientToServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { diff --git a/pkg/networkservice/core/adapters/monitor_server_to_client.go b/pkg/networkservice/core/adapters/monitor_server_to_client.go index 960153545..6d154597c 100644 --- a/pkg/networkservice/core/adapters/monitor_server_to_client.go +++ b/pkg/networkservice/core/adapters/monitor_server_to_client.go @@ -26,6 +26,9 @@ import ( "google.golang.org/grpc" "github.com/networkservicemesh/sdk/pkg/networkservice/core/eventchannel" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + ) type monitorServerToClient struct { @@ -35,7 +38,8 @@ type monitorServerToClient struct { // NewMonitorServerToClient - returns a MonitorConnectionClient that is a wrapper around the MonitorConnectionServer // events sent to the MonitorConnectionServer are received byt the MonitorConnectionClient func NewMonitorServerToClient(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionClient { - return &monitorServerToClient{server: server} + client := &monitorServerToClient{server: server} + return next.NewMonitorConnectionClient(authorize.NewMonitorConnectionsClient(), client) } func (m *monitorServerToClient) MonitorConnections(ctx context.Context, selector *networkservice.MonitorScopeSelector, _ ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { diff --git a/pkg/networkservice/core/eventchannel/monitor_client.go b/pkg/networkservice/core/eventchannel/monitor_client.go index 03bbdfa09..fb6e1a5cd 100644 --- a/pkg/networkservice/core/eventchannel/monitor_client.go +++ b/pkg/networkservice/core/eventchannel/monitor_client.go @@ -26,6 +26,8 @@ import ( "sync" "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "google.golang.org/grpc" "github.com/edwarnicke/serialize" @@ -44,9 +46,9 @@ type monitorConnectionClient struct { // returned from calling MonitorConnections receive the event. // Note: Does not perform filtering basedon MonitorScopeSelector func NewMonitorConnectionClient(eventCh <-chan *networkservice.ConnectionEvent) networkservice.MonitorConnectionClient { - return &monitorConnectionClient{ - eventCh: eventCh, - } + srv := &monitorConnectionClient{eventCh: eventCh} + return next.NewMonitorConnectionClient( + authorize.NewMonitorConnectionsClient(), srv) } func (m *monitorConnectionClient) MonitorConnections(ctx context.Context, _ *networkservice.MonitorScopeSelector, _ ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { diff --git a/pkg/tools/monitor/authorize/client.go b/pkg/tools/monitor/authorize/client.go index 79ce63a36..9f22c5214 100644 --- a/pkg/tools/monitor/authorize/client.go +++ b/pkg/tools/monitor/authorize/client.go @@ -18,12 +18,16 @@ package authorize import ( "context" + "fmt" - "google.golang.org/grpc" - + "github.com/golang-jwt/jwt/v4" "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/workloadapi" + "google.golang.org/grpc" "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/opa" ) type authorizeMonitorConnectionsClient struct { @@ -34,7 +38,9 @@ type authorizeMonitorConnectionsClient struct { // Authorize client checks rigiht side of path. func NewMonitorConnectionsClient(opts ...Option) networkservice.MonitorConnectionClient { var result = &authorizeMonitorConnectionsClient{ - policies: []Policy{}, + policies: []Policy{ + opa.WithServiceOwnConnectionPolicy(), + }, } for _, o := range opts { @@ -45,17 +51,46 @@ func NewMonitorConnectionsClient(opts ...Option) networkservice.MonitorConnectio } func (a *authorizeMonitorConnectionsClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { - srv, err := next.MonitorConnectionClient(ctx).MonitorConnections(ctx, in, opts...) + clt, err := next.MonitorConnectionClient(ctx).MonitorConnections(ctx, in, opts...) if err != nil { return nil, err } - pathSegments := in.GetPathSegments() - var path = &networkservice.Path{ - PathSegments: pathSegments[:len(pathSegments)-1], - } - if err := a.policies.check(ctx, path); err != nil { + event, err := clt.Recv() + if err != nil { return nil, err } + // add var connIdMap map[spiffeid.ID]*networkservice.Connection + for k, v := range event.Connections { + logrus.Infof("Conn %s: %v \n", k, v) + nextToken := v.GetNextPathSegment().Token + logrus.Infof("Conn next path token %v \n", nextToken) + tokenDecoded, err := jwt.ParseWithClaims( + nextToken, &jwt.RegisteredClaims{}, + func(token *jwt.Token) (interface{}, error) {return []byte("AllYourBase"), nil}, + ) + if err != nil { + return nil, fmt.Errorf("error decoding connection token: %+v", err) + } + logrus.Infof("decoded Token %v \n", tokenDecoded) + decodedClaims := tokenDecoded.Claims.(jwt.RegisteredClaims) + logrus.Infof("decoded Claims %v \n", decodedClaims) + logrus.Infof("Subject from the Claims %v", decodedClaims.Subject) + logrus.Infof("Audienct from the Claims %v", decodedClaims.Audience) + } + + source, err := workloadapi.NewX509Source(ctx) + if err != nil { + return nil, fmt.Errorf("error getting x509 source: %+v", err) + } + svid, err := source.GetX509SVID() + if err != nil { + return nil, fmt.Errorf("error getting x509 svid: %+v", err) + } + logrus.Infof("Service Own Spiffe ID %v", svid.ID) + + // if err := a.policies.check(ctx, svid); err != nil { + // return nil, err + // } - return srv, nil + return clt, nil } diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index 3f9518690..468569c83 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -18,11 +18,15 @@ package authorize import ( - "google.golang.org/grpc/peer" + "fmt" + "github.com/golang-jwt/jwt/v4" "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/workloadapi" "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/opa" ) type authorizeServer struct { @@ -34,7 +38,9 @@ type authorizeServer struct { func NewMonitorConnectionsServer(opts ...Option) networkservice.MonitorConnectionServer { // todo: add policies var s = &authorizeServer{ - policies: []Policy{}, + policies: []Policy{ + opa.WithServiceOwnConnectionPolicy(), + }, } for _, o := range opts { o.apply(&s.policies) @@ -43,15 +49,39 @@ func NewMonitorConnectionsServer(opts ...Option) networkservice.MonitorConnectio } func (a *authorizeServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { - // call smth to get ID of the Server/connection ctx := srv.Context() - var leftSide = &networkservice.Path{ - PathSegments: in.GetPathSegments(), - } - if _, ok := peer.FromContext(ctx); ok { - if err := a.policies.check(ctx, leftSide); err != nil { - return err + var decodedClaims jwt.RegisteredClaims + for _, seg := range in.GetPathSegments(){ + logrus.Printf("Conn next path token %v \n", seg.Token) + tokenDecoded, err := jwt.ParseWithClaims( + seg.Token, &jwt.RegisteredClaims{}, + func(token *jwt.Token) (interface{}, error) {return []byte("AllYourBase"), nil}, + ) + if err != nil { + return fmt.Errorf("error decoding connection token: %+v", err) } + logrus.Infof("decoded Token %v \n", tokenDecoded) + decodedClaims = tokenDecoded.Claims.(jwt.RegisteredClaims) + logrus.Infof("decoded Claims %v \n", decodedClaims) + logrus.Infof("Subject from the Claims %v", decodedClaims.Subject) + logrus.Infof("Audienct from the Claims %v", decodedClaims.Audience) + + } + source, err := workloadapi.NewX509Source(ctx) + if err != nil { + return fmt.Errorf("error getting x509 source: %+v", err) + } + svid, err := source.GetX509SVID() + if err != nil { + return fmt.Errorf("error getting x509 svid: %+v", err) } + logrus.Infof("Service Own Spiffe ID %v", svid.ID) + + + // if _, ok := peer.FromContext(ctx); ok { + // if err := a.policies.check(ctx, svid); err != nil { + // return err + // } + // } return next.MonitorConnectionServer(ctx).MonitorConnections(in, srv) } diff --git a/pkg/tools/opa/opainput.go b/pkg/tools/opa/opainput.go index 53afa123a..5c3f477c5 100644 --- a/pkg/tools/opa/opainput.go +++ b/pkg/tools/opa/opainput.go @@ -21,8 +21,10 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" - "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/svid/x509svid" "google.golang.org/grpc/peer" @@ -41,11 +43,16 @@ func PreparedOpaInput(ctx context.Context, model interface{}) (map[string]interf cert = parseX509Cert(p.AuthInfo) } var pemcert string + var spiffeID spiffeid.ID if cert != nil { pemcert = pemEncodingX509Cert(cert) + spiffeID, err := x509svid.IDFromCert(cert); if err == nil { + logrus.Infof("\nSpiffe ID %v\n", spiffeID.String()) + } } result["auth_info"] = map[string]interface{}{ "certificate": pemcert, + "ownSpiffeId": spiffeID, } return result, nil } diff --git a/pkg/tools/opa/policies.go b/pkg/tools/opa/policies.go index a7e5db815..ba5ffcea1 100644 --- a/pkg/tools/opa/policies.go +++ b/pkg/tools/opa/policies.go @@ -33,6 +33,9 @@ var tokensChainedPolicySource string //go:embed policies/tokens_expired.rego var tokensExpiredPolicySource string +//go:embed policies/service_connection.rego +var tokensServiceConnectionPolicySource string + // WithTokensValidPolicy returns default policy for checking that all tokens in the path can be decoded. func WithTokensValidPolicy() *AuthorizationPolicy { return &AuthorizationPolicy{ @@ -77,3 +80,11 @@ func WithTokensExpiredPolicy() *AuthorizationPolicy { checker: False("tokens_expired"), } } + +func WithServiceOwnConnectionPolicy() *AuthorizationPolicy { + return &AuthorizationPolicy{ + policySource: tokensServiceConnectionPolicySource, + query: "service_connection", + checker: True("service_connection"), + } +} diff --git a/pkg/tools/opa/policies/service_connection.rego b/pkg/tools/opa/policies/service_connection.rego new file mode 100644 index 000000000..3a05b0762 --- /dev/null +++ b/pkg/tools/opa/policies/service_connection.rego @@ -0,0 +1,30 @@ +# Copyright (c) 2020 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 nsm + +import input.attributes.request.http as http_request + +default service_connection = false + +service_connection { + input.ID == svc_spiffe_id +} + +svc_spiffe_id = spiffe_id { + [_, _, uri_type_san] := split(http_request.headers["x-forwarded-client-cert"], ";") + [_, spiffe_id] := split(uri_type_san, "=") +} \ No newline at end of file From 75a70896080d5299ab279bf36d429e8628f6c9a7 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 15 Jul 2022 15:50:50 +0700 Subject: [PATCH 05/39] update monitorServer to integrate with next monitor elements. Update auth and next monitor chain elements, fix policy. Add unit tests for new servers. Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/heal/eventloop.go | 4 +- .../common/monitor/client_filter.go | 2 +- .../common/monitor/eventloop.go | 7 +- .../monitor/monitor_connection_server.go | 63 +---- pkg/networkservice/common/monitor/server.go | 102 +++++++- .../common/monitor/server_test.go | 39 +++- .../core/adapters/monitor_client_to_server.go | 4 +- .../core/adapters/monitor_server_to_client.go | 6 +- .../core/eventchannel/monitor_client.go | 10 +- pkg/tools/monitor/authorize/client.go | 96 -------- pkg/tools/monitor/authorize/common.go | 4 +- .../monitor/authorize/connection_map.gen.go | 75 ++++++ pkg/tools/monitor/authorize/gen.go | 26 +++ pkg/tools/monitor/authorize/server.go | 82 +++---- pkg/tools/monitor/authorize/server_test.go | 221 ++++++++++++++++++ pkg/tools/monitor/next/client_test.go | 106 +++++++++ pkg/tools/monitor/next/common_test.go | 41 ++++ pkg/tools/monitor/next/server.go | 32 +-- pkg/tools/monitor/next/server_test.go | 106 +++++++++ .../monitor/streamcontext/stream_context.go | 68 ++++++ pkg/tools/opa/opainput.go | 17 +- pkg/tools/opa/policies.go | 2 +- .../opa/policies/service_connection.rego | 11 +- .../opa/service_connection_policy_test.go | 57 +++++ 24 files changed, 927 insertions(+), 254 deletions(-) delete mode 100644 pkg/tools/monitor/authorize/client.go create mode 100644 pkg/tools/monitor/authorize/connection_map.gen.go create mode 100644 pkg/tools/monitor/authorize/gen.go create mode 100644 pkg/tools/monitor/authorize/server_test.go create mode 100644 pkg/tools/monitor/next/client_test.go create mode 100644 pkg/tools/monitor/next/common_test.go create mode 100644 pkg/tools/monitor/next/server_test.go create mode 100644 pkg/tools/monitor/streamcontext/stream_context.go create mode 100644 pkg/tools/opa/service_connection_policy_test.go diff --git a/pkg/networkservice/common/heal/eventloop.go b/pkg/networkservice/common/heal/eventloop.go index d228863c9..32013a937 100644 --- a/pkg/networkservice/common/heal/eventloop.go +++ b/pkg/networkservice/common/heal/eventloop.go @@ -29,7 +29,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/begin" "github.com/networkservicemesh/sdk/pkg/tools/log" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) @@ -64,7 +63,8 @@ func newEventLoop(ctx context.Context, cc grpc.ClientConnInterface, conn *networ }, }, } - mClient := next.NewMonitorConnectionClient(authorize.NewMonitorConnectionsClient(), networkservice.NewMonitorConnectionClient(cc)) + + mClient := next.NewMonitorConnectionClient(networkservice.NewMonitorConnectionClient(cc)) client, err := mClient.MonitorConnections(eventLoopCtx, selector) if err != nil { eventLoopCancel() diff --git a/pkg/networkservice/common/monitor/client_filter.go b/pkg/networkservice/common/monitor/client_filter.go index 881289629..97ad7f951 100644 --- a/pkg/networkservice/common/monitor/client_filter.go +++ b/pkg/networkservice/common/monitor/client_filter.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/networkservice/common/monitor/eventloop.go b/pkg/networkservice/common/monitor/eventloop.go index c9e0559bc..8516b3383 100644 --- a/pkg/networkservice/common/monitor/eventloop.go +++ b/pkg/networkservice/common/monitor/eventloop.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -22,6 +22,8 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/pkg/errors" "google.golang.org/grpc" + + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type eventLoop struct { @@ -51,7 +53,8 @@ func newEventLoop(ctx context.Context, ec eventConsumer, cc grpc.ClientConnInter }, } - client, err := networkservice.NewMonitorConnectionClient(cc).MonitorConnections(eventLoopCtx, selector) + client, err := next.NewMonitorConnectionClient( + networkservice.NewMonitorConnectionClient(cc)).MonitorConnections(eventLoopCtx, selector) if err != nil { eventLoopCancel() return nil, errors.WithStack(err) diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index 986df7e3f..f4e268be8 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2022 Cisco and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -23,7 +23,6 @@ import ( "github.com/google/uuid" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) @@ -31,19 +30,23 @@ type monitorConnectionServer struct { chainCtx context.Context connections map[string]*networkservice.Connection filters map[string]*monitorFilter - executor serialize.Executor + executor *serialize.Executor } -func newMonitorConnectionServer(chainCtx context.Context) networkservice.MonitorConnectionServer { - srv := &monitorConnectionServer{ +func newMonitorConnectionServer(chainCtx context.Context, executor *serialize.Executor, + filters map[string]*monitorFilter, connections map[string]*networkservice.Connection) networkservice.MonitorConnectionServer { + return &monitorConnectionServer{ chainCtx: chainCtx, - connections: make(map[string]*networkservice.Connection), - filters: make(map[string]*monitorFilter), + connections: connections, + filters: filters, + executor: executor, } - return next.NewMonitorConnectionServer(authorize.NewMonitorConnectionsServer(), srv) } func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { + if err := next.MonitorConnectionServer(srv.Context()).MonitorConnections(selector, srv); err != nil { + return err + } m.executor.AsyncExec(func() { filter := newMonitorFilter(selector, srv) m.filters[uuid.New().String()] = filter @@ -67,50 +70,6 @@ func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.Mo return nil } -var _ networkservice.MonitorConnectionServer = &monitorConnectionServer{} - -func (m *monitorConnectionServer) Send(event *networkservice.ConnectionEvent) (_ error) { - m.executor.AsyncExec(func() { - if event.Type == networkservice.ConnectionEventType_UPDATE { - for _, conn := range event.GetConnections() { - m.connections[conn.GetId()] = conn.Clone() - } - } - if event.Type == networkservice.ConnectionEventType_DELETE { - for _, conn := range event.GetConnections() { - delete(m.connections, conn.GetId()) - } - } - if event.Type == networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER { - // sending event with INIITIAL_STATE_TRANSFER not permitted - return - } - for id, filter := range m.filters { - id, filter := id, filter - e := event.Clone() - filter.executor.AsyncExec(func() { - var err error - select { - case <-filter.Context().Done(): - m.executor.AsyncExec(func() { - delete(m.filters, id) - }) - default: - err = filter.Send(e) - } - if err != nil { - m.executor.AsyncExec(func() { - delete(m.filters, id) - }) - } - }) - } - }) - return nil -} - type eventConsumer interface { Send(event *networkservice.ConnectionEvent) (err error) } - -var _ eventConsumer = &monitorConnectionServer{} diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 0946981ce..b5c4c07ea 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // -// 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 // @@ -22,21 +22,33 @@ package monitor import ( "context" + "crypto/x509" + "github.com/edwarnicke/serialize" "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" + "github.com/spiffe/go-spiffe/v2/svid/x509svid" + "google.golang.org/grpc/peer" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clientconn" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" + "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/sdk/pkg/tools/postpone" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + + authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + nextMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorServer struct { - chainCtx context.Context + chainCtx context.Context + spiffeIDConnectionMap *authMonitor.SpiffeIDConnectionMap + filters map[string]*monitorFilter + executor *serialize.Executor + connections map[string]*networkservice.Connection networkservice.MonitorConnectionServer } @@ -50,10 +62,22 @@ type monitorServer struct { // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { - *monitorServerPtr = newMonitorConnectionServer(chainCtx) + spiffeIDConnectionMap := authMonitor.SpiffeIDConnectionMap{} + filters := make(map[string]*monitorFilter) + executor := serialize.Executor{} + connections := make(map[string]*networkservice.Connection) + + *monitorServerPtr = nextMonitor.NewMonitorConnectionServer( + authMonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap), + newMonitorConnectionServer(chainCtx, &executor, filters, connections), + ) return &monitorServer{ chainCtx: chainCtx, MonitorConnectionServer: *monitorServerPtr, + spiffeIDConnectionMap: &spiffeIDConnectionMap, + filters: filters, + executor: &executor, + connections: connections, } } @@ -68,7 +92,12 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net if err != nil { return nil, err } - _ = m.MonitorConnectionServer.(eventConsumer).Send(&networkservice.ConnectionEvent{ + spiffeID, err := getSpiffeID(ctx) + if err == nil { + ids, _ := m.spiffeIDConnectionMap.Load(spiffeID) + m.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + } + _ = m.Send(&networkservice.ConnectionEvent{ Type: networkservice.ConnectionEventType_UPDATE, Connections: map[string]*networkservice.Connection{conn.GetId(): conn.Clone()}, }) @@ -77,7 +106,7 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net // events through from, so start an eventLoop cc, ccLoaded := clientconn.Load(ctx) if ccLoaded { - cancelEventLoop, eventLoopErr := newEventLoop(m.chainCtx, m.MonitorConnectionServer.(eventConsumer), cc, conn) + cancelEventLoop, eventLoopErr := newEventLoop(m.chainCtx, m, cc, conn) if eventLoopErr != nil { closeCtx, closeCancel := closeCtxFunc() defer closeCancel() @@ -95,10 +124,69 @@ func (m *monitorServer) Close(ctx context.Context, conn *networkservice.Connecti if cancelEventLoop, loaded := loadAndDelete(ctx, metadata.IsClient(m)); loaded { cancelEventLoop() } + spiffeID, err := getSpiffeID(ctx) + if err == nil { + ids, _ := m.spiffeIDConnectionMap.Load(spiffeID) + m.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + } + rv, err := next.Server(ctx).Close(ctx, conn) - _ = m.MonitorConnectionServer.(eventConsumer).Send(&networkservice.ConnectionEvent{ + _ = m.Send(&networkservice.ConnectionEvent{ Type: networkservice.ConnectionEventType_DELETE, Connections: map[string]*networkservice.Connection{conn.GetId(): conn.Clone()}, }) return rv, err } + +func (m *monitorServer) Send(event *networkservice.ConnectionEvent) (_ error) { + m.executor.AsyncExec(func() { + if event.Type == networkservice.ConnectionEventType_UPDATE { + for _, conn := range event.GetConnections() { + m.connections[conn.GetId()] = conn.Clone() + } + } + if event.Type == networkservice.ConnectionEventType_DELETE { + for _, conn := range event.GetConnections() { + delete(m.connections, conn.GetId()) + } + } + if event.Type == networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER { + // sending event with INIITIAL_STATE_TRANSFER not permitted + return + } + for id, filter := range m.filters { + id, filter := id, filter + e := event.Clone() + filter.executor.AsyncExec(func() { + var err error + select { + case <-filter.Context().Done(): + m.executor.AsyncExec(func() { + delete(m.filters, id) + }) + default: + err = filter.Send(e) + } + if err != nil { + m.executor.AsyncExec(func() { + delete(m.filters, id) + }) + } + }) + } + }) + return nil +} + +func getSpiffeID(ctx context.Context) (string, error) { + p, ok := peer.FromContext(ctx) + var cert *x509.Certificate + if ok { + cert = opa.ParseX509Cert(p.AuthInfo) + } + spiffeID, err := x509svid.IDFromCert(cert) + if err == nil { + return spiffeID.String(), nil + } + return "", err +} diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index 580ac2b46..7bb64aa03 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 Cisco and/or its affiliates. +// Copyright (c) 2020-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -18,12 +18,18 @@ package monitor_test import ( "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" "testing" "time" "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" @@ -32,10 +38,39 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters" ) +const ( + // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" + certPem = `-----BEGIN CERTIFICATE----- +MIIBvjCCAWWgAwIBAgIQbnFakUhzr52nHoLGltZDyDAKBggqhkjOPQQDAjAdMQsw +CQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwHhcNMjAwMTAxMDEwMTAxWhcNMzAw +MTAxMDEwMTAxWjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAASlFpbASv+NIyVdFwTp22JR5gx7D6LJ01Z8Wz0S +ZiBneWRAcYUBBQY6zKwr/RQtCDxUcFfFyq4zEfUD29a5Phnoo4GGMIGDMA4GA1Ud +DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T +AQH/BAIwADAdBgNVHQ4EFgQUJJpYlJa1eNEcks+zJcwKClopSAowJQYDVR0RBB4w +HIYac3BpZmZlOi8vdGVzdC5jb20vd29ya2xvYWQwCgYIKoZIzj0EAwIDRwAwRAIg +Dk6tlURSF8ULhNbnyUxFQ33rDic2dX8jOIstV2dWErwCIDRH2yw0swTcUMQWYgHy +aMp+T747AZGjOEfwHb9/w+7m +-----END CERTIFICATE----- +` +) + func TestMonitorServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + // Get MonitorServer SpiffeId from peer context + block, _ := pem.Decode([]byte(certPem)) + x509cert, err := x509.ParseCertificate(block.Bytes) + assert.Nil(t, err) + authInfo := &credentials.TLSInfo{ + State: tls.ConnectionState{ + PeerCertificates: []*x509.Certificate{x509cert}, + }} + ctx, cancel := context.WithTimeout( + peer.NewContext( + context.Background(), &peer.Peer{AuthInfo: authInfo}), + time.Second, + ) defer cancel() // Specify pathSegments to test diff --git a/pkg/networkservice/core/adapters/monitor_client_to_server.go b/pkg/networkservice/core/adapters/monitor_client_to_server.go index 699d4e5aa..97791347d 100644 --- a/pkg/networkservice/core/adapters/monitor_client_to_server.go +++ b/pkg/networkservice/core/adapters/monitor_client_to_server.go @@ -18,8 +18,6 @@ package adapters import ( "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorClientToServer struct { @@ -32,7 +30,7 @@ func NewMonitorClientToServer(client networkservice.MonitorConnectionClient) net srv := &monitorClientToServer{ client: client, } - return next.NewMonitorConnectionServer(authorize.NewMonitorConnectionsServer(), srv) + return srv } func (m monitorClientToServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { diff --git a/pkg/networkservice/core/adapters/monitor_server_to_client.go b/pkg/networkservice/core/adapters/monitor_server_to_client.go index 6d154597c..960153545 100644 --- a/pkg/networkservice/core/adapters/monitor_server_to_client.go +++ b/pkg/networkservice/core/adapters/monitor_server_to_client.go @@ -26,9 +26,6 @@ import ( "google.golang.org/grpc" "github.com/networkservicemesh/sdk/pkg/networkservice/core/eventchannel" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" - ) type monitorServerToClient struct { @@ -38,8 +35,7 @@ type monitorServerToClient struct { // NewMonitorServerToClient - returns a MonitorConnectionClient that is a wrapper around the MonitorConnectionServer // events sent to the MonitorConnectionServer are received byt the MonitorConnectionClient func NewMonitorServerToClient(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionClient { - client := &monitorServerToClient{server: server} - return next.NewMonitorConnectionClient(authorize.NewMonitorConnectionsClient(), client) + return &monitorServerToClient{server: server} } func (m *monitorServerToClient) MonitorConnections(ctx context.Context, selector *networkservice.MonitorScopeSelector, _ ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { diff --git a/pkg/networkservice/core/eventchannel/monitor_client.go b/pkg/networkservice/core/eventchannel/monitor_client.go index fb6e1a5cd..a5a5d7cd7 100644 --- a/pkg/networkservice/core/eventchannel/monitor_client.go +++ b/pkg/networkservice/core/eventchannel/monitor_client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Cisco and/or its affiliates. +// Copyright (c) 2020-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -26,10 +26,10 @@ import ( "sync" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "google.golang.org/grpc" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/edwarnicke/serialize" ) @@ -46,9 +46,7 @@ type monitorConnectionClient struct { // returned from calling MonitorConnections receive the event. // Note: Does not perform filtering basedon MonitorScopeSelector func NewMonitorConnectionClient(eventCh <-chan *networkservice.ConnectionEvent) networkservice.MonitorConnectionClient { - srv := &monitorConnectionClient{eventCh: eventCh} - return next.NewMonitorConnectionClient( - authorize.NewMonitorConnectionsClient(), srv) + return next.NewMonitorConnectionClient(&monitorConnectionClient{eventCh: eventCh}) } func (m *monitorConnectionClient) MonitorConnections(ctx context.Context, _ *networkservice.MonitorScopeSelector, _ ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { diff --git a/pkg/tools/monitor/authorize/client.go b/pkg/tools/monitor/authorize/client.go deleted file mode 100644 index 9f22c5214..000000000 --- a/pkg/tools/monitor/authorize/client.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2022 Doc.ai 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 authorize - -import ( - "context" - "fmt" - - "github.com/golang-jwt/jwt/v4" - "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/sirupsen/logrus" - "github.com/spiffe/go-spiffe/v2/workloadapi" - "google.golang.org/grpc" - - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" - "github.com/networkservicemesh/sdk/pkg/tools/opa" -) - -type authorizeMonitorConnectionsClient struct { - policies policiesList -} - -// NewMonitorConnectionsClient - returns a new authorization NewMonitorConnectionsClient -// Authorize client checks rigiht side of path. -func NewMonitorConnectionsClient(opts ...Option) networkservice.MonitorConnectionClient { - var result = &authorizeMonitorConnectionsClient{ - policies: []Policy{ - opa.WithServiceOwnConnectionPolicy(), - }, - } - - for _, o := range opts { - o.apply(&result.policies) - } - - return result -} - -func (a *authorizeMonitorConnectionsClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { - clt, err := next.MonitorConnectionClient(ctx).MonitorConnections(ctx, in, opts...) - if err != nil { - return nil, err - } - event, err := clt.Recv() - if err != nil { - return nil, err - } - // add var connIdMap map[spiffeid.ID]*networkservice.Connection - for k, v := range event.Connections { - logrus.Infof("Conn %s: %v \n", k, v) - nextToken := v.GetNextPathSegment().Token - logrus.Infof("Conn next path token %v \n", nextToken) - tokenDecoded, err := jwt.ParseWithClaims( - nextToken, &jwt.RegisteredClaims{}, - func(token *jwt.Token) (interface{}, error) {return []byte("AllYourBase"), nil}, - ) - if err != nil { - return nil, fmt.Errorf("error decoding connection token: %+v", err) - } - logrus.Infof("decoded Token %v \n", tokenDecoded) - decodedClaims := tokenDecoded.Claims.(jwt.RegisteredClaims) - logrus.Infof("decoded Claims %v \n", decodedClaims) - logrus.Infof("Subject from the Claims %v", decodedClaims.Subject) - logrus.Infof("Audienct from the Claims %v", decodedClaims.Audience) - } - - source, err := workloadapi.NewX509Source(ctx) - if err != nil { - return nil, fmt.Errorf("error getting x509 source: %+v", err) - } - svid, err := source.GetX509SVID() - if err != nil { - return nil, fmt.Errorf("error getting x509 svid: %+v", err) - } - logrus.Infof("Service Own Spiffe ID %v", svid.ID) - - // if err := a.policies.check(ctx, svid); err != nil { - // return nil, err - // } - - return clt, nil -} diff --git a/pkg/tools/monitor/authorize/common.go b/pkg/tools/monitor/authorize/common.go index ac7354885..1ce8d5286 100644 --- a/pkg/tools/monitor/authorize/common.go +++ b/pkg/tools/monitor/authorize/common.go @@ -18,8 +18,6 @@ package authorize import ( "context" - - "github.com/networkservicemesh/api/pkg/api/networkservice" ) // Policy represents authorization policy for monitor connection. @@ -30,7 +28,7 @@ type Policy interface { type policiesList []Policy -func (l *policiesList) check(ctx context.Context, srv *networkservice.Path) error { +func (l *policiesList) check(ctx context.Context, srv MonitorOpaInput) error { if l == nil { return nil } diff --git a/pkg/tools/monitor/authorize/connection_map.gen.go b/pkg/tools/monitor/authorize/connection_map.gen.go new file mode 100644 index 000000000..d065515f9 --- /dev/null +++ b/pkg/tools/monitor/authorize/connection_map.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output connection_map.gen.go -type SpiffeIDConnectionMap -output connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. +// Install -output connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output connection_map.gen.go -type SpiffeIDConnectionMap" + +package authorize + +import ( + "sync" // Used by sync.Map. +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert SpiffeIDConnectionMap literal (type SpiffeIDConnectionMap) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(SpiffeIDConnectionMap{}) +} + +var _nil_SpiffeIDConnectionMap_string_value = func() (val []string) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *SpiffeIDConnectionMap) Load(key string) ([]string, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_SpiffeIDConnectionMap_string_value, ok + } + return value.([]string), ok +} + +// Store sets the value for a key. +func (m *SpiffeIDConnectionMap) Store(key string, value []string) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value []string) ([]string, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_SpiffeIDConnectionMap_string_value, loaded + } + return actual.([]string), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value []string, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_SpiffeIDConnectionMap_string_value, loaded + } + return actual.([]string), loaded +} + +// Delete deletes the value for a key. +func (m *SpiffeIDConnectionMap) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *SpiffeIDConnectionMap) Range(f func(key string, value []string) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.([]string)) + }) +} diff --git a/pkg/tools/monitor/authorize/gen.go b/pkg/tools/monitor/authorize/gen.go new file mode 100644 index 000000000..1b1d3c81e --- /dev/null +++ b/pkg/tools/monitor/authorize/gen.go @@ -0,0 +1,26 @@ +// 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 authorize + +import ( + "sync" +) + +//go:generate go-syncmap -output connection_map.gen.go -type SpiffeIDConnectionMap + +// SpiffeIDConnectionMap - sync.Map with key == string and value == []string +type SpiffeIDConnectionMap sync.Map diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index 468569c83..7eb967eb9 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -18,29 +18,29 @@ package authorize import ( - "fmt" + "crypto/x509" - "github.com/golang-jwt/jwt/v4" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/sirupsen/logrus" - "github.com/spiffe/go-spiffe/v2/workloadapi" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/svid/x509svid" + "google.golang.org/grpc/peer" "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" ) -type authorizeServer struct { - policies policiesList +type authorizeMonitorConnectionsServer struct { + policies policiesList + spiffeIDConnectionMap *SpiffeIDConnectionMap } -// NewMonitorConnectionsServer - returns a new authorization networkservicemesh.MonitorConnectionServer -// Authorize server checks left side of Path. -func NewMonitorConnectionsServer(opts ...Option) networkservice.MonitorConnectionServer { - // todo: add policies - var s = &authorizeServer{ +// NewMonitorConnectionServer - returns a new authorization networkservicemesh.MonitorConnectionServer +func NewMonitorConnectionServer(spiffeIDConnectionMap *SpiffeIDConnectionMap, opts ...Option) networkservice.MonitorConnectionServer { + var s = &authorizeMonitorConnectionsServer{ policies: []Policy{ opa.WithServiceOwnConnectionPolicy(), }, + spiffeIDConnectionMap: spiffeIDConnectionMap, } for _, o := range opts { o.apply(&s.policies) @@ -48,40 +48,42 @@ func NewMonitorConnectionsServer(opts ...Option) networkservice.MonitorConnectio return s } -func (a *authorizeServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { +// MonitorOpaInput - used to pass complex structure to monitor policies +type MonitorOpaInput struct { + SpiffeIDConnectionMap map[string][]string `json:"spiffe_id_connection_map"` + PathSegments []*networkservice.PathSegment `json:"path_segments"` + ServiceSpiffeID string `json:"service_spiffe_id"` +} + +func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { ctx := srv.Context() - var decodedClaims jwt.RegisteredClaims - for _, seg := range in.GetPathSegments(){ - logrus.Printf("Conn next path token %v \n", seg.Token) - tokenDecoded, err := jwt.ParseWithClaims( - seg.Token, &jwt.RegisteredClaims{}, - func(token *jwt.Token) (interface{}, error) {return []byte("AllYourBase"), nil}, - ) - if err != nil { - return fmt.Errorf("error decoding connection token: %+v", err) - } - logrus.Infof("decoded Token %v \n", tokenDecoded) - decodedClaims = tokenDecoded.Claims.(jwt.RegisteredClaims) - logrus.Infof("decoded Claims %v \n", decodedClaims) - logrus.Infof("Subject from the Claims %v", decodedClaims.Subject) - logrus.Infof("Audienct from the Claims %v", decodedClaims.Audience) - + p, ok := peer.FromContext(ctx) + var cert *x509.Certificate + if ok { + cert = opa.ParseX509Cert(p.AuthInfo) } - source, err := workloadapi.NewX509Source(ctx) - if err != nil { - return fmt.Errorf("error getting x509 source: %+v", err) + var input MonitorOpaInput + var spiffeID spiffeid.ID + if cert != nil { + spiffeID, _ = x509svid.IDFromCert(cert) } - svid, err := source.GetX509SVID() - if err != nil { - return fmt.Errorf("error getting x509 svid: %+v", err) + simpleMap := make(map[string][]string) + a.spiffeIDConnectionMap.Range( + func(k string, v []string) bool { + simpleMap[k] = v + return true + }, + ) + + input = MonitorOpaInput{ + ServiceSpiffeID: spiffeID.String(), + SpiffeIDConnectionMap: simpleMap, + PathSegments: in.PathSegments, } - logrus.Infof("Service Own Spiffe ID %v", svid.ID) + if err := a.policies.check(ctx, input); err != nil { + return err + } - // if _, ok := peer.FromContext(ctx); ok { - // if err := a.policies.check(ctx, svid); err != nil { - // return err - // } - // } return next.MonitorConnectionServer(ctx).MonitorConnections(in, srv) } diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go new file mode 100644 index 000000000..c20dd5340 --- /dev/null +++ b/pkg/tools/monitor/authorize/server_test.go @@ -0,0 +1,221 @@ +// Copyright (c) 2022 Doc.ai 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 authorize_test + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "testing" + "time" + + "go.uber.org/goleak" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" + + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/opa" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/stretchr/testify/require" +) + +const ( + // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" + certPem = `-----BEGIN CERTIFICATE----- +MIIBvjCCAWWgAwIBAgIQbnFakUhzr52nHoLGltZDyDAKBggqhkjOPQQDAjAdMQsw +CQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwHhcNMjAwMTAxMDEwMTAxWhcNMzAw +MTAxMDEwMTAxWjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAASlFpbASv+NIyVdFwTp22JR5gx7D6LJ01Z8Wz0S +ZiBneWRAcYUBBQY6zKwr/RQtCDxUcFfFyq4zEfUD29a5Phnoo4GGMIGDMA4GA1Ud +DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T +AQH/BAIwADAdBgNVHQ4EFgQUJJpYlJa1eNEcks+zJcwKClopSAowJQYDVR0RBB4w +HIYac3BpZmZlOi8vdGVzdC5jb20vd29ya2xvYWQwCgYIKoZIzj0EAwIDRwAwRAIg +Dk6tlURSF8ULhNbnyUxFQ33rDic2dX8jOIstV2dWErwCIDRH2yw0swTcUMQWYgHy +aMp+T747AZGjOEfwHb9/w+7m +-----END CERTIFICATE----- +` + spiffeID1 = "spiffe://test.com/workload" + spiffeID2 = "spiffe://test.com/anotherWorkload" +) + +func getContextWithTLSCert() (context.Context, error) { + block, _ := pem.Decode([]byte(certPem)) + x509cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + authInfo := &credentials.TLSInfo{ + State: tls.ConnectionState{ + PeerCertificates: []*x509.Certificate{x509cert}, + }, + } + + return peer.NewContext(context.Background(), &peer.Peer{AuthInfo: authInfo}), nil +} + +func testPolicy() authorize.Policy { + return opa.WithPolicyFromSource(` + package test + + default allow = false + + allow { + conn_ids := {y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]} + path_conn_ids := {x | x = input.path_segments[_].id} + conn_ids == path_conn_ids + } +`, "allow", opa.True) +} + +type testEmptyMCMCServer struct { + networkservice.MonitorConnection_MonitorConnectionsServer + context context.Context +} + +func (t *testEmptyMCMCServer) Send(event *networkservice.ConnectionEvent) error { + return nil +} + +func (t *testEmptyMCMCServer) Context() context.Context { + return t.context +} +func TestAuthzEndpoint(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + suits := []struct { + name string + baseCtx bool + pathSegments []*networkservice.PathSegment + spiffeIDConnMap map[string][]string + denied bool + }{ + { + name: "simple positive test without peer context", + baseCtx: false, + pathSegments: make([]*networkservice.PathSegment, 0), + denied: false, + }, + { + name: "simple positive test with peer context", + baseCtx: false, + pathSegments: make([]*networkservice.PathSegment, 0), + denied: false, + }, + { + name: "positive test with nonempty objects", + baseCtx: true, + pathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + spiffeIDConnMap: map[string][]string{spiffeID1: {"conn1"}}, + denied: false, + }, + { + name: "positive test with several spiffeIds objects", + baseCtx: true, + pathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + spiffeIDConnMap: map[string][]string{spiffeID1: {"conn1"}, spiffeID2: {"conn2"}}, + denied: false, + }, + { + name: "negative test without peer context", + baseCtx: false, + pathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + spiffeIDConnMap: map[string][]string{spiffeID1: {"conn1"}}, + denied: true, + }, + { + name: "negative test with empty path", + baseCtx: true, + pathSegments: make([]*networkservice.PathSegment, 0), + spiffeIDConnMap: map[string][]string{spiffeID1: {"conn1"}}, + denied: true, + }, + { + name: "negative test without peer context", + baseCtx: false, + pathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + spiffeIDConnMap: make(map[string][]string), + denied: true, + }, + { + name: "negative test with wrong spiffeID in the map", + baseCtx: true, + pathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + spiffeIDConnMap: map[string][]string{spiffeID2: {"conn1"}}, + denied: true, + }, + } + + for i := range suits { + s := suits[i] + t.Run(s.name, func(t *testing.T) { + var baseCtx context.Context + var err error + baseCtx = context.Background() + if s.baseCtx { + baseCtx, err = getContextWithTLSCert() + require.NoError(t, err) + } + spiffeIDConnectionMap := authorize.SpiffeIDConnectionMap{} + for k, v := range s.spiffeIDConnMap { + spiffeIDConnectionMap.Store(k, v) + } + ctx, cancel := context.WithTimeout(baseCtx, time.Second) + defer cancel() + srv := authorize.NewMonitorConnectionServer( + &spiffeIDConnectionMap, authorize.WithPolicies(testPolicy())) + checkResult := func(err error) { + if !s.denied { + require.Nil(t, err, "monitorConnections expected to be not denied: ") + return + } + require.NotNil(t, err, "monitorConnections expected to be denied") + s, ok := status.FromError(err) + require.True(t, ok, "error without error status code"+err.Error()) + require.Equal(t, s.Code(), codes.PermissionDenied, "wrong error status code") + } + + err = srv.MonitorConnections( + &networkservice.MonitorScopeSelector{PathSegments: s.pathSegments}, &testEmptyMCMCServer{context: ctx}) + checkResult(err) + }) + } +} + +func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + peerCtx, err := getContextWithTLSCert() + require.NoError(t, err) + ctx, cancel := context.WithTimeout(peerCtx, time.Second) + defer cancel() + + spiffeIDConnectionMap := authorize.SpiffeIDConnectionMap{} + spiffeIDConnectionMap.Store(spiffeID1, []string{"conn1"}) + + selector := &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, + } + // simulate heal request + err = authorize.NewMonitorConnectionServer( + &spiffeIDConnectionMap).MonitorConnections( + selector, &testEmptyMCMCServer{context: ctx}) + require.NoError(t, err) +} diff --git a/pkg/tools/monitor/next/client_test.go b/pkg/tools/monitor/next/client_test.go new file mode 100644 index 000000000..ed7efdb6d --- /dev/null +++ b/pkg/tools/monitor/next/client_test.go @@ -0,0 +1,106 @@ +// Copyright (c) 2022 Doc.ai 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 next_test + +import ( + "context" + "fmt" + "io" + "sync" + "testing" + + "google.golang.org/grpc" + + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/assert" +) + +type testEmptyMCMCClient struct { + ctx context.Context + grpc.ClientStream +} + +func (t *testEmptyMCMCClient) Recv() (*networkservice.ConnectionEvent, error) { + return nil, io.EOF +} + +func (t *testEmptyMCMCClient) Context() context.Context { + return t.ctx +} + +type testEmptyMCClient struct{} + +func (t *testEmptyMCClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { + return &testEmptyMCMCClient{ctx: ctx}, nil +} +func emptyMCClient() networkservice.MonitorConnectionClient { + return &testEmptyMCClient{} +} + +type testVisitMCClient struct{} + +// MonitorConnections(ctx context.Context, in *MonitorScopeSelector, opts ...grpc.CallOption) (MonitorConnection_MonitorConnectionsClient, error) +func (t *testVisitMCClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { + return next.MonitorConnectionClient(ctx).MonitorConnections(visit(ctx), in, opts...) +} + +func visitMCClient() networkservice.MonitorConnectionClient { + return &testVisitMCClient{} +} + +func TestNewMonitorConnectionClientShouldNotPanic(t *testing.T) { + assert.NotPanics(t, func() { + _, _ = next.NewMonitorConnectionClient().MonitorConnections(context.Background(), nil) + _, _ = next.NewWrappedMonitorConnectionClient(func(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { + return client + }).MonitorConnections(context.Background(), nil) + }) +} + +func TestDataRaceMonitorConnectionClient(t *testing.T) { + c := next.NewMonitorConnectionClient(emptyMCClient()) + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + _, _ = c.MonitorConnections(context.Background(), nil) + }() + } + wg.Wait() +} + +func TestNSClientBranches(t *testing.T) { + servers := [][]networkservice.MonitorConnectionClient{ + {visitMCClient()}, + {visitMCClient(), visitMCClient()}, + {visitMCClient(), visitMCClient(), visitMCClient()}, + {emptyMCClient(), visitMCClient(), visitMCClient()}, + {visitMCClient(), emptyMCClient(), visitMCClient()}, + {visitMCClient(), visitMCClient(), emptyMCClient()}, + {next.NewMonitorConnectionClient(), next.NewMonitorConnectionClient(visitMCClient(), next.NewMonitorConnectionClient()), visitMCClient()}, + } + expects := []int{1, 2, 3, 0, 1, 2, 2, 2} + for i, sample := range servers { + s := next.NewMonitorConnectionClient(sample...) + ctx := visit(context.Background()) + _, _ = s.MonitorConnections(ctx, nil) + assert.Equal(t, expects[i], visitValue(ctx), fmt.Sprintf("sample index: %v", i)) + } +} \ No newline at end of file diff --git a/pkg/tools/monitor/next/common_test.go b/pkg/tools/monitor/next/common_test.go new file mode 100644 index 000000000..a86443de0 --- /dev/null +++ b/pkg/tools/monitor/next/common_test.go @@ -0,0 +1,41 @@ +// Copyright (c) 2022 Doc.ai 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 next_test + +import "context" + +type contextKeyType string + +const ( + visitKey contextKeyType = "visitKey" +) + +func visit(ctx context.Context) context.Context { + if v, ok := ctx.Value(visitKey).(*int); ok { + *v++ + return ctx + } + val := 0 + return context.WithValue(ctx, visitKey, &val) +} + +func visitValue(ctx context.Context) int { + if v, ok := ctx.Value(visitKey).(*int); ok { + return *v + } + return 0 +} diff --git a/pkg/tools/monitor/next/server.go b/pkg/tools/monitor/next/server.go index 949e62e56..1d0cf573e 100644 --- a/pkg/tools/monitor/next/server.go +++ b/pkg/tools/monitor/next/server.go @@ -20,13 +20,9 @@ import ( "context" "github.com/networkservicemesh/api/pkg/api/networkservice" -) -type nextMonitorConnectionServer struct { - servers []networkservice.MonitorConnectionServer - index int - nextParent networkservice.MonitorConnectionServer -} + "github.com/networkservicemesh/sdk/pkg/tools/monitor/streamcontext" +) // MonitorConnectionsServerWrapper - a function that wraps around a networkservice.MonitorConnectionServer type MonitorConnectionsServerWrapper func(networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer @@ -34,24 +30,32 @@ type MonitorConnectionsServerWrapper func(networkservice.MonitorConnectionServer // MonitorConnectionsServerChainer - a function that chains together a list of networkservice.MonitorConnectionServers type MonitorConnectionsServerChainer func(...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer -func newWrappedMonitorConnectionServer(wrapper MonitorConnectionsServerWrapper, servers ...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { +type nextMonitorConnectionServer struct { + servers []networkservice.MonitorConnectionServer + index int + nextParent networkservice.MonitorConnectionServer +} + +// NewWrappedMonitorConnectionServer - creates a chain of servers with each one wrapped in wrapper +func NewWrappedMonitorConnectionServer(wrapper MonitorConnectionsServerWrapper, servers ...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { rv := &nextMonitorConnectionServer{servers: make([]networkservice.MonitorConnectionServer, 0, len(servers))} - for _, c := range servers { - rv.servers = append(rv.servers, wrapper(c)) + for _, srv := range servers { + rv.servers = append(rv.servers, wrapper(srv)) } return rv } // NewMonitorConnectionServer - chains together servers into a single networkservice.MonitorConnectionServer func NewMonitorConnectionServer(servers ...networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { - return newWrappedMonitorConnectionServer(func(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { - return server - }, servers...) + return NewWrappedMonitorConnectionServer( + func(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { + return server + }, servers...) } func (n *nextMonitorConnectionServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { - server, _ := n.getServerAndContext(srv.Context()) - return server.MonitorConnections(in, srv) + server, ctx := n.getServerAndContext(srv.Context()) + return server.MonitorConnections(in, streamcontext.MonitorConnectionMonitorConnectionsServer(ctx, srv)) } func (n *nextMonitorConnectionServer) getServerAndContext(ctx context.Context) (networkservice.MonitorConnectionServer, context.Context) { diff --git a/pkg/tools/monitor/next/server_test.go b/pkg/tools/monitor/next/server_test.go new file mode 100644 index 000000000..b21039641 --- /dev/null +++ b/pkg/tools/monitor/next/server_test.go @@ -0,0 +1,106 @@ +// Copyright (c) 2022 Doc.ai 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 next_test + +import ( + "context" + "fmt" + "sync" + "testing" + + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/streamcontext" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/assert" +) + +type testEmptyMCServer struct{} + +func (t *testEmptyMCServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { + return nil +} + +type testEmptyMCMCServer struct { + networkservice.MonitorConnection_MonitorConnectionsServer + context context.Context +} + +func (t *testEmptyMCMCServer) Send(event *networkservice.ConnectionEvent) error { + return nil +} + +func (t *testEmptyMCMCServer) Context() context.Context { + return t.context +} + +func emptyMCServer() networkservice.MonitorConnectionServer { + return &testEmptyMCServer{} +} + +type testVisitMCServer struct{} + +func (t *testVisitMCServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { + srv = streamcontext.MonitorConnectionMonitorConnectionsServer(visit(srv.Context()), srv) + rv := next.MonitorConnectionServer(srv.Context()).MonitorConnections(in, srv) + return rv +} + +func visitMCServer() networkservice.MonitorConnectionServer { + return &testVisitMCServer{} +} + +func TestNewMonitorConnectionsServerShouldNotPanic(t *testing.T) { + assert.NotPanics(t, func() { + _ = next.NewMonitorConnectionServer().MonitorConnections(nil, &testEmptyMCMCServer{}) + _ = next.NewWrappedMonitorConnectionServer(func(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { + return server + }).MonitorConnections(nil, &testEmptyMCMCServer{}) + }) +} + +func TestNSServerBranches(t *testing.T) { + servers := [][]networkservice.MonitorConnectionServer{ + {visitMCServer()}, + {visitMCServer(), visitMCServer()}, + {visitMCServer(), visitMCServer(), visitMCServer()}, + {emptyMCServer(), visitMCServer(), visitMCServer()}, + {visitMCServer(), emptyMCServer(), visitMCServer()}, + {visitMCServer(), visitMCServer(), emptyMCServer()}, + {next.NewMonitorConnectionServer(), next.NewMonitorConnectionServer(visitMCServer(), next.NewMonitorConnectionServer()), visitMCServer()}, + } + expects := []int{1, 2, 3, 0, 1, 2, 2, 2} + for i, sample := range servers { + s := next.NewMonitorConnectionServer(sample...) + ctx := visit(context.Background()) + eventSrv := &testEmptyMCMCServer{context: ctx} + _ = s.MonitorConnections(nil, eventSrv) + assert.Equal(t, expects[i], visitValue(eventSrv.Context()), fmt.Sprintf("sample index: %v", i)) + } +} +func TestDataRaceMonitorConnectionServer(t *testing.T) { + s := next.NewMonitorConnectionServer(emptyMCServer()) + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + _ = s.MonitorConnections(nil, &testEmptyMCMCServer{}) + }() + } + wg.Wait() +} \ No newline at end of file diff --git a/pkg/tools/monitor/streamcontext/stream_context.go b/pkg/tools/monitor/streamcontext/stream_context.go new file mode 100644 index 000000000..93ffa38a0 --- /dev/null +++ b/pkg/tools/monitor/streamcontext/stream_context.go @@ -0,0 +1,68 @@ +// Copyright (c) 2022 Doc.ai 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 streamcontext provides API to extend context for authorize server +package streamcontext + +import ( + "context" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/tools/extend" +) + +type monitorConnectionMonitorConnectionsServer struct { + networkservice.MonitorConnection_MonitorConnectionsServer + ctx context.Context +} + +func (s *monitorConnectionMonitorConnectionsServer) Context() context.Context { + return s.ctx +} + +// MonitorConnectionMonitorConnectionsServer extends context for MonitorConnection_MonitorConnectionsServer +func MonitorConnectionMonitorConnectionsServer(ctx context.Context, server networkservice.MonitorConnection_MonitorConnectionsServer) networkservice.MonitorConnection_MonitorConnectionsServer { + if server != nil { + ctx = extend.WithValuesFromContext(server.Context(), ctx) + } + + return &monitorConnectionMonitorConnectionsServer{ + ctx: ctx, + MonitorConnection_MonitorConnectionsServer: server, + } +} + +type monitorConnectionMonitorConnectionsClient struct { + networkservice.MonitorConnection_MonitorConnectionsClient + ctx context.Context +} + +func (s *monitorConnectionMonitorConnectionsClient) Context() context.Context { + return s.ctx +} + +// MonitorConnectionMonitorConnectionsClient extends context for MonitorConnection_MonitorConnectionsClient +func MonitorConnectionMonitorConnectionsClient(ctx context.Context, client networkservice.MonitorConnection_MonitorConnectionsClient) networkservice.MonitorConnection_MonitorConnectionsClient { + if client != nil { + ctx = extend.WithValuesFromContext(client.Context(), ctx) + } + + return &monitorConnectionMonitorConnectionsClient{ + ctx: ctx, + MonitorConnection_MonitorConnectionsClient: client, + } +} \ No newline at end of file diff --git a/pkg/tools/opa/opainput.go b/pkg/tools/opa/opainput.go index 5c3f477c5..4ad2243d8 100644 --- a/pkg/tools/opa/opainput.go +++ b/pkg/tools/opa/opainput.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -21,11 +21,8 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/spiffe/go-spiffe/v2/svid/x509svid" + "github.com/pkg/errors" "google.golang.org/grpc/peer" "google.golang.org/grpc/credentials" @@ -40,19 +37,14 @@ func PreparedOpaInput(ctx context.Context, model interface{}) (map[string]interf p, ok := peer.FromContext(ctx) var cert *x509.Certificate if ok { - cert = parseX509Cert(p.AuthInfo) + cert = ParseX509Cert(p.AuthInfo) } var pemcert string - var spiffeID spiffeid.ID if cert != nil { pemcert = pemEncodingX509Cert(cert) - spiffeID, err := x509svid.IDFromCert(cert); if err == nil { - logrus.Infof("\nSpiffe ID %v\n", spiffeID.String()) - } } result["auth_info"] = map[string]interface{}{ "certificate": pemcert, - "ownSpiffeId": spiffeID, } return result, nil } @@ -62,7 +54,8 @@ func pemEncodingX509Cert(cert *x509.Certificate) string { return string(certpem) } -func parseX509Cert(authInfo credentials.AuthInfo) *x509.Certificate { +// ParseX509Cert - parse authinfo to get peer sertificate +func ParseX509Cert(authInfo credentials.AuthInfo) *x509.Certificate { var peerCert *x509.Certificate switch v := authInfo.(type) { diff --git a/pkg/tools/opa/policies.go b/pkg/tools/opa/policies.go index ba5ffcea1..1fe1d45a9 100644 --- a/pkg/tools/opa/policies.go +++ b/pkg/tools/opa/policies.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 // diff --git a/pkg/tools/opa/policies/service_connection.rego b/pkg/tools/opa/policies/service_connection.rego index 3a05b0762..45af96a96 100644 --- a/pkg/tools/opa/policies/service_connection.rego +++ b/pkg/tools/opa/policies/service_connection.rego @@ -16,15 +16,10 @@ package nsm -import input.attributes.request.http as http_request - default service_connection = false service_connection { - input.ID == svc_spiffe_id + conn_ids := {y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]} + path_conn_ids := {x | x = input.path_segments[_].id} + conn_ids == path_conn_ids } - -svc_spiffe_id = spiffe_id { - [_, _, uri_type_san] := split(http_request.headers["x-forwarded-client-cert"], ";") - [_, spiffe_id] := split(uri_type_san, "=") -} \ No newline at end of file diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go new file mode 100644 index 000000000..06a82785c --- /dev/null +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -0,0 +1,57 @@ +// Copyright (c) 2020-2021 Doc.ai 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 opa_test + +import ( + "context" + // "fmt" + "testing" + // "time" + // "github.com/spiffe/go-spiffe/v2/spiffeid" + // "github.com/spiffe/go-spiffe/v2/svid/x509svid" + // "github.com/spiffe/go-spiffe/v2/workloadapi" + // "github.com/stretchr/testify/require" + // "github.com/networkservicemesh/sdk/pkg/tools/opa" +) + +func TestWithServiceConnectionPolicy(t *testing.T) { + _, cancel := context.WithCancel(context.Background()) + + defer cancel() + + // source, err := workloadapi.NewX509Source(ctx) + // if err != nil { + // fmt.Errorf("couldn't get source %w", err) + // } + // fmt.Printf("New Source %v", source) + // validSvid, err := source.GetX509SVID() + // if err != nil { + // fmt.Errorf("couldn't get SVID %w", err) + // } + // fmt.Printf("New SVID %v", validSvid) + + // id := &spiffeid.ID{td: "", path: "some/path"} + // invalidSvid := &x509svid.SVID{ + // ID: id, + // } + + // p := opa.WithServiceOwnConnectionPolicy() + // err := p.Check(ctx, nil) + // require.Nil(t, err) + // err = p.Check(context.Background(), invalidSvid) + // require.NotNil(t, err) +} From 94f3027065fadc2675c1bee09438d84ba856a893 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 15 Jul 2022 16:09:17 +0700 Subject: [PATCH 06/39] small fixes Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/monitor/client_filter.go | 2 +- .../common/monitor/monitor_connection_server.go | 4 ---- pkg/networkservice/common/monitor/server.go | 4 ++++ pkg/networkservice/core/adapters/monitor_client_to_server.go | 3 +-- pkg/tools/monitor/next/context.go | 4 +--- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pkg/networkservice/common/monitor/client_filter.go b/pkg/networkservice/common/monitor/client_filter.go index 97ad7f951..881289629 100644 --- a/pkg/networkservice/common/monitor/client_filter.go +++ b/pkg/networkservice/common/monitor/client_filter.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2022 Cisco and/or its affiliates. +// Copyright (c) 2021 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index f4e268be8..eb54a7b21 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -69,7 +69,3 @@ func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.Mo return nil } - -type eventConsumer interface { - Send(event *networkservice.ConnectionEvent) (err error) -} diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index b5c4c07ea..81815e35b 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -190,3 +190,7 @@ func getSpiffeID(ctx context.Context) (string, error) { } return "", err } + +type eventConsumer interface { + Send(event *networkservice.ConnectionEvent) (err error) +} diff --git a/pkg/networkservice/core/adapters/monitor_client_to_server.go b/pkg/networkservice/core/adapters/monitor_client_to_server.go index 97791347d..80f38ee0c 100644 --- a/pkg/networkservice/core/adapters/monitor_client_to_server.go +++ b/pkg/networkservice/core/adapters/monitor_client_to_server.go @@ -27,10 +27,9 @@ type monitorClientToServer struct { // NewMonitorClientToServer - returns a MonitorConnectionServer that is wrapped around the provided MonitorConnectionClient // events that are received by the MonitorConnectionClient are sent to the MonitorConnectionServer func NewMonitorClientToServer(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionServer { - srv := &monitorClientToServer{ + return &monitorClientToServer{ client: client, } - return srv } func (m monitorClientToServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { diff --git a/pkg/tools/monitor/next/context.go b/pkg/tools/monitor/next/context.go index 12a62f35d..e4da7e57e 100644 --- a/pkg/tools/monitor/next/context.go +++ b/pkg/tools/monitor/next/context.go @@ -33,7 +33,6 @@ const ( // withNextMonitorConnectionServer - // Wraps 'parent' in a new Context that has the Server networkservice.MonitorConnectionServer to be called in the chain -// Should only be set in CompositeEndpoint.Request/Close func withNextMonitorConnectionServer(parent context.Context, next networkservice.MonitorConnectionServer) context.Context { if parent == nil { parent = context.Background() @@ -53,7 +52,6 @@ func MonitorConnectionServer(ctx context.Context) networkservice.MonitorConnecti // withNextMonitorConnectionClient - // Wraps 'parent' in a new Context that has the Client networkservice.MonitorConnectionClient to be called in the chain -// Should only be set in CompositeEndpoint.Request/Close iS IT? func withNextMonitorConnectionClient(parent context.Context, next networkservice.MonitorConnectionClient) context.Context { if parent == nil { panic("cannot create context from nil parent") @@ -69,4 +67,4 @@ func MonitorConnectionClient(ctx context.Context) networkservice.MonitorConnecti return rv } return &tailMonitorConnectionClient{} -} \ No newline at end of file +} From 0d7f7bdea5383213abaaad6bfc5ded1a846cc47e Mon Sep 17 00:00:00 2001 From: Network Service Mesh Bot <60070799+nsmbot@users.noreply.github.com> Date: Wed, 6 Jul 2022 04:33:25 -0500 Subject: [PATCH 07/39] =?UTF-8?q?Update=20go.mod=20and=20go.sum=20to=20lat?= =?UTF-8?q?est=20version=20from=20networkservicemesh/ap=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: anastasia.malysheva --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3247ac633..0c659f826 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/miekg/dns v1.1.49 github.com/nats-io/nats-streaming-server v0.24.3 github.com/nats-io/stan.go v0.10.2 - github.com/networkservicemesh/api v1.3.2-0.20220516230921-edaa6f46d6ab + github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb github.com/open-policy-agent/opa v0.16.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index 12b2f6b1c..43a04fbcd 100644 --- a/go.sum +++ b/go.sum @@ -193,8 +193,8 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.10.2 h1:gQLd05LhzmhFkHm3/qP/klYHfM/hys45GyHa1Uly/kI= github.com/nats-io/stan.go v0.10.2/go.mod h1:vo2ax8K2IxaR3JtEMLZRFKIdoK/3o1/PKueapB7ezX0= -github.com/networkservicemesh/api v1.3.2-0.20220516230921-edaa6f46d6ab h1:hV6T7Kvze0qQphqi6g5ZKFoJ0m08OKdWETUINo3tuaA= -github.com/networkservicemesh/api v1.3.2-0.20220516230921-edaa6f46d6ab/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8= +github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb h1:ElGI/wElHXwyZ3Fu7G6GoZTxlHFMck1T7Lt8DlMVz8M= +github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= From 7eccc154b3efd39705494674413d84e919f7f62f Mon Sep 17 00:00:00 2001 From: Network Service Mesh Bot <60070799+nsmbot@users.noreply.github.com> Date: Mon, 11 Jul 2022 10:47:49 -0500 Subject: [PATCH 08/39] =?UTF-8?q?Update=20go.mod=20and=20go.sum=20to=20lat?= =?UTF-8?q?est=20version=20from=20networkservicemesh/ap=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: anastasia.malysheva --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0c659f826..21f8a5a88 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/miekg/dns v1.1.49 github.com/nats-io/nats-streaming-server v0.24.3 github.com/nats-io/stan.go v0.10.2 - github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb + github.com/networkservicemesh/api v1.4.1-0.20220711153918-a59689088578 github.com/open-policy-agent/opa v0.16.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index 43a04fbcd..f3d9eb666 100644 --- a/go.sum +++ b/go.sum @@ -193,8 +193,8 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.10.2 h1:gQLd05LhzmhFkHm3/qP/klYHfM/hys45GyHa1Uly/kI= github.com/nats-io/stan.go v0.10.2/go.mod h1:vo2ax8K2IxaR3JtEMLZRFKIdoK/3o1/PKueapB7ezX0= -github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb h1:ElGI/wElHXwyZ3Fu7G6GoZTxlHFMck1T7Lt8DlMVz8M= -github.com/networkservicemesh/api v1.4.1-0.20220705145838-0b96f94a2adb/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8= +github.com/networkservicemesh/api v1.4.1-0.20220711153918-a59689088578 h1:2MZD6SGFULqTgMKA8BFy7F+ldRErAyxsWht7oCwCVRM= +github.com/networkservicemesh/api v1.4.1-0.20220711153918-a59689088578/go.mod h1:hOF2844BSstH1311oDMDgqqXS+kdc77htZNPRKl9mf8= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= From 9bbbcebe9e166b5d1ddfdb8aa406760498bb4eb1 Mon Sep 17 00:00:00 2001 From: Denis Tingaikin <49399980+denis-tingaikin@users.noreply.github.com> Date: Tue, 12 Jul 2022 00:30:25 +0300 Subject: [PATCH 09/39] fix: apply changes for distributed vl3 dns after manual testing (#1315) * apply vl3dns fixes Signed-off-by: Denis Tingaikin * fix linter issues Signed-off-by: denis-tingaikin * handle corner cases Signed-off-by: Denis Tingaikin Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/nsmgr/vl3_test.go | 25 ++++-- .../dnscontext/vl3dns/client.go | 84 +++++++++++++++++++ .../dnscontext/vl3dns/gen.go | 26 ++++++ .../dnscontext/vl3dns/map.gen.go | 75 +++++++++++++++++ .../dnscontext/vl3dns/options.go | 7 +- .../dnscontext/vl3dns/server.go | 80 +++++++++--------- 6 files changed, 246 insertions(+), 51 deletions(-) create mode 100644 pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go create mode 100644 pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go create mode 100644 pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go diff --git a/pkg/networkservice/chains/nsmgr/vl3_test.go b/pkg/networkservice/chains/nsmgr/vl3_test.go index 0a48591aa..ddfb4ed9a 100644 --- a/pkg/networkservice/chains/nsmgr/vl3_test.go +++ b/pkg/networkservice/chains/nsmgr/vl3_test.go @@ -68,7 +68,10 @@ func Test_NSC_ConnectsTo_vl3NSE(t *testing.T) { nseReg, sandbox.GenerateTestToken, vl3.NewServer(ctx, serverPrefixCh), - vl3dns.NewServer(ctx, vl3dns.WithDomainSchemes("{{ index .Labels \"podName\" }}.{{ .NetworkService }}."), vl3dns.WithDNSPort(40053)), + vl3dns.NewServer(ctx, + func() net.IP { return net.ParseIP("127.0.0.1") }, + vl3dns.WithDomainSchemes("{{ index .Labels \"podName\" }}.{{ .NetworkService }}."), + vl3dns.WithDNSPort(40053)), ) resolver := net.Resolver{ @@ -95,7 +98,6 @@ func Test_NSC_ConnectsTo_vl3NSE(t *testing.T) { require.NoError(t, err) require.Len(t, resp.GetContext().GetDnsContext().GetConfigs(), 1) require.Len(t, resp.GetContext().GetDnsContext().GetConfigs()[0].DnsServerIps, 1) - require.Equal(t, "10.0.0.0", resp.GetContext().GetDnsContext().GetConfigs()[0].DnsServerIps[0]) req.Connection = resp.Clone() @@ -152,14 +154,22 @@ func Test_vl3NSE_ConnectsTo_vl3NSE(t *testing.T) { serverPrefixCh <- &ipam.PrefixResponse{Prefix: "10.0.0.1/24"} + var dnsConfigs = new(vl3dns.Map) + _ = domain.Nodes[0].NewEndpoint( ctx, nseReg, sandbox.GenerateTestToken, vl3.NewServer(ctx, serverPrefixCh), - vl3dns.NewServer(ctx, vl3dns.WithDomainSchemes("{{ index .Labels \"podName\" }}.{{ .NetworkService }}."), vl3dns.WithDNSListenAndServeFunc(func(ctx context.Context, handler dnsutils.Handler, listenOn string) { - dnsutils.ListenAndServe(ctx, handler, ":50053") - }), vl3dns.WithDNSPort(40053)), + vl3dns.NewServer(ctx, + func() net.IP { return net.ParseIP("0.0.0.0") }, + vl3dns.WithDomainSchemes("{{ index .Labels \"podName\" }}.{{ .NetworkService }}."), + vl3dns.WithDNSListenAndServeFunc(func(ctx context.Context, handler dnsutils.Handler, listenOn string) { + dnsutils.ListenAndServe(ctx, handler, ":50053") + }), + vl3dns.WithConfigs(dnsConfigs), + vl3dns.WithDNSPort(40053), + ), ) resolver := net.Resolver{ @@ -174,7 +184,7 @@ func Test_vl3NSE_ConnectsTo_vl3NSE(t *testing.T) { defer close(clientPrefixCh) clientPrefixCh <- &ipam.PrefixResponse{Prefix: "127.0.0.1/32"} - nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(vl3.NewClient(ctx, clientPrefixCh))) + nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(vl3dns.NewClient(net.ParseIP("127.0.0.1"), dnsConfigs), vl3.NewClient(ctx, clientPrefixCh))) req := defaultRequest(nsReg.Name) req.Connection.Id = uuid.New().String() @@ -183,9 +193,8 @@ func Test_vl3NSE_ConnectsTo_vl3NSE(t *testing.T) { resp, err := nsc.Request(ctx, req) require.NoError(t, err) - require.Len(t, resp.GetContext().GetDnsContext().GetConfigs(), 1) require.Len(t, resp.GetContext().GetDnsContext().GetConfigs()[0].DnsServerIps, 1) - require.Equal(t, "10.0.0.0", resp.GetContext().GetDnsContext().GetConfigs()[0].DnsServerIps[0]) + require.Equal(t, "127.0.0.1", resp.GetContext().GetDnsContext().GetConfigs()[0].DnsServerIps[0]) require.Equal(t, "127.0.0.1/32", resp.GetContext().GetIpContext().GetSrcIpAddrs()[0]) req.Connection = resp.Clone() diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go new file mode 100644 index 000000000..40ccd5b6a --- /dev/null +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go @@ -0,0 +1,84 @@ +// 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 vl3dns + +import ( + "context" + "net" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/networkservicemesh/api/pkg/api/networkservice" + "google.golang.org/grpc" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type vl3DNSClient struct { + dnsServerIP net.IP + dnsConfigs *Map +} + +// NewClient - returns a new null client that does nothing but call next.Client(ctx).{Request/Close} and return the result +// This is very useful in testing +func NewClient(dnsServerIP net.IP, dnsConfigs *Map) networkservice.NetworkServiceClient { + return &vl3DNSClient{ + dnsServerIP: dnsServerIP, + dnsConfigs: dnsConfigs, + } +} + +func (n *vl3DNSClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + if request.GetConnection() == nil { + request.Connection = new(networkservice.Connection) + } + if request.GetConnection().GetContext() == nil { + request.GetConnection().Context = new(networkservice.ConnectionContext) + } + if request.GetConnection().GetContext().GetDnsContext() == nil { + request.GetConnection().GetContext().DnsContext = new(networkservice.DNSContext) + } + + request.GetConnection().GetContext().GetDnsContext().Configs = []*networkservice.DNSConfig{ + { + DnsServerIps: []string{n.dnsServerIP.String()}, + }, + } + resp, err := next.Client(ctx).Request(ctx, request, opts...) + + if err == nil { + for _, config := range resp.GetContext().GetDnsContext().GetConfigs() { + var skip = false + for _, ip := range config.DnsServerIps { + if ip == n.dnsServerIP.String() { + skip = true + break + } + } + if skip { + continue + } + n.dnsConfigs.Store(resp.GetId(), config) + } + } + + return resp, err +} + +func (n *vl3DNSClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + n.dnsConfigs.Delete(conn.GetId()) + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go new file mode 100644 index 000000000..7c26deb73 --- /dev/null +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go @@ -0,0 +1,26 @@ +// 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 vl3dns + +import ( + "sync" +) + +//go:generate go-syncmap -output map.gen.go -type Map + +// Map - sync.Map with key == string and value == networkservice.DNSConfig +type Map sync.Map diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go new file mode 100644 index 000000000..64e2b83c2 --- /dev/null +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output map.gen.go -type Map -output map.gen.go -type Map"; DO NOT EDIT. +package vl3dns + +import ( + "sync" // Used by sync.Map. + + "github.com/networkservicemesh/api/pkg/api/networkservice" +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert Map literal (type Map) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(Map{}) +} + +var _nil_Map_networkservice_DNSConfig_value = func() (val *networkservice.DNSConfig) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *Map) Load(key string) (*networkservice.DNSConfig, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_Map_networkservice_DNSConfig_value, ok + } + return value.(*networkservice.DNSConfig), ok +} + +// Store sets the value for a key. +func (m *Map) Store(key string, value *networkservice.DNSConfig) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *Map) LoadOrStore(key string, value *networkservice.DNSConfig) (*networkservice.DNSConfig, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_Map_networkservice_DNSConfig_value, loaded + } + return actual.(*networkservice.DNSConfig), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *Map) LoadAndDelete(key string) (value *networkservice.DNSConfig, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_Map_networkservice_DNSConfig_value, loaded + } + return actual.(*networkservice.DNSConfig), loaded +} + +// Delete deletes the value for a key. +func (m *Map) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *Map) Range(f func(key string, value *networkservice.DNSConfig) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.(*networkservice.DNSConfig)) + }) +} diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go index c58c72d93..2fc6e818a 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go @@ -19,7 +19,6 @@ package vl3dns import ( "context" "fmt" - "net/url" "text/template" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" @@ -28,10 +27,10 @@ import ( // Option configures vl3DNSServer type Option func(*vl3DNSServer) -// WithInitialFanoutList sets initial list to fanout queries -func WithInitialFanoutList(initialFanoutList []url.URL) Option { +// WithConfigs sets initial list to fanout queries +func WithConfigs(m *Map) Option { return func(vd *vl3DNSServer) { - vd.initialFanoutList = initialFanoutList + vd.configs = m } } diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go index a7548ec11..df36e2f57 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go @@ -23,7 +23,6 @@ import ( "net" "net/url" "strings" - "sync" "text/template" "github.com/golang/protobuf/ptypes/empty" @@ -42,12 +41,12 @@ import ( type vl3DNSServer struct { dnsServerRecords memory.Map - fanoutAddresses sync.Map domainSchemeTemplates []*template.Template - initialFanoutList []url.URL + configs *Map dnsPort int dnsServer dnsutils.Handler listenAndServeDNS func(ctx context.Context, handler dnsutils.Handler, listenOn string) + getDNSServerIP func() net.IP } type clientDNSNameKey struct{} @@ -57,10 +56,12 @@ type clientDNSNameKey struct{} // By default is using fanout dns handler to connect to other vl3 nses. // chanCtx is using for signal to stop dns server. // opts confugre vl3dns networkservice instance with specific behavior. -func NewServer(chanCtx context.Context, opts ...Option) networkservice.NetworkServiceServer { +func NewServer(chanCtx context.Context, getDNSServerIP func() net.IP, opts ...Option) networkservice.NetworkServiceServer { var result = &vl3DNSServer{ dnsPort: 53, listenAndServeDNS: dnsutils.ListenAndServe, + getDNSServerIP: getDNSServerIP, + configs: new(Map), } for _, opt := range opts { @@ -86,13 +87,12 @@ func (n *vl3DNSServer) Request(ctx context.Context, request *networkservice.Netw request.Connection.Context.DnsContext = new(networkservice.DNSContext) } - var ipContext = request.GetConnection().GetContext().GetIpContext() + var dnsContext = request.GetConnection().GetContext().GetDnsContext() + var clientsConfigs = dnsContext.GetConfigs() - for _, dstIPNet := range ipContext.GetDstIPNets() { - request.GetConnection().GetContext().GetDnsContext().Configs = append(request.GetConnection().GetContext().GetDnsContext().Configs, &networkservice.DNSConfig{ - DnsServerIps: []string{dstIPNet.IP.String()}, - }) - } + dnsContext.Configs = append(dnsContext.Configs, &networkservice.DNSConfig{ + DnsServerIps: []string{n.getDNSServerIP().String()}, + }) var recordNames, err = n.buildSrcDNSRecords(request.GetConnection()) @@ -121,21 +121,29 @@ func (n *vl3DNSServer) Request(ctx context.Context, request *networkservice.Netw metadata.Map(ctx, false).Store(clientDNSNameKey{}, recordNames) } - if n.shouldAddToFanoutList(ipContext) { - for _, srcIPNet := range ipContext.GetSrcIPNets() { - var u = url.URL{Scheme: "tcp", Host: fmt.Sprintf("%v:%v", srcIPNet.IP.String(), n.dnsPort)} - n.fanoutAddresses.Store(u, struct{}{}) + resp, err := next.Server(ctx).Request(ctx, request) + + if err == nil { + if srcRoutes := resp.GetContext().GetIpContext().GetSrcIPRoutes(); len(srcRoutes) > 0 { + var lastPrefix = srcRoutes[len(srcRoutes)-1].Prefix + for _, config := range clientsConfigs { + for _, serverIP := range config.DnsServerIps { + if serverIP == n.getDNSServerIP().String() { + continue + } + if withinPrefix(serverIP, lastPrefix) { + n.configs.Store(resp.GetId(), config) + } + } + } } } - return next.Server(ctx).Request(ctx, request) + return resp, err } func (n *vl3DNSServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { - for _, srcIPNet := range conn.Context.GetIpContext().GetSrcIPNets() { - var u = url.URL{Scheme: "tcp", Host: fmt.Sprintf("%v:%v", srcIPNet.IP.String(), n.dnsPort)} - n.fanoutAddresses.Delete(u) - } + n.configs.Delete(conn.GetId()) if v, ok := metadata.Map(ctx, false).LoadAndDelete(clientDNSNameKey{}); ok { var names = v.([]string) @@ -160,31 +168,16 @@ func (n *vl3DNSServer) buildSrcDNSRecords(c *networkservice.Connection) ([]strin } func (n *vl3DNSServer) getFanoutAddresses() []url.URL { - var result = n.initialFanoutList - n.fanoutAddresses.Range(func(key, _ interface{}) bool { - result = append(result, key.(url.URL)) + var result []url.URL + n.configs.Range(func(key string, value *networkservice.DNSConfig) bool { + for _, addr := range value.DnsServerIps { + result = append(result, url.URL{Scheme: "tcp", Host: fmt.Sprintf("%v:%v", addr, n.dnsPort)}) + } return true }) return result } -func (n *vl3DNSServer) shouldAddToFanoutList(ipContext *networkservice.IPContext) bool { - if len(ipContext.SrcRoutes) > 0 { - var lastSrcRoute = ipContext.SrcRoutes[len(ipContext.SrcRoutes)-1] - _, ipNet, err := net.ParseCIDR(lastSrcRoute.Prefix) - if err != nil { - return false - } - var pool = ippool.NewWithNet(ipNet) - for _, srcIP := range ipContext.GetSrcIpAddrs() { - if !pool.ContainsNetString(srcIP) { - return true - } - } - } - return false -} - func compareStringSlices(a, b []string) bool { if len(a) != len(b) { return false @@ -196,3 +189,12 @@ func compareStringSlices(a, b []string) bool { } return true } + +func withinPrefix(ipAddr, prefix string) bool { + _, ipNet, err := net.ParseCIDR(prefix) + if err != nil { + return false + } + var pool = ippool.NewWithNet(ipNet) + return pool.ContainsString(ipAddr) +} From 7ce922dc259f534e3cd87b739cdb1a16dfab79dc Mon Sep 17 00:00:00 2001 From: Nikita Skrynnik <93182827+NikitaSkrynnik@users.noreply.github.com> Date: Tue, 12 Jul 2022 22:08:37 +1100 Subject: [PATCH 10/39] Remove duplicate dns configs in response connection in DNSContextClient (#1318) * remove duplicate dns configs in response Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * delete metadata + add removeDuplicates before request Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * check intersections + add removeDuplicates test Signed-off-by: Nikita Skrynnik * add dns configs check on dnsContextServer Signed-off-by: Nikita Skrynnik * fix ci Signed-off-by: Nikita Skrynnik * fix Test_DNSContextClient_Usecases Signed-off-by: Nikita Skrynnik * rework dns configs check in dnsContextServer Signed-off-by: Nikita Skrynnik * fix Test_DNSUsecase Signed-off-by: Nikita Skrynnik Signed-off-by: anastasia.malysheva --- .../chains/nsmgr/single_test.go | 2 +- .../connectioncontext/dnscontext/client.go | 20 ++++++++-- .../connectioncontext/dnscontext/server.go | 40 ++++++++++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/pkg/networkservice/chains/nsmgr/single_test.go b/pkg/networkservice/chains/nsmgr/single_test.go index e957ab31a..667618b19 100644 --- a/pkg/networkservice/chains/nsmgr/single_test.go +++ b/pkg/networkservice/chains/nsmgr/single_test.go @@ -47,7 +47,7 @@ import ( func Test_DNSUsecase(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*7) defer cancel() domain := sandbox.NewBuilder(ctx, t). diff --git a/pkg/networkservice/connectioncontext/dnscontext/client.go b/pkg/networkservice/connectioncontext/dnscontext/client.go index 8d271ad83..e03d14122 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/client.go +++ b/pkg/networkservice/connectioncontext/dnscontext/client.go @@ -154,10 +154,14 @@ func (c *dnsContextClient) initialize() { c.storeOriginalResolvConf() - c.resolvconfDNSConfig = &networkservice.DNSConfig{ - SearchDomains: r.Value(dnscontext.AnyDomain), - DnsServerIps: r.Value(dnscontext.NameserverProperty), + nameserver := r.Value(dnscontext.NameserverProperty) + if !containsNameserver(nameserver, c.defaultNameServerIP) { + c.resolvconfDNSConfig = &networkservice.DNSConfig{ + SearchDomains: r.Value(dnscontext.AnyDomain), + DnsServerIps: nameserver, + } } + c.dnsConfigManager.Store("", c.resolvconfDNSConfig) r.SetValue(dnscontext.NameserverProperty, c.defaultNameServerIP) @@ -169,3 +173,13 @@ func (c *dnsContextClient) initialize() { c.updateCorefileQueue.AsyncExec(c.updateCorefile) } + +func containsNameserver(servers []string, value string) bool { + for i := range servers { + if servers[i] == value { + return true + } + } + + return false +} diff --git a/pkg/networkservice/connectioncontext/dnscontext/server.go b/pkg/networkservice/connectioncontext/dnscontext/server.go index b901a380c..7102fdf26 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/server.go +++ b/pkg/networkservice/connectioncontext/dnscontext/server.go @@ -1,5 +1,7 @@ // Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,10 +45,46 @@ func (d *dnsContextServer) Request(ctx context.Context, request *networkservice. if request.GetConnection().GetContext().GetDnsContext() == nil { request.GetConnection().GetContext().DnsContext = new(networkservice.DNSContext) } - request.GetConnection().GetContext().GetDnsContext().Configs = append(request.GetConnection().GetContext().GetDnsContext().Configs, d.configs...) + + for _, config := range d.configs { + if !contains(request.GetConnection().GetContext().GetDnsContext().Configs, config) { + request.GetConnection().GetContext().GetDnsContext().Configs = append(request.GetConnection().GetContext().GetDnsContext().Configs, config) + } + } return next.Server(ctx).Request(ctx, request) } func (d *dnsContextServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { return next.Server(ctx).Close(ctx, conn) } + +func contains(array []*networkservice.DNSConfig, value *networkservice.DNSConfig) bool { + for i := range array { + if equal(array[i].DnsServerIps, value.DnsServerIps) && equal(array[i].SearchDomains, value.SearchDomains) { + return true + } + } + return false +} + +func equal(a, b []string) bool { + if len(a) != len(b) { + return false + } + + diff := make(map[string]int, len(a)) + for _, v := range a { + diff[v]++ + } + + for _, v := range b { + if _, ok := diff[v]; !ok { + return false + } + diff[v]-- + if diff[v] == 0 { + delete(diff, v) + } + } + return len(diff) == 0 +} From c891357e0f50b8cfbb04425b36ed4dd5da9f7b07 Mon Sep 17 00:00:00 2001 From: Nikita Skrynnik <93182827+NikitaSkrynnik@users.noreply.github.com> Date: Wed, 13 Jul 2022 01:37:27 +1100 Subject: [PATCH 11/39] Set os.ModePerm permission for unix sockets (#1320) * set os.ModePerm for unix sockets Signed-off-by: Nikita Skrynnik * fix TestListenAndServe_NotExistsFolder Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * apply review comments Signed-off-by: Nikita Skrynnik * apply review comments Signed-off-by: Nikita Skrynnik Signed-off-by: anastasia.malysheva --- pkg/tools/grpcutils/listen_and_serve.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/tools/grpcutils/listen_and_serve.go b/pkg/tools/grpcutils/listen_and_serve.go index 375b2f118..9a1b84a76 100644 --- a/pkg/tools/grpcutils/listen_and_serve.go +++ b/pkg/tools/grpcutils/listen_and_serve.go @@ -2,6 +2,8 @@ // // Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +23,7 @@ package grpcutils import ( "context" + "fmt" "net" "net/url" "os" @@ -70,6 +73,15 @@ func ListenAndServe(ctx context.Context, address *url.URL, server *grpc.Server) *address = *AddressToURL(ln.Addr()) } + if network == unixScheme { + if _, err = os.Stat(target); err == nil { + err = os.Chmod(target, os.ModePerm) + if err != nil { + errCh <- errors.Wrap(err, fmt.Sprintf("%v: сannot change mod", target)) + } + } + } + // Serve go func() { if err != nil { From 9eb8e4ff37f915ca726a29461469413a1d8db990 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 14 Jul 2022 20:37:27 +0700 Subject: [PATCH 12/39] Add upstreamrefresh chain element (#1324) Signed-off-by: Artem Glazychev Signed-off-by: anastasia.malysheva --- .../common/upstreamrefresh/client.go | 91 +++++++++++ .../common/upstreamrefresh/client_filter.go | 97 ++++++++++++ .../common/upstreamrefresh/doc.go | 19 +++ .../common/upstreamrefresh/eventloop.go | 141 ++++++++++++++++++ .../common/upstreamrefresh/gen.go | 28 ++++ .../common/upstreamrefresh/metadata.go | 41 +++++ .../common/upstreamrefresh/notifier.go | 73 +++++++++ .../upstreamrefresh/notifier_map.gen.go | 73 +++++++++ .../common/upstreamrefresh/options.go | 31 ++++ 9 files changed, 594 insertions(+) create mode 100644 pkg/networkservice/common/upstreamrefresh/client.go create mode 100644 pkg/networkservice/common/upstreamrefresh/client_filter.go create mode 100644 pkg/networkservice/common/upstreamrefresh/doc.go create mode 100644 pkg/networkservice/common/upstreamrefresh/eventloop.go create mode 100644 pkg/networkservice/common/upstreamrefresh/gen.go create mode 100644 pkg/networkservice/common/upstreamrefresh/metadata.go create mode 100644 pkg/networkservice/common/upstreamrefresh/notifier.go create mode 100644 pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go create mode 100644 pkg/networkservice/common/upstreamrefresh/options.go diff --git a/pkg/networkservice/common/upstreamrefresh/client.go b/pkg/networkservice/common/upstreamrefresh/client.go new file mode 100644 index 000000000..37b5a24c0 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/client.go @@ -0,0 +1,91 @@ +// 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 upstreamrefresh + +import ( + "context" + + "github.com/pkg/errors" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/clientconn" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/extend" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" +) + +type upstreamRefreshClient struct { + chainCtx context.Context + localNotifier *notifier +} + +// NewClient - returns a new upstreamrefresh chain element +func NewClient(chainCtx context.Context, opts ...Option) networkservice.NetworkServiceClient { + o := &options{} + for _, opt := range opts { + opt(o) + } + + return &upstreamRefreshClient{ + chainCtx: chainCtx, + localNotifier: o.localNotifier, + } +} + +func (u *upstreamRefreshClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + closeCtxFunc := postpone.ContextWithValues(ctx) + // Cancel any existing eventLoop + if cancelEventLoop, loaded := loadAndDelete(ctx); loaded { + cancelEventLoop() + } + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + u.localNotifier.subscribe(conn.GetId()) + + cc, ccLoaded := clientconn.Load(ctx) + if ccLoaded { + cancelEventLoop, eventLoopErr := newEventLoop( + extend.WithValuesFromContext(u.chainCtx, ctx), cc, conn, u.localNotifier) + if eventLoopErr != nil { + closeCtx, closeCancel := closeCtxFunc() + defer closeCancel() + _, _ = next.Client(closeCtx).Close(closeCtx, conn) + return nil, errors.Wrap(eventLoopErr, "unable to monitor") + } + store(ctx, cancelEventLoop) + } + return conn, nil +} + +func (u *upstreamRefreshClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*emptypb.Empty, error) { + // Unsubscribe from local notifications + u.localNotifier.unsubscribe(conn.GetId()) + + // Cancel any existing eventLoop + if cancelEventLoop, loaded := loadAndDelete(ctx); loaded { + cancelEventLoop() + } + + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/networkservice/common/upstreamrefresh/client_filter.go b/pkg/networkservice/common/upstreamrefresh/client_filter.go new file mode 100644 index 000000000..582c466e5 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/client_filter.go @@ -0,0 +1,97 @@ +// 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 upstreamrefresh + +import ( + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +type clientFilter struct { + conn *networkservice.Connection + networkservice.MonitorConnection_MonitorConnectionsClient + + logger log.Logger +} + +func newClientFilter(client networkservice.MonitorConnection_MonitorConnectionsClient, conn *networkservice.Connection, logger log.Logger) networkservice.MonitorConnection_MonitorConnectionsClient { + return &clientFilter{ + MonitorConnection_MonitorConnectionsClient: client, + conn: conn, + + logger: logger, + } +} + +func (c *clientFilter) Recv() (*networkservice.ConnectionEvent, error) { + for { + eventIn, err := c.MonitorConnection_MonitorConnectionsClient.Recv() + if err != nil { + return nil, err + } + eventOut := &networkservice.ConnectionEvent{ + Type: networkservice.ConnectionEventType_UPDATE, + Connections: make(map[string]*networkservice.Connection), + } + for _, connIn := range eventIn.GetConnections() { + if eventIn.GetType() != networkservice.ConnectionEventType_UPDATE { + continue + } + + connIn = connIn.Clone() + // If we don't have enough PathSegments connIn doesn't match e.conn + if len(connIn.GetPath().GetPathSegments()) < int(c.conn.GetPath().GetIndex()+1) { + continue + } + // If the e.conn isn't in the expected PathSegment connIn doesn't match e.conn + if connIn.GetPath().GetPathSegments()[int(c.conn.GetPath().GetIndex())].GetId() != c.conn.GetId() { + continue + } + // If the current index isn't the index of e.conn or what comes after it connIn doesn't match e.conn + if !(connIn.GetPath().GetIndex() == c.conn.GetPath().GetIndex() || connIn.GetPath().GetIndex() == c.conn.GetPath().GetIndex()+1) { + continue + } + + // Construct the outgoing Connection + connOut := c.conn.Clone() + connOut.Path = connIn.Path + connOut.GetPath().Index = c.conn.GetPath().GetIndex() + connOut.Context = connIn.Context + connOut.State = connIn.State + + // If it's deleted, mark the event state down + if eventIn.GetType() == networkservice.ConnectionEventType_DELETE { + connOut.State = networkservice.State_DOWN + } + + // If the connection hasn't changed... don't send the event + if connOut.Equals(c.conn) { + continue + } + + // Add the Connection to the outgoing event + eventOut.GetConnections()[connOut.GetId()] = connOut + + // Update the event we are watching for: + c.conn = connOut + } + if len(eventOut.GetConnections()) > 0 { + return eventOut, nil + } + } +} diff --git a/pkg/networkservice/common/upstreamrefresh/doc.go b/pkg/networkservice/common/upstreamrefresh/doc.go new file mode 100644 index 000000000..1f73b6656 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/doc.go @@ -0,0 +1,19 @@ +// 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 upstreamrefresh provides a client chain element that receives monitor connectionEvents +// and processes those that have refresh_requested state +package upstreamrefresh diff --git a/pkg/networkservice/common/upstreamrefresh/eventloop.go b/pkg/networkservice/common/upstreamrefresh/eventloop.go new file mode 100644 index 000000000..b16b111e7 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/eventloop.go @@ -0,0 +1,141 @@ +// 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 upstreamrefresh + +import ( + "context" + + "github.com/pkg/errors" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/begin" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +type eventLoop struct { + eventLoopCtx context.Context + conn *networkservice.Connection + eventFactory begin.EventFactory + client networkservice.MonitorConnection_MonitorConnectionsClient + localNotifier *notifier + logger log.Logger +} + +func newEventLoop(ctx context.Context, cc grpc.ClientConnInterface, conn *networkservice.Connection, ln *notifier) (context.CancelFunc, error) { + conn = conn.Clone() + + ev := begin.FromContext(ctx) + if ev == nil { + return func() {}, nil + } + + // Create new eventLoopCtx and store its eventLoopCancel + eventLoopCtx, eventLoopCancel := context.WithCancel(ctx) + + // Create selector to only ask for events related to our Connection + selector := &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{ + { + Id: conn.GetCurrentPathSegment().GetId(), + Name: conn.GetCurrentPathSegment().GetName(), + }, + }, + } + + client, err := networkservice.NewMonitorConnectionClient(cc).MonitorConnections(eventLoopCtx, selector) + if err != nil { + eventLoopCancel() + return nil, errors.WithStack(err) + } + + // get the initial state transfer and use it to detect whether we have a real connection or not + _, err = client.Recv() + if err != nil { + eventLoopCancel() + return nil, errors.WithStack(err) + } + + logger := log.FromContext(ctx).WithField("upstreamrefresh", "eventLoop") + cev := &eventLoop{ + eventLoopCtx: eventLoopCtx, + conn: conn, + eventFactory: ev, + client: newClientFilter(client, conn, logger), + localNotifier: ln, + logger: logger, + } + + // Start the eventLoop + go cev.eventLoop() + return eventLoopCancel, nil +} + +func (cev *eventLoop) eventLoop() { + upstreamCh := cev.monitorUpstream() + var localCh <-chan struct{} + + if cev.localNotifier.get(cev.conn.GetId()) != nil { + localCh = cev.localNotifier.get(cev.conn.GetId()) + } + + select { + case _, ok := <-upstreamCh: + if !ok { + // Connection closed + return + } + cev.logger.Debug("refresh requested from upstream") + + <-cev.eventFactory.Request() + cev.localNotifier.notify(cev.eventLoopCtx, cev.conn.GetId()) + + case _, ok := <-localCh: + if !ok { + // Unsubscribed + return + } + cev.logger.Debug("refresh requested from other connection") + <-cev.eventFactory.Request() + case <-cev.eventLoopCtx.Done(): + return + } +} + +func (cev *eventLoop) monitorUpstream() <-chan struct{} { + res := make(chan struct{}, 1) + + go func() { + defer close(res) + + for { + eventIn, err := cev.client.Recv() + if cev.eventLoopCtx.Err() != nil || err != nil { + return + } + + // Handle event + if eventIn.GetConnections()[cev.conn.GetId()].GetState() == networkservice.State_REFRESH_REQUESTED { + res <- struct{}{} + return + } + } + }() + + return res +} diff --git a/pkg/networkservice/common/upstreamrefresh/gen.go b/pkg/networkservice/common/upstreamrefresh/gen.go new file mode 100644 index 000000000..722e08ed2 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/gen.go @@ -0,0 +1,28 @@ +// 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 upstreamrefresh + +import ( + "sync" +) + +type typeCh = chan struct{} + +//go:generate go-syncmap -output notifier_map.gen.go -type notifierMap + +// clientMap - sync.Map with key == string and value == chan struct{} +type notifierMap sync.Map diff --git a/pkg/networkservice/common/upstreamrefresh/metadata.go b/pkg/networkservice/common/upstreamrefresh/metadata.go new file mode 100644 index 000000000..c368f456f --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/metadata.go @@ -0,0 +1,41 @@ +// 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 upstreamrefresh + +import ( + "context" + + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +type key struct{} + +// store sets the context.CancelFunc stored in per Connection.Id metadata. +func store(ctx context.Context, cancel context.CancelFunc) { + metadata.Map(ctx, true).Store(key{}, cancel) +} + +// loadAndDelete deletes the context.CancelFunc stored in per Connection.Id metadata, +// returning the previous value if any. The loaded result reports whether the key was present. +func loadAndDelete(ctx context.Context) (value context.CancelFunc, ok bool) { + rawValue, ok := metadata.Map(ctx, true).LoadAndDelete(key{}) + if !ok { + return + } + value, ok = rawValue.(context.CancelFunc) + return value, ok +} diff --git a/pkg/networkservice/common/upstreamrefresh/notifier.go b/pkg/networkservice/common/upstreamrefresh/notifier.go new file mode 100644 index 000000000..7288e2b7d --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/notifier.go @@ -0,0 +1,73 @@ +// 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 upstreamrefresh + +import ( + "context" + + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +// notifier - notifies all subscribers of an event +type notifier struct { + channels notifierMap +} + +func newNotifier() *notifier { + return ¬ifier{} +} + +func (n *notifier) subscribe(id string) { + if n == nil { + return + } + n.unsubscribe(id) + n.channels.Store(id, make(chan struct{})) +} + +func (n *notifier) get(id string) <-chan struct{} { + if n == nil { + return nil + } + if v, ok := n.channels.Load(id); ok { + return v + } + return nil +} + +func (n *notifier) unsubscribe(id string) { + if n == nil { + return + } + if v, ok := n.channels.LoadAndDelete(id); ok { + close(v) + } +} + +func (n *notifier) notify(ctx context.Context, initiatorID string) { + if n == nil { + return + } + n.channels.Range(func(key string, value typeCh) bool { + if initiatorID == key { + return true + } + log.FromContext(ctx).WithField("upstreamrefresh", "notifier").Debug("send notification to: %v", key) + value <- struct{}{} + return true + }) +} diff --git a/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go b/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go new file mode 100644 index 000000000..a4f0e7753 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go @@ -0,0 +1,73 @@ +// Code generated by "-output notifier_map.gen.go -type notifierMap -output notifier_map.gen.go -type notifierMap"; DO NOT EDIT. +package upstreamrefresh + +import ( + "sync" // Used by sync.Map. +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert notifierMap literal (type notifierMap) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(notifierMap{}) +} + +var _nil_notifierMap_typeCh_value = func() (val typeCh) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *notifierMap) Load(key string) (typeCh, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_notifierMap_typeCh_value, ok + } + return value.(typeCh), ok +} + +// Store sets the value for a key. +func (m *notifierMap) Store(key string, value typeCh) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *notifierMap) LoadOrStore(key string, value typeCh) (typeCh, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_notifierMap_typeCh_value, loaded + } + return actual.(typeCh), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *notifierMap) LoadAndDelete(key string) (value typeCh, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_notifierMap_typeCh_value, loaded + } + return actual.(typeCh), loaded +} + +// Delete deletes the value for a key. +func (m *notifierMap) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *notifierMap) Range(f func(key string, value typeCh) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.(typeCh)) + }) +} diff --git a/pkg/networkservice/common/upstreamrefresh/options.go b/pkg/networkservice/common/upstreamrefresh/options.go new file mode 100644 index 000000000..09effd3c6 --- /dev/null +++ b/pkg/networkservice/common/upstreamrefresh/options.go @@ -0,0 +1,31 @@ +// 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 upstreamrefresh + +type options struct { + localNotifier *notifier +} + +// Option - option for upstreamrefresh chain element +type Option func(o *options) + +// WithLocalNotifications - allows all connections to receive events, if at least one of them received an event from upstream. +func WithLocalNotifications() Option { + return func(o *options) { + o.localNotifier = newNotifier() + } +} From e270f28d3893ca8cddcafd706f1c102e64c58642 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 14 Jul 2022 20:58:18 +0700 Subject: [PATCH 13/39] Add vl3mtu chain element (#1325) Signed-off-by: Artem Glazychev Signed-off-by: anastasia.malysheva --- .../common/monitor/eventloop.go | 4 +- pkg/networkservice/common/monitor/metadata.go | 19 ++- .../connectioncontext/mtu/vl3mtu/client.go | 82 ++++++++++ .../mtu/vl3mtu/client_test.go | 76 ++++++++++ .../connectioncontext/mtu/vl3mtu/doc.go | 18 +++ .../connectioncontext/mtu/vl3mtu/server.go | 103 +++++++++++++ .../mtu/vl3mtu/server_test.go | 142 ++++++++++++++++++ 7 files changed, 441 insertions(+), 3 deletions(-) create mode 100644 pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go create mode 100644 pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go create mode 100644 pkg/networkservice/connectioncontext/mtu/vl3mtu/doc.go create mode 100644 pkg/networkservice/connectioncontext/mtu/vl3mtu/server.go create mode 100644 pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go diff --git a/pkg/networkservice/common/monitor/eventloop.go b/pkg/networkservice/common/monitor/eventloop.go index 8516b3383..181ac9fe0 100644 --- a/pkg/networkservice/common/monitor/eventloop.go +++ b/pkg/networkservice/common/monitor/eventloop.go @@ -29,11 +29,11 @@ import ( type eventLoop struct { eventLoopCtx context.Context conn *networkservice.Connection - eventConsumer eventConsumer + eventConsumer EventConsumer client networkservice.MonitorConnection_MonitorConnectionsClient } -func newEventLoop(ctx context.Context, ec eventConsumer, cc grpc.ClientConnInterface, conn *networkservice.Connection) (context.CancelFunc, error) { +func newEventLoop(ctx context.Context, ec EventConsumer, cc grpc.ClientConnInterface, conn *networkservice.Connection) (context.CancelFunc, error) { conn = conn.Clone() // Is another chain element asking for events? If not, no need to monitor if ec == nil { diff --git a/pkg/networkservice/common/monitor/metadata.go b/pkg/networkservice/common/monitor/metadata.go index 3b1ee0ed1..6b1001fe1 100644 --- a/pkg/networkservice/common/monitor/metadata.go +++ b/pkg/networkservice/common/monitor/metadata.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -23,6 +23,7 @@ import ( ) type key struct{} +type keyEventConsumer struct{} // store sets the context.CancelFunc stored in per Connection.Id metadata. func store(ctx context.Context, isClient bool, cancel context.CancelFunc) { @@ -39,3 +40,19 @@ func loadAndDelete(ctx context.Context, isClient bool) (value context.CancelFunc value, ok = rawValue.(context.CancelFunc) return value, ok } + +// storeEventConsumer sets the eventConsumer stored in per Connection.Id metadata. +func storeEventConsumer(ctx context.Context, isClient bool, eventConsumer EventConsumer) { + metadata.Map(ctx, isClient).Store(keyEventConsumer{}, eventConsumer) +} + +// LoadEventConsumer loads EventConsumer stored in per Connection.Id metadata. +// The loaded result reports whether the key was present. +func LoadEventConsumer(ctx context.Context, isClient bool) (value EventConsumer, ok bool) { + rawValue, ok := metadata.Map(ctx, isClient).Load(keyEventConsumer{}) + if !ok { + return + } + value, ok = rawValue.(EventConsumer) + return value, ok +} diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go new file mode 100644 index 000000000..3d4b0eb25 --- /dev/null +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go @@ -0,0 +1,82 @@ +// 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 vl3mtu + +import ( + "context" + "sync" + "sync/atomic" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type vl3MtuClient struct { + minMtu uint32 + m sync.Mutex +} + +// NewClient - returns a new vl3mtu client chain element. +// It stores a minimum mtu of the vl3 mtu and updates connection context if required +func NewClient() networkservice.NetworkServiceClient { + return &vl3MtuClient{ + minMtu: jumboFrameSize, + } +} + +func (v *vl3MtuClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + c := request.GetConnection() + if c.GetContext() == nil { + c.Context = &networkservice.ConnectionContext{} + } + + // Check MTU of the connection + minMTU := atomic.LoadUint32(&v.minMtu) + if minMTU < c.GetContext().GetMTU() || c.GetContext().GetMTU() == 0 { + c.GetContext().MTU = minMTU + } + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + // Update MTU of the vl3 + v.updateMinMTU(conn) + + return conn, nil +} + +func (v *vl3MtuClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*emptypb.Empty, error) { + return next.Client(ctx).Close(ctx, conn, opts...) +} + +func (v *vl3MtuClient) updateMinMTU(conn *networkservice.Connection) { + if atomic.LoadUint32(&v.minMtu) <= conn.GetContext().GetMTU() { + return + } + + v.m.Lock() + defer v.m.Unlock() + if atomic.LoadUint32(&v.minMtu) <= conn.GetContext().GetMTU() { + return + } + atomic.StoreUint32(&v.minMtu, conn.GetContext().GetMTU()) +} diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go new file mode 100644 index 000000000..28e98a5b2 --- /dev/null +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go @@ -0,0 +1,76 @@ +// 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 vl3mtu_test + +import ( + "context" + "testing" + "time" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/mtu/vl3mtu" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +func Test_vl3MtuClient(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + client := next.NewNetworkServiceClient( + vl3mtu.NewClient(), + ) + + // Send the first Request + resp1, err := client.Request(ctx, &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: "1", + Context: &networkservice.ConnectionContext{MTU: 2000}, + }, + }) + require.NoError(t, err) + require.Equal(t, uint32(2000), resp1.GetContext().GetMTU()) + + // Send request without MTU + resp2, err := client.Request(ctx, &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: "2", + }, + }) + require.NoError(t, err) + require.Equal(t, uint32(2000), resp2.GetContext().GetMTU()) + + // Send request with lower MTU + resp3, err := client.Request(ctx, &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: "3", + Context: &networkservice.ConnectionContext{MTU: 1500}, + }, + }) + require.NoError(t, err) + require.Equal(t, uint32(1500), resp3.GetContext().GetMTU()) + + // Refresh the first connection + resp1, err = client.Request(ctx, &networkservice.NetworkServiceRequest{Connection: resp1}) + + require.NoError(t, err) + require.Equal(t, uint32(1500), resp1.GetContext().GetMTU()) +} diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/doc.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/doc.go new file mode 100644 index 000000000..811b8a417 --- /dev/null +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/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 vl3mtu provides networkservice.NetworkService chain elements to store minimum value of vl3 MTU. +package vl3mtu diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server.go new file mode 100644 index 000000000..cae9ebeaa --- /dev/null +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server.go @@ -0,0 +1,103 @@ +// 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 vl3mtu + +import ( + "context" + + "github.com/edwarnicke/serialize" + "github.com/golang/protobuf/ptypes/empty" + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +const ( + jumboFrameSize = 9000 +) + +type vl3MtuServer struct { + connections map[string]*networkservice.Connection + executor serialize.Executor + minMtu uint32 +} + +// NewServer - returns a new vl3mtu server chain element. +// It stores a minimum mtu of the vl3 and sends connectionEvent if refresh required +func NewServer() networkservice.NetworkServiceServer { + return &vl3MtuServer{ + minMtu: jumboFrameSize, + connections: make(map[string]*networkservice.Connection), + } +} + +func (v *vl3MtuServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { + // Check MTU of the connection + if request.GetConnection().GetContext() == nil { + request.GetConnection().Context = &networkservice.ConnectionContext{} + } + <-v.executor.AsyncExec(func() { + if request.GetConnection().GetContext().MTU > v.minMtu || request.GetConnection().GetContext().MTU == 0 { + request.GetConnection().GetContext().MTU = v.minMtu + } + }) + + conn, err := next.Server(ctx).Request(ctx, request) + if err != nil { + return conn, err + } + + v.executor.AsyncExec(func() { + // We need to update minimum mtu of the vl3 network and send notifications to the already connected clients. + logger := log.FromContext(ctx).WithField("vl3MtuServer", "Request") + if conn.GetContext().MTU < v.minMtu { + v.minMtu = conn.GetContext().MTU + logger.Debug("MTU was updated") + + connections := make(map[string]*networkservice.Connection) + for _, c := range v.connections { + if c.GetId() == conn.GetId() { + continue + } + connections[c.GetId()] = c.Clone() + connections[c.GetId()].GetContext().MTU = v.minMtu + connections[c.GetId()].State = networkservice.State_REFRESH_REQUESTED + } + if eventConsumer, ok := monitor.LoadEventConsumer(ctx, metadata.IsClient(v)); ok { + _ = eventConsumer.Send(&networkservice.ConnectionEvent{ + Type: networkservice.ConnectionEventType_UPDATE, + Connections: connections, + }) + } else { + logger.Debug("eventConsumer is not presented") + } + } + v.connections[conn.GetId()] = conn + }) + + return conn, err +} + +func (v *vl3MtuServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { + v.executor.AsyncExec(func() { + delete(v.connections, conn.GetId()) + }) + return next.Server(ctx).Close(ctx, conn) +} diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go new file mode 100644 index 000000000..aad0a9af7 --- /dev/null +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go @@ -0,0 +1,142 @@ +// 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 vl3mtu_test + +import ( + "context" + + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor" + "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/mtu/vl3mtu" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +func Test_vl3MtuServer(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + // Specify pathSegments to test + segmentNames := []string{"local-nsm", "remote-nsm"} + + // Create monitorServer + var monitorServer networkservice.MonitorConnectionServer + server := chain.NewNetworkServiceServer( + metadata.NewServer(), + monitor.NewServer(ctx, &monitorServer), + vl3mtu.NewServer(), + ) + monitorClient := adapters.NewMonitorServerToClient(monitorServer) + + // Create maps to hold returned connections and receivers + connections := make(map[string]*networkservice.Connection) + receivers := make(map[string]networkservice.MonitorConnection_MonitorConnectionsClient) + + // Get Empty initial state transfers + for _, segmentName := range segmentNames { + monitorCtx, cancelMonitor := context.WithCancel(ctx) + defer cancelMonitor() + + var monitorErr error + receivers[segmentName], monitorErr = monitorClient.MonitorConnections(monitorCtx, &networkservice.MonitorScopeSelector{ + PathSegments: []*networkservice.PathSegment{{Name: segmentName}}, + }) + require.NoError(t, monitorErr) + + event, err := receivers[segmentName].Recv() + require.NoError(t, err) + + require.NotNil(t, event) + require.Equal(t, networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER, event.GetType()) + require.Empty(t, event.GetConnections()[segmentName].GetPath().GetPathSegments()) + } + + // Send requests + var err error + connections[segmentNames[0]], err = server.Request(ctx, &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: segmentNames[0], + Path: &networkservice.Path{ + Index: 0, + PathSegments: []*networkservice.PathSegment{{Name: segmentNames[0]}}, + }, + }, + }) + require.NoError(t, err) + + // Send requests with different mtu + connections[segmentNames[1]], err = server.Request(ctx, &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: segmentNames[1], + Path: &networkservice.Path{ + Index: 1, + PathSegments: []*networkservice.PathSegment{{Name: segmentNames[1]}}, + }, + Context: &networkservice.ConnectionContext{MTU: 1500}, + }, + }) + require.NoError(t, err) + + // Get Updates and insure we've properly filtered by segmentName + for _, segmentName := range segmentNames { + var event *networkservice.ConnectionEvent + event, err = receivers[segmentName].Recv() + require.NoError(t, err) + + require.NotNil(t, event) + require.Equal(t, networkservice.ConnectionEventType_UPDATE, event.GetType()) + require.Len(t, event.GetConnections()[segmentName].GetPath().GetPathSegments(), 1) + require.Equal(t, segmentName, event.GetConnections()[segmentName].GetPath().GetPathSegments()[0].GetName()) + } + + // The first client should receive REFRESH_REQUESTED state, because MTU was updated + event, err := receivers[segmentNames[0]].Recv() + require.NoError(t, err) + + require.NotNil(t, event) + require.Equal(t, networkservice.ConnectionEventType_UPDATE, event.GetType()) + require.Equal(t, networkservice.State_REFRESH_REQUESTED, event.GetConnections()[segmentNames[0]].State) + require.Len(t, event.GetConnections()[segmentNames[0]].GetPath().GetPathSegments(), 1) + require.Equal(t, segmentNames[0], event.GetConnections()[segmentNames[0]].GetPath().GetPathSegments()[0].GetName()) + + // Close Connections + for _, conn := range connections { + _, err := server.Close(ctx, conn) + require.NoError(t, err) + } + + // Get deleteMonitorClientCC Events and insure we've properly filtered by segmentName + for _, segmentName := range segmentNames { + event, err := receivers[segmentName].Recv() + require.NoError(t, err) + + require.NotNil(t, event) + require.Equal(t, networkservice.ConnectionEventType_DELETE, event.GetType()) + require.Len(t, event.GetConnections()[segmentName].GetPath().GetPathSegments(), 1) + require.Equal(t, segmentName, event.GetConnections()[segmentName].GetPath().GetPathSegments()[0].GetName()) + } +} From 5eb7da1bc22fadba25f14f77fc66d2c900ecaa1c Mon Sep 17 00:00:00 2001 From: Denis Tingaikin <49399980+denis-tingaikin@users.noreply.github.com> Date: Thu, 14 Jul 2022 18:23:44 +0300 Subject: [PATCH 14/39] add cluster-info chain elements (#1326) Signed-off-by: Denis Tingaikin Signed-off-by: anastasia.malysheva --- .../chains/nsmgrproxy/server.go | 4 ++ .../common/clusterinfo/options.go | 27 +++++++ .../common/clusterinfo/server.go | 66 +++++++++++++++++ .../common/clusterinfo/server_test.go | 46 ++++++++++++ pkg/registry/common/clusterinfo/nse_server.go | 70 +++++++++++++++++++ .../common/clusterinfo/nse_server_test.go | 49 +++++++++++++ pkg/registry/common/clusterinfo/options.go | 27 +++++++ 7 files changed, 289 insertions(+) create mode 100644 pkg/networkservice/common/clusterinfo/options.go create mode 100644 pkg/networkservice/common/clusterinfo/server.go create mode 100644 pkg/networkservice/common/clusterinfo/server_test.go create mode 100644 pkg/registry/common/clusterinfo/nse_server.go create mode 100644 pkg/registry/common/clusterinfo/nse_server_test.go create mode 100644 pkg/registry/common/clusterinfo/options.go diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index 75c9b3369..6eb8184b8 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -33,6 +33,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgr" "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/clusterinfo" "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/discover" "github.com/networkservicemesh/sdk/pkg/networkservice/common/interdomainbypass" @@ -41,6 +42,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/common/begin" "github.com/networkservicemesh/sdk/pkg/registry/common/clientconn" "github.com/networkservicemesh/sdk/pkg/registry/common/clienturl" + registryclusterinfo "github.com/networkservicemesh/sdk/pkg/registry/common/clusterinfo" registryconnect "github.com/networkservicemesh/sdk/pkg/registry/common/connect" "github.com/networkservicemesh/sdk/pkg/registry/common/dial" registryswapip "github.com/networkservicemesh/sdk/pkg/registry/common/swapip" @@ -187,6 +189,7 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to interdomainbypass.NewServer(&interdomainBypassNSEServer, opts.listenOn), discover.NewServer(nsClient, nseClient), swapip.NewServer(opts.openMapIPChannel(ctx)), + clusterinfo.NewServer(), connect.NewServer( client.NewClient( ctx, @@ -219,6 +222,7 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to clienturl.NewNetworkServiceEndpointRegistryServer(proxyURL), interdomainBypassNSEServer, registryswapip.NewNetworkServiceEndpointRegistryServer(opts.openMapIPChannel(ctx)), + registryclusterinfo.NewNetworkServiceEndpointRegistryServer(), registryconnect.NewNetworkServiceEndpointRegistryServer( chain.NewNetworkServiceEndpointRegistryClient( clientconn.NewNetworkServiceEndpointRegistryClient(), diff --git a/pkg/networkservice/common/clusterinfo/options.go b/pkg/networkservice/common/clusterinfo/options.go new file mode 100644 index 000000000..4582bda37 --- /dev/null +++ b/pkg/networkservice/common/clusterinfo/options.go @@ -0,0 +1,27 @@ +// 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 clusterinfo + +// Option overrides default configuration +type Option = func(*clusterinfoServer) + +// WithConfigPath replaces defeault clusterinfo config file path +func WithConfigPath(p string) func(o *clusterinfoServer) { + return func(o *clusterinfoServer) { + o.configPath = p + } +} diff --git a/pkg/networkservice/common/clusterinfo/server.go b/pkg/networkservice/common/clusterinfo/server.go new file mode 100644 index 000000000..7871506c5 --- /dev/null +++ b/pkg/networkservice/common/clusterinfo/server.go @@ -0,0 +1,66 @@ +// 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 clusterinfo provides a chain element that appends clusterinfo labels into the request. +package clusterinfo + +import ( + "context" + "io/ioutil" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/networkservicemesh/api/pkg/api/networkservice" + "gopkg.in/yaml.v2" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type clusterinfoServer struct { + configPath string +} + +// NewServer - returns a new clusterinfo NetworkServiceServer that adds clusterinfo labels into request from the cluterinfo configuration. +func NewServer(opts ...Option) networkservice.NetworkServiceServer { + var r = &clusterinfoServer{ + configPath: "/etc/clusterinfo/config.yaml", + } + for _, opt := range opts { + opt(r) + } + return r +} + +func (n *clusterinfoServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { + if request.GetConnection().GetLabels() == nil { + request.GetConnection().Labels = make(map[string]string) + } + + var m = make(map[string]string) + + if b, err := ioutil.ReadFile(n.configPath); err == nil { + _ = yaml.Unmarshal(b, &m) + } + + for k, v := range m { + request.GetConnection().GetLabels()[k] = v + } + + return next.Server(ctx).Request(ctx, request) +} + +func (n *clusterinfoServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { + return next.Server(ctx).Close(ctx, conn) +} diff --git a/pkg/networkservice/common/clusterinfo/server_test.go b/pkg/networkservice/common/clusterinfo/server_test.go new file mode 100644 index 000000000..0c9e3da2e --- /dev/null +++ b/pkg/networkservice/common/clusterinfo/server_test.go @@ -0,0 +1,46 @@ +// 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 clusterinfo_test + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/clusterinfo" +) + +func TestReadClusterName(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + var path = filepath.Join(t.TempDir(), "clusterinfo.yaml") + require.NoError(t, ioutil.WriteFile(path, []byte("CLUSTER_NAME: my-cluster1"), os.ModePerm)) + + var s = clusterinfo.NewServer(clusterinfo.WithConfigPath(path)) + + var resp, err = s.Request(context.Background(), &networkservice.NetworkServiceRequest{Connection: &networkservice.Connection{}}) + require.NoError(t, err) + + require.Len(t, resp.Labels, 1) + require.Equal(t, "my-cluster1", resp.GetLabels()["CLUSTER_NAME"]) +} diff --git a/pkg/registry/common/clusterinfo/nse_server.go b/pkg/registry/common/clusterinfo/nse_server.go new file mode 100644 index 000000000..ef85e7920 --- /dev/null +++ b/pkg/registry/common/clusterinfo/nse_server.go @@ -0,0 +1,70 @@ +// 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 clusterinfo provides a chain element that appends clusterinfo labels into the request. +package clusterinfo + +import ( + "context" + "io/ioutil" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/networkservicemesh/api/pkg/api/registry" + "gopkg.in/yaml.v2" + + "github.com/networkservicemesh/sdk/pkg/registry/core/next" +) + +type clusterinfoNSEServer struct { + configPath string +} + +func (n *clusterinfoNSEServer) Register(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*registry.NetworkServiceEndpoint, error) { + var m = make(map[string]string) + + if b, err := ioutil.ReadFile(n.configPath); err == nil { + _ = yaml.Unmarshal(b, &m) + } + + for k, v := range m { + for _, labels := range nse.GetNetworkServiceLabels() { + if labels.GetLabels() == nil { + labels.Labels = make(map[string]string) + } + labels.GetLabels()[k] = v + } + } + return next.NetworkServiceEndpointRegistryServer(ctx).Register(ctx, nse) +} + +func (n *clusterinfoNSEServer) Find(query *registry.NetworkServiceEndpointQuery, server registry.NetworkServiceEndpointRegistry_FindServer) error { + return next.NetworkServiceEndpointRegistryServer(server.Context()).Find(query, server) +} + +func (n *clusterinfoNSEServer) Unregister(ctx context.Context, nse *registry.NetworkServiceEndpoint) (*empty.Empty, error) { + return next.NetworkServiceEndpointRegistryServer(ctx).Unregister(ctx, nse) +} + +// NewNetworkServiceEndpointRegistryServer - returns a new clusterinfo server that adds clusterinfo labels into nse registration +func NewNetworkServiceEndpointRegistryServer(opts ...Option) registry.NetworkServiceEndpointRegistryServer { + var r = &clusterinfoNSEServer{ + configPath: "/etc/clusterinfo/config.yaml", + } + for _, opt := range opts { + opt(r) + } + return r +} diff --git a/pkg/registry/common/clusterinfo/nse_server_test.go b/pkg/registry/common/clusterinfo/nse_server_test.go new file mode 100644 index 000000000..107094d44 --- /dev/null +++ b/pkg/registry/common/clusterinfo/nse_server_test.go @@ -0,0 +1,49 @@ +// 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 clusterinfo_test + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/networkservicemesh/api/pkg/api/registry" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/networkservicemesh/sdk/pkg/registry/common/clusterinfo" +) + +func TestReadClusterName(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + var path = filepath.Join(t.TempDir(), "clusterinfo.yaml") + require.NoError(t, ioutil.WriteFile(path, []byte("CLUSTER_NAME: my-cluster1"), os.ModePerm)) + + var s = clusterinfo.NewNetworkServiceEndpointRegistryServer(clusterinfo.WithConfigPath(path)) + + var resp, err = s.Register(context.Background(), ®istry.NetworkServiceEndpoint{NetworkServiceLabels: map[string]*registry.NetworkServiceLabels{ + "ns-1": {}, + }}) + require.NoError(t, err) + + require.Len(t, resp.GetNetworkServiceLabels(), 1) + require.Len(t, resp.GetNetworkServiceLabels()["ns-1"].GetLabels(), 1) + require.Equal(t, "my-cluster1", resp.GetNetworkServiceLabels()["ns-1"].GetLabels()["CLUSTER_NAME"]) +} diff --git a/pkg/registry/common/clusterinfo/options.go b/pkg/registry/common/clusterinfo/options.go new file mode 100644 index 000000000..7d8fcfd62 --- /dev/null +++ b/pkg/registry/common/clusterinfo/options.go @@ -0,0 +1,27 @@ +// 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 clusterinfo + +// Option overrides default configuration +type Option = func(*clusterinfoNSEServer) + +// WithConfigPath replaces defeault clusterinfo config file path +func WithConfigPath(p string) func(o *clusterinfoNSEServer) { + return func(o *clusterinfoNSEServer) { + o.configPath = p + } +} From b3d4a97cd03aba0ec652c435936c536fd60dc197 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 15 Jul 2022 16:22:00 +0700 Subject: [PATCH 15/39] small fixes after merge conflicts Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/monitor/server.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 81815e35b..b76319795 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -191,6 +191,7 @@ func getSpiffeID(ctx context.Context) (string, error) { return "", err } -type eventConsumer interface { +// EventConsumer - interface for monitor events sending +type EventConsumer interface { Send(event *networkservice.ConnectionEvent) (err error) } From 089d06e203f9104844855b3823ae8722e15a1cd3 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 15 Jul 2022 19:13:04 +0700 Subject: [PATCH 16/39] fix other tests, add test for policy Signed-off-by: anastasia.malysheva --- .../common/monitor/server_test.go | 2 +- .../mtu/vl3mtu/server_test.go | 40 ++++++++++++-- pkg/tools/monitor/next/server_test.go | 7 +-- .../opa/service_connection_policy_test.go | 54 ++++++++----------- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index 7bb64aa03..0b0a02624 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -58,7 +58,7 @@ aMp+T747AZGjOEfwHb9/w+7m func TestMonitorServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - // Get MonitorServer SpiffeId from peer context + // Put peer Certificate to context block, _ := pem.Decode([]byte(certPem)) x509cert, err := x509.ParseCertificate(block.Bytes) assert.Nil(t, err) diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go index aad0a9af7..1915540e8 100644 --- a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go @@ -18,12 +18,17 @@ package vl3mtu_test import ( "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" "testing" "time" "github.com/stretchr/testify/require" "go.uber.org/goleak" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" "github.com/networkservicemesh/api/pkg/api/networkservice" @@ -34,10 +39,39 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" ) + +const ( + // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" + certPem = `-----BEGIN CERTIFICATE----- +MIIBvjCCAWWgAwIBAgIQbnFakUhzr52nHoLGltZDyDAKBggqhkjOPQQDAjAdMQsw +CQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwHhcNMjAwMTAxMDEwMTAxWhcNMzAw +MTAxMDEwMTAxWjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAASlFpbASv+NIyVdFwTp22JR5gx7D6LJ01Z8Wz0S +ZiBneWRAcYUBBQY6zKwr/RQtCDxUcFfFyq4zEfUD29a5Phnoo4GGMIGDMA4GA1Ud +DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T +AQH/BAIwADAdBgNVHQ4EFgQUJJpYlJa1eNEcks+zJcwKClopSAowJQYDVR0RBB4w +HIYac3BpZmZlOi8vdGVzdC5jb20vd29ya2xvYWQwCgYIKoZIzj0EAwIDRwAwRAIg +Dk6tlURSF8ULhNbnyUxFQ33rDic2dX8jOIstV2dWErwCIDRH2yw0swTcUMQWYgHy +aMp+T747AZGjOEfwHb9/w+7m +-----END CERTIFICATE----- +` +) + func Test_vl3MtuServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + // Put peer Certificate to context + block, _ := pem.Decode([]byte(certPem)) + x509cert, err := x509.ParseCertificate(block.Bytes) + require.NoError(t, err) + authInfo := &credentials.TLSInfo{ + State: tls.ConnectionState{ + PeerCertificates: []*x509.Certificate{x509cert}, + }} + ctx, cancel := context.WithTimeout( + peer.NewContext( + context.Background(), &peer.Peer{AuthInfo: authInfo}), + time.Second, + ) defer cancel() // Specify pathSegments to test @@ -76,7 +110,7 @@ func Test_vl3MtuServer(t *testing.T) { } // Send requests - var err error + connections[segmentNames[0]], err = server.Request(ctx, &networkservice.NetworkServiceRequest{ Connection: &networkservice.Connection{ Id: segmentNames[0], diff --git a/pkg/tools/monitor/next/server_test.go b/pkg/tools/monitor/next/server_test.go index b21039641..a76c2bf26 100644 --- a/pkg/tools/monitor/next/server_test.go +++ b/pkg/tools/monitor/next/server_test.go @@ -66,10 +66,11 @@ func visitMCServer() networkservice.MonitorConnectionServer { func TestNewMonitorConnectionsServerShouldNotPanic(t *testing.T) { assert.NotPanics(t, func() { - _ = next.NewMonitorConnectionServer().MonitorConnections(nil, &testEmptyMCMCServer{}) + _ = next.NewMonitorConnectionServer().MonitorConnections( + nil, &testEmptyMCMCServer{context: context.Background()}) _ = next.NewWrappedMonitorConnectionServer(func(server networkservice.MonitorConnectionServer) networkservice.MonitorConnectionServer { return server - }).MonitorConnections(nil, &testEmptyMCMCServer{}) + }).MonitorConnections(nil, &testEmptyMCMCServer{context: context.Background()}) }) } @@ -99,7 +100,7 @@ func TestDataRaceMonitorConnectionServer(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - _ = s.MonitorConnections(nil, &testEmptyMCMCServer{}) + _ = s.MonitorConnections(nil, &testEmptyMCMCServer{context: context.Background()}) }() } wg.Wait() diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go index 06a82785c..a316ba348 100644 --- a/pkg/tools/opa/service_connection_policy_test.go +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -18,40 +18,32 @@ package opa_test import ( "context" - // "fmt" "testing" - // "time" - // "github.com/spiffe/go-spiffe/v2/spiffeid" - // "github.com/spiffe/go-spiffe/v2/svid/x509svid" - // "github.com/spiffe/go-spiffe/v2/workloadapi" - // "github.com/stretchr/testify/require" - // "github.com/networkservicemesh/sdk/pkg/tools/opa" -) -func TestWithServiceConnectionPolicy(t *testing.T) { - _, cancel := context.WithCancel(context.Background()) + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/require" - defer cancel() + "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/opa" +) - // source, err := workloadapi.NewX509Source(ctx) - // if err != nil { - // fmt.Errorf("couldn't get source %w", err) - // } - // fmt.Printf("New Source %v", source) - // validSvid, err := source.GetX509SVID() - // if err != nil { - // fmt.Errorf("couldn't get SVID %w", err) - // } - // fmt.Printf("New SVID %v", validSvid) +func TestWithServiceConnectionPolicy(t *testing.T) { + var p = opa.WithServiceOwnConnectionPolicy() + var input = authorize.MonitorOpaInput{ + PathSegments: []*networkservice.PathSegment{ + {}, + { + Id: "conn1", + }, + }, + SpiffeIDConnectionMap: map[string][]string{ + spiffeID: {"conn1"}, + }, + ServiceSpiffeID: spiffeID, + } - // id := &spiffeid.ID{td: "", path: "some/path"} - // invalidSvid := &x509svid.SVID{ - // ID: id, - // } + ctx := context.Background() - // p := opa.WithServiceOwnConnectionPolicy() - // err := p.Check(ctx, nil) - // require.Nil(t, err) - // err = p.Check(context.Background(), invalidSvid) - // require.NotNil(t, err) + err := p.Check(ctx, input) + require.NoError(t, err) } From 0fb7cc665c79a17e7f1fb56466f0b39b307fd31c Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 15 Jul 2022 19:35:34 +0700 Subject: [PATCH 17/39] lint fixes for test Signed-off-by: anastasia.malysheva --- .../mtu/vl3mtu/server_test.go | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go index 1915540e8..40dbf991a 100644 --- a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go @@ -39,7 +39,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" ) - const ( // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" certPem = `-----BEGIN CERTIFICATE----- @@ -57,26 +56,27 @@ aMp+T747AZGjOEfwHb9/w+7m ` ) -func Test_vl3MtuServer(t *testing.T) { - t.Cleanup(func() { goleak.VerifyNone(t) }) - // Put peer Certificate to context +func getContextWithTLSCert(t *testing.T) (context.Context, context.CancelFunc) { block, _ := pem.Decode([]byte(certPem)) x509cert, err := x509.ParseCertificate(block.Bytes) require.NoError(t, err) + authInfo := &credentials.TLSInfo{ State: tls.ConnectionState{ PeerCertificates: []*x509.Certificate{x509cert}, - }} - ctx, cancel := context.WithTimeout( - peer.NewContext( - context.Background(), &peer.Peer{AuthInfo: authInfo}), - time.Second, - ) - defer cancel() + }, + } + return context.WithTimeout(peer.NewContext(context.Background(), &peer.Peer{AuthInfo: authInfo}), time.Second) +} + +func Test_vl3MtuServer(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + // Put peer Certificate to context // Specify pathSegments to test segmentNames := []string{"local-nsm", "remote-nsm"} - + ctx, cancel := getContextWithTLSCert(t) + defer cancel() // Create monitorServer var monitorServer networkservice.MonitorConnectionServer server := chain.NewNetworkServiceServer( @@ -100,7 +100,6 @@ func Test_vl3MtuServer(t *testing.T) { PathSegments: []*networkservice.PathSegment{{Name: segmentName}}, }) require.NoError(t, monitorErr) - event, err := receivers[segmentName].Recv() require.NoError(t, err) @@ -110,7 +109,7 @@ func Test_vl3MtuServer(t *testing.T) { } // Send requests - + var err error connections[segmentNames[0]], err = server.Request(ctx, &networkservice.NetworkServiceRequest{ Connection: &networkservice.Connection{ Id: segmentNames[0], From 79c8bca66cc948a80dd85b84dc4f9c9dee911002 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 18 Jul 2022 15:06:50 +0700 Subject: [PATCH 18/39] add Any option for monitor auth policy Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 25 +++++++++++---- pkg/networkservice/chains/nsmgr/server.go | 15 +++++++-- .../chains/nsmgrproxy/server.go | 31 +++++++++++++------ pkg/networkservice/common/monitor/server.go | 23 ++++++++------ .../common/monitor/server_test.go | 3 +- pkg/tools/sandbox/node.go | 2 ++ 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index d4fc340d8..37f41f538 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020-2021 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // -// 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 // @@ -41,6 +41,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/updatetoken" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" + authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -62,6 +63,7 @@ type endpoint struct { type serverOptions struct { name string authorizeServer networkservice.NetworkServiceServer + authMonitorOptions []authMonitor.Option additionalFunctionality []networkservice.NetworkServiceServer } @@ -85,6 +87,13 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } +// WithMonitorConnectionAuthorize sets authorization server chain element +func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { + return func(o *serverOptions) { + o.authMonitorOptions = opts + } +} + // WithAdditionalFunctionality sets additional NetworkServiceServer chain elements to be included in the chain func WithAdditionalFunctionality(additionalFunctionality ...networkservice.NetworkServiceServer) Option { return func(o *serverOptions) { @@ -94,15 +103,19 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { + rv := &endpoint{} opts := &serverOptions{ - name: "endpoint-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), + name: "endpoint-" + uuid.New().String(), + authorizeServer: authorize.NewServer(authorize.Any()), + authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, } for _, opt := range options { opt(opts) } - rv := &endpoint{} + for _, opt := range options { + opt(opts) + } rv.NetworkServiceServer = chain.NewNetworkServiceServer( append([]networkservice.NetworkServiceServer{ updatepath.NewServer(opts.name), @@ -111,7 +124,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opts.authorizeServer, metadata.NewServer(), timeout.NewServer(ctx), - monitor.NewServer(ctx, &rv.MonitorConnectionServer), + monitor.NewServer(ctx, &rv.MonitorConnectionServer, opts.authMonitorOptions...), trimpath.NewServer(), }, opts.additionalFunctionality...)...) diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index 0550d2c83..b4417f5ec 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -58,6 +58,7 @@ import ( registryadapter "github.com/networkservicemesh/sdk/pkg/registry/core/adapters" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" + authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -75,6 +76,7 @@ type nsmgrServer struct { type serverOptions struct { authorizeServer networkservice.NetworkServiceServer + authMonitorOptions []authMonitor.Option dialOptions []grpc.DialOption dialTimeout time.Duration regURL *url.URL @@ -118,6 +120,13 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } +// WithMonitorConnectionAuthorize sets authorization options for monitor connection chain element +func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { + return func(o *serverOptions) { + o.authMonitorOptions = opts + } +} + // WithRegistry sets URL and dial options to reach the upstream registry, if not passed memory storage will be used. func WithRegistry(regURL *url.URL) Option { return func(o *serverOptions) { @@ -146,8 +155,11 @@ var _ Nsmgr = (*nsmgrServer)(nil) // tokenGenerator - authorization token generator // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { + rv := &nsmgrServer{} + opts := &serverOptions{ authorizeServer: authorize.NewServer(authorize.Any()), + authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, name: "nsmgr-" + uuid.New().String(), forwarderServiceName: "forwarder", } @@ -155,8 +167,6 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opt(opts) } - rv := &nsmgrServer{} - var nsRegistry = memory.NewNetworkServiceRegistryServer() if opts.regURL != nil { // Use remote registry @@ -212,6 +222,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), + endpoint.WithMonitorConnectionAuthorize(opts.authMonitorOptions...), endpoint.WithAdditionalFunctionality( adapters.NewClientToServer(clientinfo.NewClient()), discoverforwarder.NewServer( diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index 6eb8184b8..c7f6eb07c 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -50,6 +50,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/fs" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" + authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -67,12 +68,13 @@ type nsmgrProxyServer struct { } type serverOptions struct { - name string - mapipFilePath string - listenOn *url.URL - authorizeServer networkservice.NetworkServiceServer - dialOptions []grpc.DialOption - dialTimeout time.Duration + name string + mapipFilePath string + listenOn *url.URL + authorizeServer networkservice.NetworkServiceServer + authMonitorOptions []authMonitor.Option + dialOptions []grpc.DialOption + dialTimeout time.Duration } func (s *serverOptions) openMapIPChannel(ctx context.Context) <-chan map[string]string { @@ -117,6 +119,13 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } +// WithMonitorConnectionAuthorize sets authorization options for monitor connection chain element +func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { + return func(o *serverOptions) { + o.authMonitorOptions = opts + } +} + // WithListenOn sets current listenOn url func WithListenOn(u *url.URL) Option { return func(o *serverOptions) { @@ -150,10 +159,11 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to rv := new(nsmgrProxyServer) opts := &serverOptions{ - name: "nsmgr-proxy-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), - listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, - mapipFilePath: "map-ip.yaml", + name: "nsmgr-proxy-" + uuid.New().String(), + authorizeServer: authorize.NewServer(authorize.Any()), + authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, + listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, + mapipFilePath: "map-ip.yaml", } for _, opt := range options { opt(opts) @@ -185,6 +195,7 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), + endpoint.WithMonitorConnectionAuthorize(opts.authMonitorOptions...), endpoint.WithAdditionalFunctionality( interdomainbypass.NewServer(&interdomainBypassNSEServer, opts.listenOn), discover.NewServer(nsClient, nseClient), diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index b76319795..6cf8f99a9 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -61,14 +61,14 @@ type monitorServer struct { // networkservice.MonitorConnectionServer that can be used either standalone or in a // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management -func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { +func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer, opts ...authMonitor.Option) networkservice.NetworkServiceServer { spiffeIDConnectionMap := authMonitor.SpiffeIDConnectionMap{} filters := make(map[string]*monitorFilter) executor := serialize.Executor{} connections := make(map[string]*networkservice.Connection) *monitorServerPtr = nextMonitor.NewMonitorConnectionServer( - authMonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap), + authMonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, opts...), newMonitorConnectionServer(chainCtx, &executor, filters, connections), ) return &monitorServer{ @@ -92,8 +92,7 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net if err != nil { return nil, err } - spiffeID, err := getSpiffeID(ctx) - if err == nil { + if spiffeID, err := getSpiffeID(ctx); err == nil { ids, _ := m.spiffeIDConnectionMap.Load(spiffeID) m.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) } @@ -181,14 +180,18 @@ func (m *monitorServer) Send(event *networkservice.ConnectionEvent) (_ error) { func getSpiffeID(ctx context.Context) (string, error) { p, ok := peer.FromContext(ctx) var cert *x509.Certificate - if ok { - cert = opa.ParseX509Cert(p.AuthInfo) + if !ok { + return "", errors.New("fail to get peer from context") } - spiffeID, err := x509svid.IDFromCert(cert) - if err == nil { - return spiffeID.String(), nil + cert = opa.ParseX509Cert(p.AuthInfo) + if cert != nil { + spiffeID, err := x509svid.IDFromCert(cert) + if err == nil { + return spiffeID.String(), nil + } + return "", errors.New("fail to get Spiffe ID from certificate") } - return "", err + return "", errors.New("fail to get certificate from peer") } // EventConsumer - interface for monitor events sending diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index 0b0a02624..c1916d66a 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -25,7 +25,6 @@ import ( "time" "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" "google.golang.org/grpc/credentials" @@ -61,7 +60,7 @@ func TestMonitorServer(t *testing.T) { // Put peer Certificate to context block, _ := pem.Decode([]byte(certPem)) x509cert, err := x509.ParseCertificate(block.Bytes) - assert.Nil(t, err) + require.NoError(t, err) authInfo := &credentials.TLSInfo{ State: tls.ConnectionState{ PeerCertificates: []*x509.Certificate{x509cert}, diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index 9af355122..a98d5ee44 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -40,6 +40,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/common/sendfd" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/log" + authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -69,6 +70,7 @@ func (n *Node) NewNSMgr( options := []nsmgr.Option{ nsmgr.WithName(name), nsmgr.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + nsmgr.WithMonitorConnectionAuthorize(authMonitor.Any()), nsmgr.WithDialOptions(dialOptions...), nsmgr.WithDialTimeout(DialTimeout), } From 62ae8a70929e7a601bde392193ab18da7eb4c730 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 18 Jul 2022 16:35:37 +0700 Subject: [PATCH 19/39] lint fixes Signed-off-by: anastasia.malysheva --- pkg/tools/monitor/next/client_test.go | 2 +- pkg/tools/monitor/next/server_test.go | 2 +- pkg/tools/monitor/next/tail_client.go | 2 +- pkg/tools/monitor/streamcontext/stream_context.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/tools/monitor/next/client_test.go b/pkg/tools/monitor/next/client_test.go index ed7efdb6d..d620406d8 100644 --- a/pkg/tools/monitor/next/client_test.go +++ b/pkg/tools/monitor/next/client_test.go @@ -103,4 +103,4 @@ func TestNSClientBranches(t *testing.T) { _, _ = s.MonitorConnections(ctx, nil) assert.Equal(t, expects[i], visitValue(ctx), fmt.Sprintf("sample index: %v", i)) } -} \ No newline at end of file +} diff --git a/pkg/tools/monitor/next/server_test.go b/pkg/tools/monitor/next/server_test.go index a76c2bf26..7afd4b52f 100644 --- a/pkg/tools/monitor/next/server_test.go +++ b/pkg/tools/monitor/next/server_test.go @@ -104,4 +104,4 @@ func TestDataRaceMonitorConnectionServer(t *testing.T) { }() } wg.Wait() -} \ No newline at end of file +} diff --git a/pkg/tools/monitor/next/tail_client.go b/pkg/tools/monitor/next/tail_client.go index d3f41caa1..60539b648 100644 --- a/pkg/tools/monitor/next/tail_client.go +++ b/pkg/tools/monitor/next/tail_client.go @@ -33,4 +33,4 @@ type tailMonitorConnectionClient struct { func (t *tailMonitorConnectionClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { return t.MonitorConnection_MonitorConnectionsClient, nil -} \ No newline at end of file +} diff --git a/pkg/tools/monitor/streamcontext/stream_context.go b/pkg/tools/monitor/streamcontext/stream_context.go index 93ffa38a0..17715440d 100644 --- a/pkg/tools/monitor/streamcontext/stream_context.go +++ b/pkg/tools/monitor/streamcontext/stream_context.go @@ -65,4 +65,4 @@ func MonitorConnectionMonitorConnectionsClient(ctx context.Context, client netwo ctx: ctx, MonitorConnection_MonitorConnectionsClient: client, } -} \ No newline at end of file +} From 77e553fa754b1bbe64767f6e4dc0b48fbdb8a3b9 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 18 Jul 2022 22:22:35 +0700 Subject: [PATCH 20/39] remove redundant monitor chains. move spiffeIdmap from MonitorServer to AuthorizeServer Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 20 +++++---- pkg/networkservice/chains/nsmgr/server.go | 32 ++++++------- .../chains/nsmgrproxy/server.go | 30 ++++++------- pkg/networkservice/common/authorize/server.go | 39 ++++++++++++++-- .../common/authorize/server_test.go | 10 +++-- pkg/networkservice/common/heal/eventloop.go | 4 +- pkg/networkservice/common/monitor/server.go | 45 ++----------------- .../core/eventchannel/monitor_client.go | 8 ++-- pkg/tools/sandbox/node.go | 7 +-- 9 files changed, 97 insertions(+), 98 deletions(-) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index 37f41f538..fb69b76c8 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -41,7 +41,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/updatetoken" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" - authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -63,7 +64,8 @@ type endpoint struct { type serverOptions struct { name string authorizeServer networkservice.NetworkServiceServer - authMonitorOptions []authMonitor.Option + authorizeMonitorServer networkservice.MonitorConnectionServer + authMonitorOptions []authmonitor.Option additionalFunctionality []networkservice.NetworkServiceServer } @@ -87,10 +89,10 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithMonitorConnectionAuthorize sets authorization server chain element -func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { +// WithAdditionalMonitorFunctionality sets authorization server chain element +func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { - o.authMonitorOptions = opts + o.authorizeMonitorServer = authorizeMonitorServer } } @@ -104,10 +106,11 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { rv := &endpoint{} + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "endpoint-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), - authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, + authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), + authMonitorOptions: []authmonitor.Option{authmonitor.Any()}, } for _, opt := range options { opt(opts) @@ -116,6 +119,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options for _, opt := range options { opt(opts) } + monitorConnectionServer := next.NewMonitorConnectionServer(opts.authorizeMonitorServer, rv.MonitorConnectionServer) rv.NetworkServiceServer = chain.NewNetworkServiceServer( append([]networkservice.NetworkServiceServer{ updatepath.NewServer(opts.name), @@ -124,7 +128,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opts.authorizeServer, metadata.NewServer(), timeout.NewServer(ctx), - monitor.NewServer(ctx, &rv.MonitorConnectionServer, opts.authMonitorOptions...), + monitor.NewServer(ctx, &monitorConnectionServer), trimpath.NewServer(), }, opts.additionalFunctionality...)...) diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index b4417f5ec..c15bd955f 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -58,8 +58,8 @@ import ( registryadapter "github.com/networkservicemesh/sdk/pkg/registry/core/adapters" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" - authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) // Nsmgr - A simple combination of the Endpoint, registry.NetworkServiceRegistryServer, and registry.NetworkServiceDiscoveryServer interfaces @@ -75,14 +75,14 @@ type nsmgrServer struct { } type serverOptions struct { - authorizeServer networkservice.NetworkServiceServer - authMonitorOptions []authMonitor.Option - dialOptions []grpc.DialOption - dialTimeout time.Duration - regURL *url.URL - name string - url string - forwarderServiceName string + authorizeServer networkservice.NetworkServiceServer + authorizeMonitorServer networkservice.MonitorConnectionServer + dialOptions []grpc.DialOption + dialTimeout time.Duration + regURL *url.URL + name string + url string + forwarderServiceName string } // Option modifies server option value @@ -120,10 +120,10 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithMonitorConnectionAuthorize sets authorization options for monitor connection chain element -func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { +// WithAdditionalMonitorFunctionality sets authorization server chain element +func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { - o.authMonitorOptions = opts + o.authorizeMonitorServer = authorizeMonitorServer } } @@ -156,10 +156,10 @@ var _ Nsmgr = (*nsmgrServer)(nil) // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { rv := &nsmgrServer{} - + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ - authorizeServer: authorize.NewServer(authorize.Any()), - authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, + authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any()), name: "nsmgr-" + uuid.New().String(), forwarderServiceName: "forwarder", } @@ -222,7 +222,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), - endpoint.WithMonitorConnectionAuthorize(opts.authMonitorOptions...), + endpoint.WithAdditionalMonitorFunctionality(opts.authorizeMonitorServer), endpoint.WithAdditionalFunctionality( adapters.NewClientToServer(clientinfo.NewClient()), discoverforwarder.NewServer( diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index c7f6eb07c..d9b4f286f 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -50,8 +50,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/fs" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" - authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) func (n *nsmgrProxyServer) Register(s *grpc.Server) { @@ -68,13 +68,13 @@ type nsmgrProxyServer struct { } type serverOptions struct { - name string - mapipFilePath string - listenOn *url.URL - authorizeServer networkservice.NetworkServiceServer - authMonitorOptions []authMonitor.Option - dialOptions []grpc.DialOption - dialTimeout time.Duration + name string + mapipFilePath string + listenOn *url.URL + authorizeServer networkservice.NetworkServiceServer + authorizeMonitorServer networkservice.MonitorConnectionServer + dialOptions []grpc.DialOption + dialTimeout time.Duration } func (s *serverOptions) openMapIPChannel(ctx context.Context) <-chan map[string]string { @@ -119,10 +119,10 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithMonitorConnectionAuthorize sets authorization options for monitor connection chain element -func WithMonitorConnectionAuthorize(opts ...authMonitor.Option) Option { +// WithAdditionalMonitorFunctionality sets authorization server chain element +func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { - o.authMonitorOptions = opts + o.authorizeMonitorServer = authorizeMonitorServer } } @@ -157,11 +157,11 @@ func WithDialTimeout(dialTimeout time.Duration) Option { // NewServer creates new proxy NSMgr func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator token.GeneratorFunc, options ...Option) nsmgr.Nsmgr { rv := new(nsmgrProxyServer) - + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "nsmgr-proxy-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), - authMonitorOptions: []authMonitor.Option{authMonitor.Any()}, + authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any()), listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, mapipFilePath: "map-ip.yaml", } @@ -195,7 +195,7 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), - endpoint.WithMonitorConnectionAuthorize(opts.authMonitorOptions...), + endpoint.WithAdditionalMonitorFunctionality(opts.authorizeMonitorServer), endpoint.WithAdditionalFunctionality( interdomainbypass.NewServer(&interdomainBypassNSEServer, opts.listenOn), discover.NewServer(nsClient, nseClient), diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index d8b568cd2..a36896dca 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -21,23 +21,29 @@ package authorize import ( "context" + "crypto/x509" "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + "github.com/spiffe/go-spiffe/v2/svid/x509svid" "google.golang.org/grpc/peer" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) type authorizeServer struct { policies policiesList + spiffeIDConnectionMap *authmonitor.SpiffeIDConnectionMap + } // NewServer - returns a new authorization networkservicemesh.NetworkServiceServers // Authorize server checks left side of Path. -func NewServer(opts ...Option) networkservice.NetworkServiceServer { +func NewServer(spiffeIDConnectionMap *authmonitor.SpiffeIDConnectionMap, opts ...Option) networkservice.NetworkServiceServer { var s = &authorizeServer{ policies: []Policy{ opa.WithTokensValidPolicy(), @@ -45,6 +51,7 @@ func NewServer(opts ...Option) networkservice.NetworkServiceServer { opa.WithTokensExpiredPolicy(), opa.WithTokenChainPolicy(), }, + spiffeIDConnectionMap: spiffeIDConnectionMap, } for _, o := range opts { o.apply(&s.policies) @@ -53,10 +60,15 @@ func NewServer(opts ...Option) networkservice.NetworkServiceServer { } func (a *authorizeServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { - var index = request.GetConnection().GetPath().GetIndex() + conn := request.GetConnection() + var index = conn.GetPath().GetIndex() var leftSide = &networkservice.Path{ Index: index, - PathSegments: request.GetConnection().GetPath().GetPathSegments()[:index+1], + PathSegments: conn.GetPath().GetPathSegments()[:index+1], + } + if spiffeID, err := getSpiffeID(ctx); err == nil { + ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) + a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { @@ -72,6 +84,10 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec Index: index, PathSegments: conn.GetPath().GetPathSegments()[:index+1], } + if spiffeID, err := getSpiffeID(ctx); err == nil { + ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) + a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { return nil, err @@ -79,3 +95,20 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec } return next.Server(ctx).Close(ctx, conn) } + +func getSpiffeID(ctx context.Context) (string, error) { + p, ok := peer.FromContext(ctx) + var cert *x509.Certificate + if !ok { + return "", errors.New("fail to get peer from context") + } + cert = opa.ParseX509Cert(p.AuthInfo) + if cert != nil { + spiffeID, err := x509svid.IDFromCert(cert) + if err == nil { + return spiffeID.String(), nil + } + return "", errors.New("fail to get Spiffe ID from certificate") + } + return "", errors.New("fail to get certificate from peer") +} \ No newline at end of file diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index f4bb6f9a0..09c184c39 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.go @@ -30,6 +30,7 @@ import ( "google.golang.org/grpc/status" "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) func testPolicy() authorize.Policy { @@ -73,11 +74,12 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { } // simulate heal request - conn, err := authorize.NewServer().Request(context.Background(), r) + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} + conn, err := authorize.NewServer(&spiffeIDConnectionMap).Request(context.Background(), r) require.NoError(t, err) // simulate timeout close - _, err = authorize.NewServer().Close(context.Background(), conn) + _, err = authorize.NewServer(&spiffeIDConnectionMap).Close(context.Background(), conn) require.NoError(t, err) } @@ -103,11 +105,11 @@ func TestAuthzEndpoint(t *testing.T) { denied: true, }, } - + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} for i := range suits { s := suits[i] t.Run(s.name, func(t *testing.T) { - srv := authorize.NewServer(authorize.WithPolicies(s.policy)) + srv := authorize.NewServer(&spiffeIDConnectionMap, authorize.WithPolicies(s.policy)) checkResult := func(err error) { if !s.denied { require.Nil(t, err, "request expected to be not denied: ") diff --git a/pkg/networkservice/common/heal/eventloop.go b/pkg/networkservice/common/heal/eventloop.go index 32013a937..eda3fad58 100644 --- a/pkg/networkservice/common/heal/eventloop.go +++ b/pkg/networkservice/common/heal/eventloop.go @@ -29,7 +29,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/begin" "github.com/networkservicemesh/sdk/pkg/tools/log" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type eventLoop struct { @@ -64,8 +63,7 @@ func newEventLoop(ctx context.Context, cc grpc.ClientConnInterface, conn *networ }, } - mClient := next.NewMonitorConnectionClient(networkservice.NewMonitorConnectionClient(cc)) - client, err := mClient.MonitorConnections(eventLoopCtx, selector) + client, err := networkservice.NewMonitorConnectionClient(cc).MonitorConnections(eventLoopCtx, selector) if err != nil { eventLoopCancel() return nil, errors.WithStack(err) diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 6cf8f99a9..4c35e6e7e 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -22,30 +22,21 @@ package monitor import ( "context" - "crypto/x509" - "github.com/edwarnicke/serialize" "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" - "github.com/spiffe/go-spiffe/v2/svid/x509svid" - "google.golang.org/grpc/peer" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/clientconn" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" - "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/sdk/pkg/tools/postpone" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" - authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" - nextMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorServer struct { chainCtx context.Context - spiffeIDConnectionMap *authMonitor.SpiffeIDConnectionMap filters map[string]*monitorFilter executor *serialize.Executor connections map[string]*networkservice.Connection @@ -61,20 +52,15 @@ type monitorServer struct { // networkservice.MonitorConnectionServer that can be used either standalone or in a // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management -func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer, opts ...authMonitor.Option) networkservice.NetworkServiceServer { - spiffeIDConnectionMap := authMonitor.SpiffeIDConnectionMap{} +func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { filters := make(map[string]*monitorFilter) executor := serialize.Executor{} connections := make(map[string]*networkservice.Connection) - *monitorServerPtr = nextMonitor.NewMonitorConnectionServer( - authMonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, opts...), - newMonitorConnectionServer(chainCtx, &executor, filters, connections), - ) + *monitorServerPtr = newMonitorConnectionServer(chainCtx, &executor, filters, connections) return &monitorServer{ chainCtx: chainCtx, MonitorConnectionServer: *monitorServerPtr, - spiffeIDConnectionMap: &spiffeIDConnectionMap, filters: filters, executor: &executor, connections: connections, @@ -92,10 +78,7 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net if err != nil { return nil, err } - if spiffeID, err := getSpiffeID(ctx); err == nil { - ids, _ := m.spiffeIDConnectionMap.Load(spiffeID) - m.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) - } + _ = m.Send(&networkservice.ConnectionEvent{ Type: networkservice.ConnectionEventType_UPDATE, Connections: map[string]*networkservice.Connection{conn.GetId(): conn.Clone()}, @@ -123,11 +106,6 @@ func (m *monitorServer) Close(ctx context.Context, conn *networkservice.Connecti if cancelEventLoop, loaded := loadAndDelete(ctx, metadata.IsClient(m)); loaded { cancelEventLoop() } - spiffeID, err := getSpiffeID(ctx) - if err == nil { - ids, _ := m.spiffeIDConnectionMap.Load(spiffeID) - m.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) - } rv, err := next.Server(ctx).Close(ctx, conn) _ = m.Send(&networkservice.ConnectionEvent{ @@ -177,23 +155,6 @@ func (m *monitorServer) Send(event *networkservice.ConnectionEvent) (_ error) { return nil } -func getSpiffeID(ctx context.Context) (string, error) { - p, ok := peer.FromContext(ctx) - var cert *x509.Certificate - if !ok { - return "", errors.New("fail to get peer from context") - } - cert = opa.ParseX509Cert(p.AuthInfo) - if cert != nil { - spiffeID, err := x509svid.IDFromCert(cert) - if err == nil { - return spiffeID.String(), nil - } - return "", errors.New("fail to get Spiffe ID from certificate") - } - return "", errors.New("fail to get certificate from peer") -} - // EventConsumer - interface for monitor events sending type EventConsumer interface { Send(event *networkservice.ConnectionEvent) (err error) diff --git a/pkg/networkservice/core/eventchannel/monitor_client.go b/pkg/networkservice/core/eventchannel/monitor_client.go index a5a5d7cd7..03bbdfa09 100644 --- a/pkg/networkservice/core/eventchannel/monitor_client.go +++ b/pkg/networkservice/core/eventchannel/monitor_client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Cisco and/or its affiliates. +// Copyright (c) 2020 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -28,8 +28,6 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "google.golang.org/grpc" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" - "github.com/edwarnicke/serialize" ) @@ -46,7 +44,9 @@ type monitorConnectionClient struct { // returned from calling MonitorConnections receive the event. // Note: Does not perform filtering basedon MonitorScopeSelector func NewMonitorConnectionClient(eventCh <-chan *networkservice.ConnectionEvent) networkservice.MonitorConnectionClient { - return next.NewMonitorConnectionClient(&monitorConnectionClient{eventCh: eventCh}) + return &monitorConnectionClient{ + eventCh: eventCh, + } } func (m *monitorConnectionClient) MonitorConnections(ctx context.Context, _ *networkservice.MonitorScopeSelector, _ ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index a98d5ee44..1e34022bf 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -40,7 +40,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/common/sendfd" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/log" - authMonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -66,11 +66,12 @@ func (n *Node) NewNSMgr( } dialOptions := DialOptions(WithTokenGenerator(generatorFunc)) + spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} options := []nsmgr.Option{ nsmgr.WithName(name), - nsmgr.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - nsmgr.WithMonitorConnectionAuthorize(authMonitor.Any()), + nsmgr.WithAuthorizeServer(authorize.NewServer(&spiffeIDConnectionMap, authorize.Any())), + nsmgr.WithAdditionalMonitorFunctionality(authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any())), nsmgr.WithDialOptions(dialOptions...), nsmgr.WithDialTimeout(DialTimeout), } From fcb929c54ea049fec01b226b3b3e7be43a18644e Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Tue, 19 Jul 2022 15:24:02 +0700 Subject: [PATCH 21/39] refactor to pass spiffeIdConnmap with options to the servers Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 21 +++++------ pkg/networkservice/chains/nsmgr/server.go | 33 +++++++++-------- .../chains/nsmgrproxy/server.go | 19 +++++----- pkg/networkservice/common/authorize/client.go | 17 ++++----- .../common/authorize/options.go | 30 +++++++++------- pkg/networkservice/common/authorize/server.go | 35 ++++++++++--------- .../common/authorize/server_test.go | 13 ++++--- pkg/networkservice/common/monitor/server.go | 9 +++-- pkg/tools/monitor/authorize/options.go | 28 +++++++++------ pkg/tools/monitor/authorize/server.go | 21 ++++++----- pkg/tools/monitor/authorize/server_test.go | 17 +++++---- pkg/tools/sandbox/node.go | 5 ++- .../authorize => spire}/connection_map.gen.go | 2 +- pkg/tools/{monitor/authorize => spire}/gen.go | 2 +- 14 files changed, 135 insertions(+), 117 deletions(-) rename pkg/tools/{monitor/authorize => spire}/connection_map.gen.go (99%) rename pkg/tools/{monitor/authorize => spire}/gen.go (98%) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index fb69b76c8..4053834e1 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -89,8 +89,8 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAdditionalMonitorFunctionality sets authorization server chain element -func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { +// WithAuthorizeMonitorServer sets authorization server chain element +func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } @@ -106,20 +106,17 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { rv := &endpoint{} - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ - name: "endpoint-" + uuid.New().String(), - authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), - authMonitorOptions: []authmonitor.Option{authmonitor.Any()}, + name: "endpoint-" + uuid.New().String(), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + authorizeServer: authorize.NewServer(authorize.Any()), + authMonitorOptions: []authmonitor.Option{authmonitor.Any()}, } for _, opt := range options { opt(opts) } + var mcsPtr networkservice.MonitorConnectionServer - for _, opt := range options { - opt(opts) - } - monitorConnectionServer := next.NewMonitorConnectionServer(opts.authorizeMonitorServer, rv.MonitorConnectionServer) rv.NetworkServiceServer = chain.NewNetworkServiceServer( append([]networkservice.NetworkServiceServer{ updatepath.NewServer(opts.name), @@ -128,10 +125,10 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opts.authorizeServer, metadata.NewServer(), timeout.NewServer(ctx), - monitor.NewServer(ctx, &monitorConnectionServer), + monitor.NewServer(ctx, &mcsPtr), trimpath.NewServer(), }, opts.additionalFunctionality...)...) - + rv.MonitorConnectionServer = next.NewMonitorConnectionServer(opts.authorizeMonitorServer, mcsPtr) return rv } diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index c15bd955f..697c2c779 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -58,8 +58,8 @@ import ( registryadapter "github.com/networkservicemesh/sdk/pkg/registry/core/adapters" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) // Nsmgr - A simple combination of the Endpoint, registry.NetworkServiceRegistryServer, and registry.NetworkServiceDiscoveryServer interfaces @@ -75,14 +75,14 @@ type nsmgrServer struct { } type serverOptions struct { - authorizeServer networkservice.NetworkServiceServer - authorizeMonitorServer networkservice.MonitorConnectionServer - dialOptions []grpc.DialOption - dialTimeout time.Duration - regURL *url.URL - name string - url string - forwarderServiceName string + authorizeServer networkservice.NetworkServiceServer + authorizeMonitorServer networkservice.MonitorConnectionServer + dialOptions []grpc.DialOption + dialTimeout time.Duration + regURL *url.URL + name string + url string + forwarderServiceName string } // Option modifies server option value @@ -120,8 +120,8 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAdditionalMonitorFunctionality sets authorization server chain element -func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { +// WithAuthorizeMonitorServer sets authorization server chain element +func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } @@ -156,12 +156,11 @@ var _ Nsmgr = (*nsmgrServer)(nil) // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { rv := &nsmgrServer{} - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ - authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any()), - name: "nsmgr-" + uuid.New().String(), - forwarderServiceName: "forwarder", + authorizeServer: authorize.NewServer(authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + name: "nsmgr-" + uuid.New().String(), + forwarderServiceName: "forwarder", } for _, opt := range options { opt(opts) @@ -222,7 +221,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), - endpoint.WithAdditionalMonitorFunctionality(opts.authorizeMonitorServer), + endpoint.WithAuthorizeMonitorServer(opts.authorizeMonitorServer), endpoint.WithAdditionalFunctionality( adapters.NewClientToServer(clientinfo.NewClient()), discoverforwarder.NewServer( diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index d9b4f286f..66d5d9139 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -50,8 +50,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/fs" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" - "github.com/networkservicemesh/sdk/pkg/tools/token" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/token" ) func (n *nsmgrProxyServer) Register(s *grpc.Server) { @@ -119,8 +119,8 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAdditionalMonitorFunctionality sets authorization server chain element -func WithAdditionalMonitorFunctionality(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { +// WithAuthorizeMonitorServer sets authorization server chain element +func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } @@ -157,13 +157,12 @@ func WithDialTimeout(dialTimeout time.Duration) Option { // NewServer creates new proxy NSMgr func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator token.GeneratorFunc, options ...Option) nsmgr.Nsmgr { rv := new(nsmgrProxyServer) - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} opts := &serverOptions{ - name: "nsmgr-proxy-" + uuid.New().String(), - authorizeServer: authorize.NewServer(&spiffeIDConnectionMap, authorize.Any()), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any()), - listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, - mapipFilePath: "map-ip.yaml", + name: "nsmgr-proxy-" + uuid.New().String(), + authorizeServer: authorize.NewServer(authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, + mapipFilePath: "map-ip.yaml", } for _, opt := range options { opt(opts) @@ -195,7 +194,7 @@ func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator to rv.Endpoint = endpoint.NewServer(ctx, tokenGenerator, endpoint.WithName(opts.name), endpoint.WithAuthorizeServer(opts.authorizeServer), - endpoint.WithAdditionalMonitorFunctionality(opts.authorizeMonitorServer), + endpoint.WithAuthorizeMonitorServer(opts.authorizeMonitorServer), endpoint.WithAdditionalFunctionality( interdomainbypass.NewServer(&interdomainBypassNSEServer, opts.listenOn), discover.NewServer(nsClient, nseClient), diff --git a/pkg/networkservice/common/authorize/client.go b/pkg/networkservice/common/authorize/client.go index 146e15b89..3a33fa00f 100644 --- a/pkg/networkservice/common/authorize/client.go +++ b/pkg/networkservice/common/authorize/client.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. // -// Copyright (c) 2020-2021 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -42,19 +42,20 @@ type authorizeClient struct { // NewClient - returns a new authorization networkservicemesh.NetworkServiceClient // Authorize client checks rigiht side of path. func NewClient(opts ...Option) networkservice.NetworkServiceClient { - var result = &authorizeClient{ - policies: []Policy{ + o := &options{ + policies: policiesList{ opa.WithTokensValidPolicy(), opa.WithNextTokenSignedPolicy(), opa.WithTokensExpiredPolicy(), opa.WithTokenChainPolicy(), }, } - - for _, o := range opts { - o.apply(&result.policies) + for _, opt := range opts { + opt(o) + } + var result = &authorizeClient{ + policies: o.policies, } - return result } diff --git a/pkg/networkservice/common/authorize/options.go b/pkg/networkservice/common/authorize/options.go index 2e2d3e834..9bb2bb0f1 100644 --- a/pkg/networkservice/common/authorize/options.go +++ b/pkg/networkservice/common/authorize/options.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. // -// Copyright (c) 2020-2021 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -18,11 +18,16 @@ package authorize -// Option is authorization option for server -type Option interface { - apply(*policiesList) +import "github.com/networkservicemesh/sdk/pkg/tools/spire" + +type options struct { + policies policiesList + spiffeIDConnectionMap *spire.SpiffeIDConnectionMap } +// Option is authorization option for network service server +type Option func(*options) + // Any authorizes any call of request/close func Any() Option { return WithPolicies(nil) @@ -30,13 +35,14 @@ func Any() Option { // WithPolicies sets custom policies func WithPolicies(p ...Policy) Option { - return optionFunc(func(l *policiesList) { - *l = p - }) + return func(o *options) { + o.policies = p + } } -type optionFunc func(*policiesList) - -func (f optionFunc) apply(a *policiesList) { - f(a) +// WithSpiffeIDConnectionMap sets custom policies +func WithSpiffeIDConnectionMap(s *spire.SpiffeIDConnectionMap) Option { + return func(o *options) { + o.spiffeIDConnectionMap = s + } } diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index a36896dca..7ee483b99 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. // -// Copyright (c) 2020-2021 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -32,29 +32,32 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/spire" ) type authorizeServer struct { - policies policiesList - spiffeIDConnectionMap *authmonitor.SpiffeIDConnectionMap - + policies policiesList + spiffeIDConnectionMap *spire.SpiffeIDConnectionMap } // NewServer - returns a new authorization networkservicemesh.NetworkServiceServers // Authorize server checks left side of Path. -func NewServer(spiffeIDConnectionMap *authmonitor.SpiffeIDConnectionMap, opts ...Option) networkservice.NetworkServiceServer { - var s = &authorizeServer{ - policies: []Policy{ +func NewServer(opts ...Option) networkservice.NetworkServiceServer { + o := &options{ + policies: policiesList{ opa.WithTokensValidPolicy(), opa.WithPrevTokenSignedPolicy(), opa.WithTokensExpiredPolicy(), opa.WithTokenChainPolicy(), }, - spiffeIDConnectionMap: spiffeIDConnectionMap, + spiffeIDConnectionMap: &spire.SpiffeIDConnectionMap{}, + } + for _, opt := range opts { + opt(o) } - for _, o := range opts { - o.apply(&s.policies) + var s = &authorizeServer{ + policies: o.policies, + spiffeIDConnectionMap: o.spiffeIDConnectionMap, } return s } @@ -66,15 +69,15 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N Index: index, PathSegments: conn.GetPath().GetPathSegments()[:index+1], } - if spiffeID, err := getSpiffeID(ctx); err == nil { - ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) - a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) - } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { return nil, err } } + if spiffeID, err := getSpiffeID(ctx); err == nil { + ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) + a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + } return next.Server(ctx).Request(ctx, request) } diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index 09c184c39..98e4b3686 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.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 // @@ -21,6 +21,7 @@ import ( "testing" "github.com/networkservicemesh/sdk/pkg/tools/opa" + "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" @@ -30,7 +31,6 @@ import ( "google.golang.org/grpc/status" "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" ) func testPolicy() authorize.Policy { @@ -74,12 +74,11 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { } // simulate heal request - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} - conn, err := authorize.NewServer(&spiffeIDConnectionMap).Request(context.Background(), r) + conn, err := authorize.NewServer().Request(context.Background(), r) require.NoError(t, err) // simulate timeout close - _, err = authorize.NewServer(&spiffeIDConnectionMap).Close(context.Background(), conn) + _, err = authorize.NewServer().Close(context.Background(), conn) require.NoError(t, err) } @@ -105,11 +104,11 @@ func TestAuthzEndpoint(t *testing.T) { denied: true, }, } - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} + spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} for i := range suits { s := suits[i] t.Run(s.name, func(t *testing.T) { - srv := authorize.NewServer(&spiffeIDConnectionMap, authorize.WithPolicies(s.policy)) + srv := authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap), authorize.WithPolicies(s.policy)) checkResult := func(err error) { if !s.denied { require.Nil(t, err, "request expected to be not denied: ") diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 4c35e6e7e..d81e3bf40 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -32,14 +32,13 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" - ) type monitorServer struct { - chainCtx context.Context - filters map[string]*monitorFilter - executor *serialize.Executor - connections map[string]*networkservice.Connection + chainCtx context.Context + filters map[string]*monitorFilter + executor *serialize.Executor + connections map[string]*networkservice.Connection networkservice.MonitorConnectionServer } diff --git a/pkg/tools/monitor/authorize/options.go b/pkg/tools/monitor/authorize/options.go index f421535d2..931cfdb0e 100644 --- a/pkg/tools/monitor/authorize/options.go +++ b/pkg/tools/monitor/authorize/options.go @@ -1,5 +1,7 @@ // Copyright (c) 2022 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco Systems, Inc. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,11 +18,16 @@ package authorize -// Option is authorization option for server -type Option interface { - apply(*policiesList) +import "github.com/networkservicemesh/sdk/pkg/tools/spire" + +type options struct { + policies policiesList + spiffeIDConnectionMap *spire.SpiffeIDConnectionMap } +// Option is authorization option for monitor connection server +type Option func(*options) + // Any authorizes any call of request/close func Any() Option { return WithPolicies(nil) @@ -28,13 +35,14 @@ func Any() Option { // WithPolicies sets custom policies func WithPolicies(p ...Policy) Option { - return optionFunc(func(l *policiesList) { - *l = p - }) + return func(o *options) { + o.policies = p + } } -type optionFunc func(*policiesList) - -func (f optionFunc) apply(a *policiesList) { - f(a) +// WithSpiffeIDConnectionMap sets custom policies +func WithSpiffeIDConnectionMap(s *spire.SpiffeIDConnectionMap) Option { + return func(o *options) { + o.spiffeIDConnectionMap = s + } } diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index 7eb967eb9..d40b172d9 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -27,23 +27,26 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" + "github.com/networkservicemesh/sdk/pkg/tools/spire" ) type authorizeMonitorConnectionsServer struct { policies policiesList - spiffeIDConnectionMap *SpiffeIDConnectionMap + spiffeIDConnectionMap *spire.SpiffeIDConnectionMap } // NewMonitorConnectionServer - returns a new authorization networkservicemesh.MonitorConnectionServer -func NewMonitorConnectionServer(spiffeIDConnectionMap *SpiffeIDConnectionMap, opts ...Option) networkservice.MonitorConnectionServer { - var s = &authorizeMonitorConnectionsServer{ - policies: []Policy{ - opa.WithServiceOwnConnectionPolicy(), - }, - spiffeIDConnectionMap: spiffeIDConnectionMap, +func NewMonitorConnectionServer(opts ...Option) networkservice.MonitorConnectionServer { + o := &options{ + policies: policiesList{opa.WithServiceOwnConnectionPolicy()}, + spiffeIDConnectionMap: &spire.SpiffeIDConnectionMap{}, } - for _, o := range opts { - o.apply(&s.policies) + for _, opt := range opts { + opt(o) + } + var s = &authorizeMonitorConnectionsServer{ + policies: o.policies, + spiffeIDConnectionMap: o.spiffeIDConnectionMap, } return s } diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go index c20dd5340..d170d5ff7 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitor/authorize/server_test.go @@ -32,6 +32,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" "github.com/networkservicemesh/sdk/pkg/tools/opa" + "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/api/pkg/api/networkservice" @@ -174,14 +175,14 @@ func TestAuthzEndpoint(t *testing.T) { baseCtx, err = getContextWithTLSCert() require.NoError(t, err) } - spiffeIDConnectionMap := authorize.SpiffeIDConnectionMap{} + spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} for k, v := range s.spiffeIDConnMap { spiffeIDConnectionMap.Store(k, v) } ctx, cancel := context.WithTimeout(baseCtx, time.Second) defer cancel() srv := authorize.NewMonitorConnectionServer( - &spiffeIDConnectionMap, authorize.WithPolicies(testPolicy())) + authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap), authorize.WithPolicies(testPolicy())) checkResult := func(err error) { if !s.denied { require.Nil(t, err, "monitorConnections expected to be not denied: ") @@ -207,15 +208,19 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { ctx, cancel := context.WithTimeout(peerCtx, time.Second) defer cancel() - spiffeIDConnectionMap := authorize.SpiffeIDConnectionMap{} - spiffeIDConnectionMap.Store(spiffeID1, []string{"conn1"}) - selector := &networkservice.MonitorScopeSelector{ PathSegments: []*networkservice.PathSegment{{Id: "conn1"}}, } // simulate heal request err = authorize.NewMonitorConnectionServer( - &spiffeIDConnectionMap).MonitorConnections( + authorize.Any()).MonitorConnections( + selector, &testEmptyMCMCServer{context: ctx}) + require.NoError(t, err) + + spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} + spiffeIDConnectionMap.Store(spiffeID1, []string{"conn1"}) + err = authorize.NewMonitorConnectionServer( + authorize.Any()).MonitorConnections( selector, &testEmptyMCMCServer{context: ctx}) require.NoError(t, err) } diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index 1e34022bf..e897f70c0 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -66,12 +66,11 @@ func (n *Node) NewNSMgr( } dialOptions := DialOptions(WithTokenGenerator(generatorFunc)) - spiffeIDConnectionMap := authmonitor.SpiffeIDConnectionMap{} options := []nsmgr.Option{ nsmgr.WithName(name), - nsmgr.WithAuthorizeServer(authorize.NewServer(&spiffeIDConnectionMap, authorize.Any())), - nsmgr.WithAdditionalMonitorFunctionality(authmonitor.NewMonitorConnectionServer(&spiffeIDConnectionMap, authmonitor.Any())), + nsmgr.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + nsmgr.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), nsmgr.WithDialOptions(dialOptions...), nsmgr.WithDialTimeout(DialTimeout), } diff --git a/pkg/tools/monitor/authorize/connection_map.gen.go b/pkg/tools/spire/connection_map.gen.go similarity index 99% rename from pkg/tools/monitor/authorize/connection_map.gen.go rename to pkg/tools/spire/connection_map.gen.go index d065515f9..b6efae4ad 100644 --- a/pkg/tools/monitor/authorize/connection_map.gen.go +++ b/pkg/tools/spire/connection_map.gen.go @@ -1,7 +1,7 @@ // Code generated by "-output connection_map.gen.go -type SpiffeIDConnectionMap -output connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. // Install -output connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output connection_map.gen.go -type SpiffeIDConnectionMap" -package authorize +package spire import ( "sync" // Used by sync.Map. diff --git a/pkg/tools/monitor/authorize/gen.go b/pkg/tools/spire/gen.go similarity index 98% rename from pkg/tools/monitor/authorize/gen.go rename to pkg/tools/spire/gen.go index 1b1d3c81e..0881bcc09 100644 --- a/pkg/tools/monitor/authorize/gen.go +++ b/pkg/tools/spire/gen.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package authorize +package spire import ( "sync" From a74c692bdb537af39d3e2b7a575fed369fad2836 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Tue, 19 Jul 2022 16:20:42 +0700 Subject: [PATCH 22/39] minor fixes Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 11 ++--- pkg/networkservice/chains/nsmgr/server.go | 7 ++- .../chains/nsmgrproxy/server.go | 5 ++- .../common/authorize/options.go | 2 +- pkg/networkservice/common/authorize/server.go | 8 ++-- .../common/monitor/eventloop.go | 5 +-- pkg/networkservice/common/monitor/server.go | 2 + .../mtu/vl3mtu/server_test.go | 43 +++---------------- pkg/networkservice/core/next/client.go | 4 +- pkg/tools/monitor/authorize/options.go | 2 +- pkg/tools/monitor/authorize/server.go | 2 +- pkg/tools/monitor/authorize/server_test.go | 2 +- 12 files changed, 33 insertions(+), 60 deletions(-) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index 4053834e1..ca4e79cac 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -65,7 +65,6 @@ type serverOptions struct { name string authorizeServer networkservice.NetworkServiceServer authorizeMonitorServer networkservice.MonitorConnectionServer - authMonitorOptions []authmonitor.Option additionalFunctionality []networkservice.NetworkServiceServer } @@ -89,8 +88,11 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAuthorizeMonitorServer sets authorization server chain element +// WithAuthorizeMonitorServer sets authorization MonitorConnectionServer chain element func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { + if authorizeMonitorServer == nil { + panic("authorizeMonitorServer cannot be nil") + } return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } @@ -105,18 +107,17 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { - rv := &endpoint{} opts := &serverOptions{ name: "endpoint-" + uuid.New().String(), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), authorizeServer: authorize.NewServer(authorize.Any()), - authMonitorOptions: []authmonitor.Option{authmonitor.Any()}, + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), } for _, opt := range options { opt(opts) } var mcsPtr networkservice.MonitorConnectionServer + rv := &endpoint{} rv.NetworkServiceServer = chain.NewNetworkServiceServer( append([]networkservice.NetworkServiceServer{ updatepath.NewServer(opts.name), diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index 697c2c779..ca8577545 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -120,8 +120,11 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAuthorizeMonitorServer sets authorization server chain element +// WithAuthorizeMonitorServer sets authorization MonitorConnectionServer chain element func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { + if authorizeMonitorServer == nil { + panic("authorizeMonitorServer cannot be nil") + } return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } @@ -155,7 +158,6 @@ var _ Nsmgr = (*nsmgrServer)(nil) // tokenGenerator - authorization token generator // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { - rv := &nsmgrServer{} opts := &serverOptions{ authorizeServer: authorize.NewServer(authorize.Any()), authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), @@ -166,6 +168,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options opt(opts) } + rv := &nsmgrServer{} var nsRegistry = memory.NewNetworkServiceRegistryServer() if opts.regURL != nil { // Use remote registry diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index 66d5d9139..111466082 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -119,8 +119,11 @@ func WithAuthorizeServer(authorizeServer networkservice.NetworkServiceServer) Op } } -// WithAuthorizeMonitorServer sets authorization server chain element +// WithAuthorizeMonitorServer sets authorization MonitorConnectionServer chain element func WithAuthorizeMonitorServer(authorizeMonitorServer networkservice.MonitorConnectionServer) Option { + if authorizeMonitorServer == nil { + panic("authorizeMonitorServer cannot be nil") + } return func(o *serverOptions) { o.authorizeMonitorServer = authorizeMonitorServer } diff --git a/pkg/networkservice/common/authorize/options.go b/pkg/networkservice/common/authorize/options.go index 9bb2bb0f1..3e0fceede 100644 --- a/pkg/networkservice/common/authorize/options.go +++ b/pkg/networkservice/common/authorize/options.go @@ -40,7 +40,7 @@ func WithPolicies(p ...Policy) Option { } } -// WithSpiffeIDConnectionMap sets custom policies +// WithSpiffeIDConnectionMap sets map to keep spiffeIDConnectionMap to authorize connections with MonitorServer func WithSpiffeIDConnectionMap(s *spire.SpiffeIDConnectionMap) Option { return func(o *options) { o.spiffeIDConnectionMap = s diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index 7ee483b99..1da8f6655 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -88,9 +88,9 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec PathSegments: conn.GetPath().GetPathSegments()[:index+1], } if spiffeID, err := getSpiffeID(ctx); err == nil { - ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) - a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) - } + ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) + a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { return nil, err @@ -114,4 +114,4 @@ func getSpiffeID(ctx context.Context) (string, error) { return "", errors.New("fail to get Spiffe ID from certificate") } return "", errors.New("fail to get certificate from peer") -} \ No newline at end of file +} diff --git a/pkg/networkservice/common/monitor/eventloop.go b/pkg/networkservice/common/monitor/eventloop.go index 181ac9fe0..45f4c3e3f 100644 --- a/pkg/networkservice/common/monitor/eventloop.go +++ b/pkg/networkservice/common/monitor/eventloop.go @@ -22,8 +22,6 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/pkg/errors" "google.golang.org/grpc" - - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type eventLoop struct { @@ -53,8 +51,7 @@ func newEventLoop(ctx context.Context, ec EventConsumer, cc grpc.ClientConnInter }, } - client, err := next.NewMonitorConnectionClient( - networkservice.NewMonitorConnectionClient(cc)).MonitorConnections(eventLoopCtx, selector) + client, err := networkservice.NewMonitorConnectionClient(cc).MonitorConnections(eventLoopCtx, selector) if err != nil { eventLoopCancel() return nil, errors.WithStack(err) diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index d81e3bf40..7f5e47c8a 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -22,9 +22,11 @@ package monitor import ( "context" + "github.com/edwarnicke/serialize" "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/clientconn" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" "github.com/networkservicemesh/sdk/pkg/tools/postpone" diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go index 40dbf991a..aad0a9af7 100644 --- a/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/server_test.go @@ -18,17 +18,12 @@ package vl3mtu_test import ( "context" - "crypto/tls" - "crypto/x509" - "encoding/pem" "testing" "time" "github.com/stretchr/testify/require" "go.uber.org/goleak" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" "github.com/networkservicemesh/api/pkg/api/networkservice" @@ -39,44 +34,15 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" ) -const ( - // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" - certPem = `-----BEGIN CERTIFICATE----- -MIIBvjCCAWWgAwIBAgIQbnFakUhzr52nHoLGltZDyDAKBggqhkjOPQQDAjAdMQsw -CQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwHhcNMjAwMTAxMDEwMTAxWhcNMzAw -MTAxMDEwMTAxWjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwWTATBgcq -hkjOPQIBBggqhkjOPQMBBwNCAASlFpbASv+NIyVdFwTp22JR5gx7D6LJ01Z8Wz0S -ZiBneWRAcYUBBQY6zKwr/RQtCDxUcFfFyq4zEfUD29a5Phnoo4GGMIGDMA4GA1Ud -DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T -AQH/BAIwADAdBgNVHQ4EFgQUJJpYlJa1eNEcks+zJcwKClopSAowJQYDVR0RBB4w -HIYac3BpZmZlOi8vdGVzdC5jb20vd29ya2xvYWQwCgYIKoZIzj0EAwIDRwAwRAIg -Dk6tlURSF8ULhNbnyUxFQ33rDic2dX8jOIstV2dWErwCIDRH2yw0swTcUMQWYgHy -aMp+T747AZGjOEfwHb9/w+7m ------END CERTIFICATE----- -` -) - -func getContextWithTLSCert(t *testing.T) (context.Context, context.CancelFunc) { - block, _ := pem.Decode([]byte(certPem)) - x509cert, err := x509.ParseCertificate(block.Bytes) - require.NoError(t, err) - - authInfo := &credentials.TLSInfo{ - State: tls.ConnectionState{ - PeerCertificates: []*x509.Certificate{x509cert}, - }, - } - return context.WithTimeout(peer.NewContext(context.Background(), &peer.Peer{AuthInfo: authInfo}), time.Second) -} - func Test_vl3MtuServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - // Put peer Certificate to context + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() // Specify pathSegments to test segmentNames := []string{"local-nsm", "remote-nsm"} - ctx, cancel := getContextWithTLSCert(t) - defer cancel() + // Create monitorServer var monitorServer networkservice.MonitorConnectionServer server := chain.NewNetworkServiceServer( @@ -100,6 +66,7 @@ func Test_vl3MtuServer(t *testing.T) { PathSegments: []*networkservice.PathSegment{{Name: segmentName}}, }) require.NoError(t, monitorErr) + event, err := receivers[segmentName].Recv() require.NoError(t, err) diff --git a/pkg/networkservice/core/next/client.go b/pkg/networkservice/core/next/client.go index 6190e72c2..5e5302b99 100644 --- a/pkg/networkservice/core/next/client.go +++ b/pkg/networkservice/core/next/client.go @@ -1,6 +1,6 @@ -// Copyright (c) 2020-2022 Cisco Systems, Inc. +// Copyright (c) 2020 Cisco Systems, Inc. // -// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/authorize/options.go b/pkg/tools/monitor/authorize/options.go index 931cfdb0e..e618e7761 100644 --- a/pkg/tools/monitor/authorize/options.go +++ b/pkg/tools/monitor/authorize/options.go @@ -40,7 +40,7 @@ func WithPolicies(p ...Policy) Option { } } -// WithSpiffeIDConnectionMap sets custom policies +// WithSpiffeIDConnectionMap sets map to keep spiffeIDConnectionMap to authorize connections with MonitorServer func WithSpiffeIDConnectionMap(s *spire.SpiffeIDConnectionMap) Option { return func(o *options) { o.spiffeIDConnectionMap = s diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index d40b172d9..a7e72f2c0 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -38,7 +38,7 @@ type authorizeMonitorConnectionsServer struct { // NewMonitorConnectionServer - returns a new authorization networkservicemesh.MonitorConnectionServer func NewMonitorConnectionServer(opts ...Option) networkservice.MonitorConnectionServer { o := &options{ - policies: policiesList{opa.WithServiceOwnConnectionPolicy()}, + policies: policiesList{opa.WithServiceOwnConnectionPolicy()}, spiffeIDConnectionMap: &spire.SpiffeIDConnectionMap{}, } for _, opt := range opts { diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go index d170d5ff7..67b3f77e4 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitor/authorize/server_test.go @@ -220,7 +220,7 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} spiffeIDConnectionMap.Store(spiffeID1, []string{"conn1"}) err = authorize.NewMonitorConnectionServer( - authorize.Any()).MonitorConnections( + authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap)).MonitorConnections( selector, &testEmptyMCMCServer{context: ctx}) require.NoError(t, err) } From d44075751f2e5ba1d0d0fc2b919db824e8306c31 Mon Sep 17 00:00:00 2001 From: Nikita Skrynnik <93182827+NikitaSkrynnik@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:16:38 +1100 Subject: [PATCH 23/39] Get rid of coredns sidecar for nscs (#1313) * add logs Signed-off-by: Nikita Skrynnik * rework fanout + cleanup Signed-off-by: Nikita Skrynnik * add resolvconf chain element Signed-off-by: Nikita Skrynnik * fix sync.Map Signed-off-by: Nikita Skrynnik * search chain element implemented (probably Signed-off-by: Nikita Skrynnik * update dnsContextClient Signed-off-by: Nikita Skrynnik * add cache chain element + rework dnsconfigs chain element Signed-off-by: Nikita Skrynnik * delete dnscontext Signed-off-by: Nikita Skrynnik * add cache chain element Signed-off-by: Nikita Skrynnik * fix dnsconfigs and fanout chain elements Signed-off-by: Nikita Skrynnik * fix resolvconf chain elements Signed-off-by: Nikita Skrynnik * finish search chain element Signed-off-by: Nikita Skrynnik * minor fixes Signed-off-by: Nikita Skrynnik * fix cache unit test Signed-off-by: Nikita Skrynnik * rework wrappers Signed-off-by: Nikita Skrynnik * delete dnscontext folder Signed-off-by: Nikita Skrynnik * rework search chain element Signed-off-by: Nikita Skrynnik * add test for resolvconf Signed-off-by: Nikita Skrynnik * minor fixes Signed-off-by: Nikita Skrynnik * run go mod tidy Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * fix tests Signed-off-by: Nikita Skrynnik * delete Test_DNSUsecase Signed-off-by: Nikita Skrynnik * rework unit tests Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * use dns memory chain element for unit tests Signed-off-by: Nikita Skrynnik * fix Test_vl3NSE_ConnectsTo_vl3NSE Signed-off-by: Nikita Skrynnik * add sandbox test for dns server Signed-off-by: Nikita Skrynnik * fix dns server test Signed-off-by: Nikita Skrynnik * restore resolv_conf_tests Signed-off-by: Nikita Skrynnik * add port check Signed-off-by: Nikita Skrynnik * run all tests Signed-off-by: Nikita Skrynnik * debug dns sandbox test Signed-off-by: Nikita Skrynnik * fix dns sandbox test Signed-off-by: Nikita Skrynnik * minor fixes Signed-off-by: Nikita Skrynnik * move dns sandbox test to separate file Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * rework resolvconf chain element Signed-off-by: Nikita Skrynnik * restore question section in response Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * fix search domains fix Signed-off-by: Nikita Skrynnik * minor refactoring in search chain element Signed-off-by: Nikita Skrynnik * delete logging Signed-off-by: Nikita Skrynnik * resolve comments Signed-off-by: Nikita Skrynnik * fix ci Signed-off-by: Nikita Skrynnik * minor refactoring Signed-off-by: Nikita Skrynnik * minor fixes after rebase Signed-off-by: Nikita Skrynnik * delete resolvconfDNSHandler Signed-off-by: Nikita Skrynnik * fix Test_DNSContextClient_Usecases Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * merge all search domains only on the first dns request Signed-off-by: Nikita Skrynnik * move resolvconf parser to dnsContextClient and make it private Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * add checkmsg chain element Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * move dnsconfigs.Map to a separate folder Signed-off-by: Nikita Skrynnik * minor fixes after rebase Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik * fix Test_vl3NSE_ConnectsTo_vl3NSE Signed-off-by: Nikita Skrynnik * add logs to Test_vl3NSE_ConnectsTo_vl3NSE Signed-off-by: Nikita Skrynnik * minor fixes after rebase (again) Signed-off-by: Nikita Skrynnik * fix Test_DNSContextClient_Usecases Signed-off-by: Nikita Skrynnik * debug Test_vl3NSE_ConnectsTo_vl3NSE Signed-off-by: Nikita Skrynnik * add option with dns port for fanout + delete defaultTimeout Signed-off-by: Nikita Skrynnik * make dns cache map private Signed-off-by: Nikita Skrynnik * rename clienturlctx context functions Signed-off-by: Nikita Skrynnik * add initialization of lastTTLUpdate variable in cache chain element Signed-off-by: Nikita Skrynnik * return single value slice in ClientURLs func if we have signle clientURL in context Signed-off-by: Nikita Skrynnik * restore DNSConfigs Decoder Signed-off-by: Nikita Skrynnik * delete sync.Once from dnsconfigs handler Signed-off-by: Nikita Skrynnik * change name and description of the WithDNSPort option Signed-off-by: Nikita Skrynnik * delete debug logging Signed-off-by: Nikita Skrynnik * fix linter Signed-off-by: Nikita Skrynnik Signed-off-by: anastasia.malysheva --- go.mod | 2 +- pkg/networkservice/chains/nsmgr/dns_test.go | 145 ++++++++++++++++ .../chains/nsmgr/single_test.go | 66 -------- pkg/networkservice/chains/nsmgr/vl3_test.go | 10 +- .../connectioncontext/dnscontext/client.go | 60 ++----- .../dnscontext/client_test.go | 133 ++------------- .../connectioncontext/dnscontext/options.go | 25 +-- .../dnscontext/resolvconf.go} | 27 ++- .../dnscontext/resolvconf_test.go} | 22 +-- .../dnscontext/vl3dns/client.go | 10 +- .../dnscontext/vl3dns/options.go | 5 +- .../dnscontext/vl3dns/server.go | 28 ++-- pkg/tools/clienturlctx/context.go | 27 ++- .../config_decoder.go | 4 +- .../config_decoder_test.go | 8 +- pkg/tools/dnsconfig/gen.go | 26 +++ .../dnsconfig/sync_map.gen.go} | 24 +-- pkg/tools/dnscontext/manager.go | 94 ----------- pkg/tools/dnscontext/manager_test.go | 158 ------------------ .../doc.go => dnsutils/cache/gen.go} | 13 +- pkg/tools/dnsutils/cache/handler.go | 97 +++++++++++ pkg/tools/dnsutils/cache/handler_test.go | 79 +++++++++ .../cache/response_writer_wrapper.go} | 32 ++-- pkg/tools/dnsutils/cache/sync_map.gen.go | 75 +++++++++ pkg/tools/dnsutils/checkmsg/handler.go | 43 +++++ pkg/tools/dnsutils/checkmsg/handler_test.go | 48 ++++++ pkg/tools/dnsutils/connect/handler.go | 2 +- pkg/tools/dnsutils/dnsconfigs/handler.go | 67 ++++++++ pkg/tools/dnsutils/dnsconfigs/handler_test.go | 93 +++++++++++ .../dnsutils/fanout/{fanout.go => handler.go} | 50 +++--- pkg/tools/dnsutils/fanout/options.go | 27 +++ pkg/tools/dnsutils/memory/handler.go | 2 +- pkg/tools/dnsutils/noloop/handler.go | 4 - pkg/tools/dnsutils/searches/context.go | 43 +++++ pkg/tools/dnsutils/searches/handler.go | 76 +++++++++ pkg/tools/dnsutils/searches/handler_test.go | 87 ++++++++++ .../dnsutils/searches/response_writer.go} | 17 +- 37 files changed, 1113 insertions(+), 616 deletions(-) create mode 100644 pkg/networkservice/chains/nsmgr/dns_test.go rename pkg/{tools/dnscontext/resolv_conf.go => networkservice/connectioncontext/dnscontext/resolvconf.go} (70%) rename pkg/{tools/dnscontext/resolv_conf_test.go => networkservice/connectioncontext/dnscontext/resolvconf_test.go} (77%) rename pkg/tools/{dnscontext => dnsconfig}/config_decoder.go (94%) rename pkg/tools/{dnscontext => dnsconfig}/config_decoder_test.go (87%) create mode 100644 pkg/tools/dnsconfig/gen.go rename pkg/{networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go => tools/dnsconfig/sync_map.gen.go} (66%) delete mode 100644 pkg/tools/dnscontext/manager.go delete mode 100644 pkg/tools/dnscontext/manager_test.go rename pkg/tools/{dnscontext/doc.go => dnsutils/cache/gen.go} (64%) create mode 100644 pkg/tools/dnsutils/cache/handler.go create mode 100644 pkg/tools/dnsutils/cache/handler_test.go rename pkg/tools/{dnscontext/const.go => dnsutils/cache/response_writer_wrapper.go} (56%) create mode 100644 pkg/tools/dnsutils/cache/sync_map.gen.go create mode 100644 pkg/tools/dnsutils/checkmsg/handler.go create mode 100644 pkg/tools/dnsutils/checkmsg/handler_test.go create mode 100644 pkg/tools/dnsutils/dnsconfigs/handler.go create mode 100644 pkg/tools/dnsutils/dnsconfigs/handler_test.go rename pkg/tools/dnsutils/fanout/{fanout.go => handler.go} (72%) create mode 100644 pkg/tools/dnsutils/fanout/options.go create mode 100644 pkg/tools/dnsutils/searches/context.go create mode 100644 pkg/tools/dnsutils/searches/handler.go create mode 100644 pkg/tools/dnsutils/searches/handler_test.go rename pkg/{networkservice/connectioncontext/dnscontext/vl3dns/gen.go => tools/dnsutils/searches/response_writer.go} (73%) diff --git a/go.mod b/go.mod index 21f8a5a88..80ecc0fff 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( go.opentelemetry.io/otel/trace v1.3.0 go.uber.org/atomic v1.7.0 go.uber.org/goleak v1.1.12 + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 gonum.org/v1/gonum v0.6.2 google.golang.org/grpc v1.42.0 google.golang.org/protobuf v1.27.1 @@ -85,7 +86,6 @@ require ( go.opentelemetry.io/proto/otlp v0.11.0 // indirect golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect diff --git a/pkg/networkservice/chains/nsmgr/dns_test.go b/pkg/networkservice/chains/nsmgr/dns_test.go new file mode 100644 index 000000000..7b37f3b96 --- /dev/null +++ b/pkg/networkservice/chains/nsmgr/dns_test.go @@ -0,0 +1,145 @@ +// Copyright (c) 2020-2022 Doc.ai 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. + +//go:build !windows +// +build !windows + +package nsmgr_test + +import ( + "context" + "net" + "testing" + "time" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/cls" + kernelmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/kernel" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" + "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/dnscontext" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/cache" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/dnsconfigs" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/fanout" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/memory" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/noloop" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/norecursion" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/searches" + "github.com/networkservicemesh/sdk/pkg/tools/sandbox" +) + +func requireIPv4Lookup(ctx context.Context, t *testing.T, r *net.Resolver, host, expected string) { + addrs, err := r.LookupIP(ctx, "ip4", host) + require.NoError(t, err) + require.Len(t, addrs, 1) + require.Equal(t, expected, addrs[0].String()) +} + +func Test_DNSUsecase(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*200) + defer cancel() + + domain := sandbox.NewBuilder(ctx, t). + SetNodesCount(1). + SetNSMgrProxySupplier(nil). + SetRegistryProxySupplier(nil). + Build() + + nsRegistryClient := domain.NewNSRegistryClient(ctx, sandbox.GenerateTestToken) + + nsReg, err := nsRegistryClient.Register(ctx, defaultRegistryService(t.Name())) + require.NoError(t, err) + + nseReg := defaultRegistryEndpoint(nsReg.Name) + + nse := domain.Nodes[0].NewEndpoint(ctx, nseReg, sandbox.GenerateTestToken) + + dnsConfigsMap := new(dnsconfig.Map) + nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(dnscontext.NewClient( + dnscontext.WithChainContext(ctx), + dnscontext.WithDNSConfigsMap(dnsConfigsMap), + ))) + + dnsConfigs := []*networkservice.DNSConfig{ + { + DnsServerIps: []string{"127.0.0.1:40053"}, + SearchDomains: []string{"com"}, + }, + } + + // DNS server on nse side + dnsRecords := new(memory.Map) + dnsRecords.Store("my.domain.", []net.IP{net.ParseIP("4.4.4.4")}) + dnsRecords.Store("my.domain.com.", []net.IP{net.ParseIP("5.5.5.5")}) + dnsutils.ListenAndServe(ctx, memory.NewDNSHandler(dnsRecords), ":40053") + + // DNS server on nsc side + clientDNSHandler := next.NewDNSHandler( + dnsconfigs.NewDNSHandler(dnsConfigsMap), + searches.NewDNSHandler(), + noloop.NewDNSHandler(), + norecursion.NewDNSHandler(), + cache.NewDNSHandler(), + fanout.NewDNSHandler(), + ) + dnsutils.ListenAndServe(ctx, clientDNSHandler, ":50053") + + request := &networkservice.NetworkServiceRequest{ + MechanismPreferences: []*networkservice.Mechanism{ + {Cls: cls.LOCAL, Type: kernelmech.MECHANISM}, + }, + Connection: &networkservice.Connection{ + Id: "1", + NetworkService: nsReg.Name, + Context: &networkservice.ConnectionContext{ + DnsContext: &networkservice.DNSContext{ + Configs: dnsConfigs, + }, + }, + Labels: make(map[string]string), + }, + } + + resolver := net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + var dialer net.Dialer + return dialer.DialContext(ctx, network, "127.0.0.1:50053") + }, + } + + _, err = resolver.LookupIP(ctx, "ip4", "my.domain") + require.Error(t, err) + + conn, err := nsc.Request(ctx, request) + require.NoError(t, err) + + requireIPv4Lookup(ctx, t, &resolver, "my.domain", "4.4.4.4") + requireIPv4Lookup(ctx, t, &resolver, "my.domain.com", "5.5.5.5") + + _, err = nsc.Close(ctx, conn) + require.NoError(t, err) + + _, err = nse.Unregister(ctx, nseReg) + require.NoError(t, err) +} diff --git a/pkg/networkservice/chains/nsmgr/single_test.go b/pkg/networkservice/chains/nsmgr/single_test.go index 667618b19..a2be8fa4d 100644 --- a/pkg/networkservice/chains/nsmgr/single_test.go +++ b/pkg/networkservice/chains/nsmgr/single_test.go @@ -19,11 +19,9 @@ package nsmgr_test import ( "context" "fmt" - "io/ioutil" "net" "net/url" "os" - "path/filepath" "testing" "time" @@ -38,75 +36,11 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgr" "github.com/networkservicemesh/sdk/pkg/networkservice/common/excludedprefixes" - "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/dnscontext" "github.com/networkservicemesh/sdk/pkg/networkservice/ipam/point2pointipam" "github.com/networkservicemesh/sdk/pkg/tools/clientinfo" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" ) -func Test_DNSUsecase(t *testing.T) { - t.Cleanup(func() { goleak.VerifyNone(t) }) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*7) - defer cancel() - - domain := sandbox.NewBuilder(ctx, t). - SetNodesCount(1). - SetNSMgrProxySupplier(nil). - SetRegistryProxySupplier(nil). - Build() - - nsRegistryClient := domain.NewNSRegistryClient(ctx, sandbox.GenerateTestToken) - - nsReg, err := nsRegistryClient.Register(ctx, defaultRegistryService(t.Name())) - require.NoError(t, err) - - nseReg := defaultRegistryEndpoint(nsReg.Name) - - nse := domain.Nodes[0].NewEndpoint(ctx, nseReg, sandbox.GenerateTestToken, dnscontext.NewServer( - &networkservice.DNSConfig{ - DnsServerIps: []string{"8.8.8.8"}, - SearchDomains: []string{"my.domain1"}, - }, - &networkservice.DNSConfig{ - DnsServerIps: []string{"8.8.4.4"}, - SearchDomains: []string{"my.domain1"}, - }, - )) - - corefilePath := filepath.Join(t.TempDir(), "corefile") - resolveConfigPath := filepath.Join(t.TempDir(), "resolv.conf") - - err = ioutil.WriteFile(resolveConfigPath, []byte("nameserver 8.8.4.4\nsearch example.com\n"), os.ModePerm) - require.NoError(t, err) - - const expectedCorefile = ". {\n\tfanout . 8.8.4.4\n\tlog\n\treload\n\tcache {\n\t\tdenial 0\n\t}\n}\nmy.domain1 {\n\tfanout . 8.8.4.4 8.8.8.8\n\tlog\n\tcache {\n\t\tdenial 0\n\t}\n}" - - nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(dnscontext.NewClient( - dnscontext.WithChainContext(ctx), - dnscontext.WithCorefilePath(corefilePath), - dnscontext.WithResolveConfigPath(resolveConfigPath), - ))) - - conn, err := nsc.Request(ctx, defaultRequest(nsReg.Name)) - require.NoError(t, err) - - require.Eventually(t, func() bool { - // #nosec - b, readFileErr := ioutil.ReadFile(corefilePath) - if readFileErr != nil { - return false - } - return string(b) == expectedCorefile - }, time.Second, time.Millisecond*100) - - _, err = nsc.Close(ctx, conn) - require.NoError(t, err) - - _, err = nse.Unregister(ctx, nseReg) - require.NoError(t, err) -} - func Test_AwareNSEs(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) diff --git a/pkg/networkservice/chains/nsmgr/vl3_test.go b/pkg/networkservice/chains/nsmgr/vl3_test.go index ddfb4ed9a..8e71f2d62 100644 --- a/pkg/networkservice/chains/nsmgr/vl3_test.go +++ b/pkg/networkservice/chains/nsmgr/vl3_test.go @@ -34,6 +34,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/dnscontext/vl3dns" "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/ipcontext/vl3" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/memory" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" @@ -116,13 +117,6 @@ func Test_NSC_ConnectsTo_vl3NSE(t *testing.T) { } } -func requireIPv4Lookup(ctx context.Context, t *testing.T, r *net.Resolver, host, expected string) { - addrs, err := r.LookupIP(ctx, "ip4", host) - require.NoError(t, err) - require.Len(t, addrs, 1) - require.Equal(t, expected, addrs[0].String()) -} - func Test_vl3NSE_ConnectsTo_vl3NSE(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) @@ -154,7 +148,7 @@ func Test_vl3NSE_ConnectsTo_vl3NSE(t *testing.T) { serverPrefixCh <- &ipam.PrefixResponse{Prefix: "10.0.0.1/24"} - var dnsConfigs = new(vl3dns.Map) + var dnsConfigs = new(dnsconfig.Map) _ = domain.Nodes[0].NewEndpoint( ctx, diff --git a/pkg/networkservice/connectioncontext/dnscontext/client.go b/pkg/networkservice/connectioncontext/dnscontext/client.go index e03d14122..eee42d636 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/client.go +++ b/pkg/networkservice/connectioncontext/dnscontext/client.go @@ -22,12 +22,6 @@ import ( "context" "io/ioutil" "os" - "path" - "path/filepath" - - "github.com/edwarnicke/serialize" - - "github.com/networkservicemesh/sdk/pkg/tools/log" "github.com/golang/protobuf/ptypes/empty" "github.com/networkservicemesh/api/pkg/api/networkservice" @@ -35,7 +29,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" - "github.com/networkservicemesh/sdk/pkg/tools/dnscontext" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" + "github.com/networkservicemesh/sdk/pkg/tools/log" ) const ( @@ -44,13 +39,11 @@ const ( type dnsContextClient struct { chainContext context.Context - coreFilePath string resolveConfigPath string storedResolvConfigPath string defaultNameServerIP string - dnsConfigManager dnscontext.Manager - updateCorefileQueue serialize.Executor resolvconfDNSConfig *networkservice.DNSConfig + dnsConfigsMap *dnsconfig.Map } // NewClient creates a new DNS client chain component. Setups all DNS traffic to the localhost. Monitors DNS configs from connections. @@ -59,15 +52,14 @@ func NewClient(options ...DNSOption) networkservice.NetworkServiceClient { chainContext: context.Background(), defaultNameServerIP: "127.0.0.1", resolveConfigPath: "/etc/resolv.conf", - coreFilePath: "/etc/coredns/Corefile", } for _, o := range options { o.apply(c) } - var _, name = path.Split(c.resolveConfigPath) - c.storedResolvConfigPath = path.Join(path.Dir(c.coreFilePath), name+".restore") + c.storedResolvConfigPath = c.resolveConfigPath + ".restore" c.initialize() + return c } @@ -91,36 +83,19 @@ func (c *dnsContextClient) Request(ctx context.Context, request *networkservice. if err != nil { return nil, err } - var conifgs []*networkservice.DNSConfig + + var configs []*networkservice.DNSConfig if rv.GetContext().GetDnsContext() != nil { - conifgs = rv.GetContext().GetDnsContext().GetConfigs() - } - if len(conifgs) > 0 { - c.dnsConfigManager.Store(rv.GetId(), conifgs...) - c.updateCorefileQueue.AsyncExec(c.updateCorefile) + configs = rv.GetContext().GetDnsContext().GetConfigs() } - return rv, err -} + c.dnsConfigsMap.Store(rv.Id, configs) -func (c *dnsContextClient) updateCorefile() { - dir := filepath.Dir(c.coreFilePath) - _ = os.MkdirAll(dir, os.ModePerm) - err := ioutil.WriteFile(c.coreFilePath, []byte(c.dnsConfigManager.String()), os.ModePerm) - if err != nil { - log.FromContext(c.chainContext).Errorf("An error during update corefile: %v", err.Error()) - } + return rv, err } func (c *dnsContextClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { - var conifgs []*networkservice.DNSConfig - if conn.GetContext().GetDnsContext() != nil { - conifgs = conn.GetContext().GetDnsContext().GetConfigs() - } - if len(conifgs) > 0 { - c.dnsConfigManager.Remove(conn.GetId()) - c.updateCorefileQueue.AsyncExec(c.updateCorefile) - } + c.dnsConfigsMap.Delete(conn.Id) return next.Client(ctx).Close(ctx, conn, opts...) } @@ -146,7 +121,7 @@ func (c *dnsContextClient) storeOriginalResolvConf() { func (c *dnsContextClient) initialize() { c.restoreResolvConf() - r, err := dnscontext.OpenResolveConfig(c.resolveConfigPath) + r, err := openResolveConfig(c.resolveConfigPath) if err != nil { log.FromContext(c.chainContext).Errorf("An error during open resolve config: %v", err.Error()) return @@ -154,24 +129,21 @@ func (c *dnsContextClient) initialize() { c.storeOriginalResolvConf() - nameserver := r.Value(dnscontext.NameserverProperty) + nameserver := r.Value(nameserverProperty) if !containsNameserver(nameserver, c.defaultNameServerIP) { c.resolvconfDNSConfig = &networkservice.DNSConfig{ - SearchDomains: r.Value(dnscontext.AnyDomain), + SearchDomains: r.Value(searchProperty), DnsServerIps: nameserver, } } - c.dnsConfigManager.Store("", c.resolvconfDNSConfig) - - r.SetValue(dnscontext.NameserverProperty, c.defaultNameServerIP) + r.SetValue(nameserverProperty, c.defaultNameServerIP) + r.SetValue(searchProperty, []string{}...) if err = r.Save(); err != nil { log.FromContext(c.chainContext).Errorf("An error during save resolve config: %v", err.Error()) return } - - c.updateCorefileQueue.AsyncExec(c.updateCorefile) } func containsNameserver(servers []string, value string) bool { diff --git a/pkg/networkservice/connectioncontext/dnscontext/client_test.go b/pkg/networkservice/connectioncontext/dnscontext/client_test.go index e44252da9..7dcc59aab 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/client_test.go +++ b/pkg/networkservice/connectioncontext/dnscontext/client_test.go @@ -34,57 +34,14 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/dnscontext" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" ) -func Test_DNSContextClient_Restart(t *testing.T) { - t.Cleanup(func() { goleak.VerifyNone(t) }) - corefilePath := filepath.Join(t.TempDir(), "corefile") - resolveConfigPath := filepath.Join(t.TempDir(), "resolv.conf") - err := ioutil.WriteFile(resolveConfigPath, []byte("nameserver 8.8.4.4\n"), os.ModePerm) - require.NoError(t, err) - const expectedEmptyCorefile = `. { - fanout . 8.8.4.4 - log - reload - cache { - denial 0 - } -}` - for i := 0; i < 100; i++ { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - var c = chain.NewNetworkServiceClient( - metadata.NewClient(), - dnscontext.NewClient( - dnscontext.WithCorefilePath(corefilePath), - dnscontext.WithResolveConfigPath(resolveConfigPath), - dnscontext.WithChainContext(ctx), - ), - ) - _, _ = c.Request(ctx, &networkservice.NetworkServiceRequest{}) - - cancel() - } - - require.Never(t, func() bool { - for { - // #nosec - b, err := ioutil.ReadFile(corefilePath) - if err == nil { - time.Sleep(time.Millisecond * 50) - continue - } - return string(b) != expectedEmptyCorefile - } - }, time.Second/2, time.Millisecond*100) -} - func Test_DNSContextClient_Usecases(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - corefilePath := filepath.Join(t.TempDir(), "corefile") resolveConfigPath := filepath.Join(t.TempDir(), "resolv.conf") err := ioutil.WriteFile(resolveConfigPath, []byte("nameserver 8.8.4.4\nsearch example.com\n"), os.ModePerm) @@ -93,84 +50,30 @@ func Test_DNSContextClient_Usecases(t *testing.T) { client := chain.NewNetworkServiceClient( metadata.NewClient(), dnscontext.NewClient( - dnscontext.WithCorefilePath(corefilePath), - dnscontext.WithResolveConfigPath(resolveConfigPath), dnscontext.WithChainContext(ctx), + dnscontext.WithResolveConfigPath(resolveConfigPath), + dnscontext.WithDNSConfigsMap(new(dnsconfig.Map)), ), ) - const expectedEmptyCorefile = `. { - fanout . 8.8.4.4 - log - reload - cache { - denial 0 - } -}` + const expectedResolvconfFile = `nameserver 127.0.0.1` + requireFileChanged(ctx, t, resolveConfigPath, expectedResolvconfFile) - requireFileChanged(ctx, t, corefilePath, expectedEmptyCorefile) - - var samples = []struct { - request *networkservice.NetworkServiceRequest - expectedCorefile string - }{ - { - expectedCorefile: ". {\n\tfanout . 8.8.4.4\n\tlog\n\treload\n\tcache {\n\t\tdenial 0\n\t}\n}\nexample.com {\n\tfanout . 8.8.8.8\n\tlog\n\tcache {\n\t\tdenial 0\n\t}\n}", - request: &networkservice.NetworkServiceRequest{ - Connection: &networkservice.Connection{ - Id: "nsc-1", - Context: &networkservice.ConnectionContext{ - DnsContext: &networkservice.DNSContext{ - Configs: []*networkservice.DNSConfig{ - { - SearchDomains: []string{"example.com"}, - DnsServerIps: []string{"8.8.8.8"}, - }, - }, - }, - }, - }, - }, - }, - { - expectedCorefile: ". {\n\tfanout . 8.8.4.4\n\tlog\n\treload\n\tcache {\n\t\tdenial 0\n\t}\n}\nexample.com {\n\tfanout . 7.7.7.7 8.8.8.8 9.9.9.9\n\tlog\n\tcache {\n\t\tdenial 0\n\t}\n}", - request: &networkservice.NetworkServiceRequest{ - Connection: &networkservice.Connection{ - Id: "nsc-1", - Context: &networkservice.ConnectionContext{ - DnsContext: &networkservice.DNSContext{ - Configs: []*networkservice.DNSConfig{ - { - SearchDomains: []string{"example.com"}, - DnsServerIps: []string{"7.7.7.7"}, - }, - { - SearchDomains: []string{"example.com"}, - DnsServerIps: []string{"8.8.8.8"}, - }, - { - SearchDomains: []string{"example.com"}, - DnsServerIps: []string{"9.9.9.9"}, - }, - }, - }, - }, - }, - }, + request := &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{ + Id: "nsc-1", + Context: &networkservice.ConnectionContext{}, }, } - for _, s := range samples { - resp, err := client.Request(ctx, s.request) - require.NoError(t, err) - require.NotNil(t, resp.GetContext().GetDnsContext()) - require.Len(t, resp.GetContext().GetDnsContext().GetConfigs(), len(s.request.GetConnection().Context.DnsContext.GetConfigs())) - requireFileChanged(ctx, t, corefilePath, s.expectedCorefile) - _, err = client.Close(ctx, resp) - require.NoError(t, err) - - requireFileChanged(ctx, t, corefilePath, expectedEmptyCorefile) - } + resp, err := client.Request(ctx, request) + require.NoError(t, err) + require.NotNil(t, resp.GetContext().GetDnsContext()) + require.Len(t, resp.GetContext().GetDnsContext().GetConfigs(), len(request.GetConnection().Context.DnsContext.GetConfigs())) + require.Contains(t, resp.Context.DnsContext.Configs[0].DnsServerIps, "8.8.4.4") + require.Contains(t, resp.Context.DnsContext.Configs[0].SearchDomains, "example.com") + _, err = client.Close(ctx, resp) + require.NoError(t, err) } func requireFileChanged(ctx context.Context, t *testing.T, location, expected string) { diff --git a/pkg/networkservice/connectioncontext/dnscontext/options.go b/pkg/networkservice/connectioncontext/dnscontext/options.go index 7975b5730..61a27dd65 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/options.go +++ b/pkg/networkservice/connectioncontext/dnscontext/options.go @@ -1,5 +1,7 @@ // Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +20,8 @@ package dnscontext import ( "context" - "net" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" ) // DNSOption is applying options for DNS client. @@ -32,28 +35,28 @@ func (f applyFunc) apply(c *dnsContextClient) { f(c) } -// WithCorefilePath sets specific corefile path for DNS client. -func WithCorefilePath(path string) DNSOption { +// WithResolveConfigPath sets resolv.conf path for resonvConfigHandler. +func WithResolveConfigPath(path string) DNSOption { return applyFunc(func(c *dnsContextClient) { - c.coreFilePath = path + c.resolveConfigPath = path }) } -// WithResolveConfigPath sets specific resolve config file path for DNS client. -func WithResolveConfigPath(path string) DNSOption { +// WithDefaultNameServerIP sets default nameserver ip for resolvConfigHandler. +func WithDefaultNameServerIP(ip string) DNSOption { return applyFunc(func(c *dnsContextClient) { - c.resolveConfigPath = path + c.defaultNameServerIP = ip }) } -// WithDefaultNameServerIP sets specific IP address of default DNS server. -func WithDefaultNameServerIP(ip net.IP) DNSOption { +// WithDNSConfigsMap sets configs map for DNS client. +func WithDNSConfigsMap(configsMap *dnsconfig.Map) DNSOption { return applyFunc(func(c *dnsContextClient) { - c.defaultNameServerIP = ip.String() + c.dnsConfigsMap = configsMap }) } -// WithChainContext sets chain context for DNS server. +// WithChainContext sets chain context for DNS client. func WithChainContext(ctx context.Context) DNSOption { return applyFunc(func(c *dnsContextClient) { c.chainContext = ctx diff --git a/pkg/tools/dnscontext/resolv_conf.go b/pkg/networkservice/connectioncontext/dnscontext/resolvconf.go similarity index 70% rename from pkg/tools/dnscontext/resolv_conf.go rename to pkg/networkservice/connectioncontext/dnscontext/resolvconf.go index de0585eb2..1ebedb6e0 100644 --- a/pkg/tools/dnscontext/resolv_conf.go +++ b/pkg/networkservice/connectioncontext/dnscontext/resolvconf.go @@ -24,15 +24,15 @@ import ( "strings" ) -// ResolveConfig provides API for editing / reading resolv.conf -type ResolveConfig struct { +// resolveConfig provides API for editing / reading resolv.conf +type resolveConfig struct { path string properties map[string][]string } -// OpenResolveConfig reads resolve config file from specific path -func OpenResolveConfig(p string) (*ResolveConfig, error) { - r := &ResolveConfig{ +// openResolveConfig reads resolve config file from specific path +func openResolveConfig(p string) (*resolveConfig, error) { + r := &resolveConfig{ path: p, properties: make(map[string][]string), } @@ -42,7 +42,7 @@ func OpenResolveConfig(p string) (*ResolveConfig, error) { return r, nil } -func (r *ResolveConfig) readProperties() error { +func (r *resolveConfig) readProperties() error { b, err := ioutil.ReadFile(r.path) if err != nil { return err @@ -57,12 +57,12 @@ func (r *ResolveConfig) readProperties() error { } // Value returns value of property -func (r *ResolveConfig) Value(k string) []string { +func (r *resolveConfig) Value(k string) []string { return r.properties[k] } // SetValue sets value for specific property -func (r *ResolveConfig) SetValue(k string, values ...string) { +func (r *resolveConfig) SetValue(k string, values ...string) { if len(values) == 0 { delete(r.properties, k) } else { @@ -71,7 +71,7 @@ func (r *ResolveConfig) SetValue(k string, values ...string) { } // Save saves resolve config file -func (r *ResolveConfig) Save() error { +func (r *resolveConfig) Save() error { var sb strings.Builder var index int for k, v := range r.properties { @@ -83,3 +83,12 @@ func (r *ResolveConfig) Save() error { } return ioutil.WriteFile(r.path, []byte(sb.String()), os.ModePerm) } + +const ( + // searchProperty means search list for host-name lookup + searchProperty = "search" + // nameserverProperty means name server IP address + nameserverProperty = "nameserver" + // optionsProperty allows certain internal resolver variables to be modified + optionsProperty = "options" +) diff --git a/pkg/tools/dnscontext/resolv_conf_test.go b/pkg/networkservice/connectioncontext/dnscontext/resolvconf_test.go similarity index 77% rename from pkg/tools/dnscontext/resolv_conf_test.go rename to pkg/networkservice/connectioncontext/dnscontext/resolvconf_test.go index 2edd53a3d..43ac065bb 100644 --- a/pkg/tools/dnscontext/resolv_conf_test.go +++ b/pkg/networkservice/connectioncontext/dnscontext/resolvconf_test.go @@ -1,5 +1,3 @@ -// Copyright (c) 2020 Doc.ai and/or its affiliates. -// // Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 @@ -16,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dnscontext_test +package dnscontext import ( "io/ioutil" @@ -27,8 +25,6 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/networkservicemesh/sdk/pkg/tools/dnscontext" ) func createSample(name, source string) (string, error) { @@ -50,14 +46,14 @@ options ndots:5 defer func() { _ = os.Remove(p) }() - conf, err := dnscontext.OpenResolveConfig(p) + conf, err := openResolveConfig(p) require.NotNil(t, conf) require.Nil(t, err) - result := conf.Value(dnscontext.NameserverProperty) + result := conf.Value(nameserverProperty) require.EqualValues(t, result, []string{"127.0.0.1"}) - result = conf.Value(dnscontext.SearchProperty) + result = conf.Value(searchProperty) require.EqualValues(t, result, []string{"default.svc.cluster.local", "svc.cluster.local", "cluster.local"}) - result = conf.Value(dnscontext.OptionsProperty) + result = conf.Value(optionsProperty) require.EqualValues(t, result, []string{"ndots:5"}) } @@ -70,11 +66,11 @@ options ndots:5` defer func() { _ = os.Remove(p) }() - config, err := dnscontext.OpenResolveConfig(p) + config, err := openResolveConfig(p) require.Nil(t, err) - config.SetValue(dnscontext.NameserverProperty, "127.0.0.1") - config.SetValue(dnscontext.SearchProperty, "default.svc.cluster.local", "svc.cluster.local", "cluster.local") - config.SetValue(dnscontext.OptionsProperty, "ndots:5") + config.SetValue(nameserverProperty, "127.0.0.1") + config.SetValue(searchProperty, "default.svc.cluster.local", "svc.cluster.local", "cluster.local") + config.SetValue(optionsProperty, "ndots:5") config.SetValue("my_property") err = config.Save() require.Nil(t, err) diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go index 40ccd5b6a..817ac23f6 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/client.go @@ -25,16 +25,17 @@ import ( "google.golang.org/grpc" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" ) type vl3DNSClient struct { dnsServerIP net.IP - dnsConfigs *Map + dnsConfigs *dnsconfig.Map } // NewClient - returns a new null client that does nothing but call next.Client(ctx).{Request/Close} and return the result // This is very useful in testing -func NewClient(dnsServerIP net.IP, dnsConfigs *Map) networkservice.NetworkServiceClient { +func NewClient(dnsServerIP net.IP, dnsConfigs *dnsconfig.Map) networkservice.NetworkServiceClient { return &vl3DNSClient{ dnsServerIP: dnsServerIP, dnsConfigs: dnsConfigs, @@ -60,6 +61,7 @@ func (n *vl3DNSClient) Request(ctx context.Context, request *networkservice.Netw resp, err := next.Client(ctx).Request(ctx, request, opts...) if err == nil { + configs := make([]*networkservice.DNSConfig, 0) for _, config := range resp.GetContext().GetDnsContext().GetConfigs() { var skip = false for _, ip := range config.DnsServerIps { @@ -71,8 +73,10 @@ func (n *vl3DNSClient) Request(ctx context.Context, request *networkservice.Netw if skip { continue } - n.dnsConfigs.Store(resp.GetId(), config) + configs = append(configs, config) } + + n.dnsConfigs.Store(resp.GetId(), configs) } return resp, err diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go index 2fc6e818a..5c6565abf 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/options.go @@ -21,6 +21,7 @@ import ( "fmt" "text/template" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" ) @@ -28,9 +29,9 @@ import ( type Option func(*vl3DNSServer) // WithConfigs sets initial list to fanout queries -func WithConfigs(m *Map) Option { +func WithConfigs(m *dnsconfig.Map) Option { return func(vd *vl3DNSServer) { - vd.configs = m + vd.dnsConfigs = m } } diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go index df36e2f57..67c1ce083 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go +++ b/pkg/networkservice/connectioncontext/dnscontext/vl3dns/server.go @@ -21,7 +21,6 @@ import ( "context" "fmt" "net" - "net/url" "strings" "text/template" @@ -30,7 +29,9 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/dnsconfigs" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/fanout" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/memory" dnsnext "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" @@ -41,8 +42,8 @@ import ( type vl3DNSServer struct { dnsServerRecords memory.Map + dnsConfigs *dnsconfig.Map domainSchemeTemplates []*template.Template - configs *Map dnsPort int dnsServer dnsutils.Handler listenAndServeDNS func(ctx context.Context, handler dnsutils.Handler, listenOn string) @@ -61,7 +62,7 @@ func NewServer(chanCtx context.Context, getDNSServerIP func() net.IP, opts ...Op dnsPort: 53, listenAndServeDNS: dnsutils.ListenAndServe, getDNSServerIP: getDNSServerIP, - configs: new(Map), + dnsConfigs: new(dnsconfig.Map), } for _, opt := range opts { @@ -70,10 +71,11 @@ func NewServer(chanCtx context.Context, getDNSServerIP func() net.IP, opts ...Op if result.dnsServer == nil { result.dnsServer = dnsnext.NewDNSHandler( + dnsconfigs.NewDNSHandler(result.dnsConfigs), noloop.NewDNSHandler(), norecursion.NewDNSHandler(), memory.NewDNSHandler(&result.dnsServerRecords), - fanout.NewDNSHandler(result.getFanoutAddresses), + fanout.NewDNSHandler(fanout.WithDefaultDNSPort(uint16(result.dnsPort))), ) } @@ -124,6 +126,7 @@ func (n *vl3DNSServer) Request(ctx context.Context, request *networkservice.Netw resp, err := next.Server(ctx).Request(ctx, request) if err == nil { + configs := make([]*networkservice.DNSConfig, 0) if srcRoutes := resp.GetContext().GetIpContext().GetSrcIPRoutes(); len(srcRoutes) > 0 { var lastPrefix = srcRoutes[len(srcRoutes)-1].Prefix for _, config := range clientsConfigs { @@ -132,18 +135,18 @@ func (n *vl3DNSServer) Request(ctx context.Context, request *networkservice.Netw continue } if withinPrefix(serverIP, lastPrefix) { - n.configs.Store(resp.GetId(), config) + configs = append(configs, config) } } } } + n.dnsConfigs.Store(resp.GetId(), configs) } - return resp, err } func (n *vl3DNSServer) Close(ctx context.Context, conn *networkservice.Connection) (*empty.Empty, error) { - n.configs.Delete(conn.GetId()) + n.dnsConfigs.Delete(conn.Id) if v, ok := metadata.Map(ctx, false).LoadAndDelete(clientDNSNameKey{}); ok { var names = v.([]string) @@ -167,17 +170,6 @@ func (n *vl3DNSServer) buildSrcDNSRecords(c *networkservice.Connection) ([]strin return result, nil } -func (n *vl3DNSServer) getFanoutAddresses() []url.URL { - var result []url.URL - n.configs.Range(func(key string, value *networkservice.DNSConfig) bool { - for _, addr := range value.DnsServerIps { - result = append(result, url.URL{Scheme: "tcp", Host: fmt.Sprintf("%v:%v", addr, n.dnsPort)}) - } - return true - }) - return result -} - func compareStringSlices(a, b []string) bool { if len(a) != len(b) { return false diff --git a/pkg/tools/clienturlctx/context.go b/pkg/tools/clienturlctx/context.go index 2a4724302..3be8c06e7 100644 --- a/pkg/tools/clienturlctx/context.go +++ b/pkg/tools/clienturlctx/context.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 Cisco Systems, Inc. +// Copyright (c) 2020-2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -25,7 +25,8 @@ import ( ) const ( - clientURLKey contextKeyType = "ClientURL" + clientURLKey contextKeyType = "ClientURL" + clientURLsKey contextKeyType = "ClientURLs" // UnixURLScheme - scheme for unix urls UnixURLScheme = "unix" ) @@ -50,3 +51,25 @@ func ClientURL(ctx context.Context) *url.URL { } return nil } + +// WithClientURLs - +// Wraps 'parent' in a new Context that has list of passed URLs +func WithClientURLs(parent context.Context, urls []url.URL) context.Context { + if parent == nil { + panic("cannot create context from nil parent") + } + return context.WithValue(parent, clientURLsKey, urls) +} + +// ClientURLs - +// Returns list of URLs +func ClientURLs(ctx context.Context) []url.URL { + if rv, ok := ctx.Value(clientURLsKey).([]url.URL); ok { + return rv + } + + if rv, ok := ctx.Value(clientURLKey).(url.URL); ok { + return []url.URL{rv} + } + return nil +} diff --git a/pkg/tools/dnscontext/config_decoder.go b/pkg/tools/dnsconfig/config_decoder.go similarity index 94% rename from pkg/tools/dnscontext/config_decoder.go rename to pkg/tools/dnsconfig/config_decoder.go index af436605f..810f36f00 100644 --- a/pkg/tools/dnscontext/config_decoder.go +++ b/pkg/tools/dnsconfig/config_decoder.go @@ -1,5 +1,7 @@ // Copyright (c) 2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +16,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dnscontext +package dnsconfig import ( "encoding/json" diff --git a/pkg/tools/dnscontext/config_decoder_test.go b/pkg/tools/dnsconfig/config_decoder_test.go similarity index 87% rename from pkg/tools/dnscontext/config_decoder_test.go rename to pkg/tools/dnsconfig/config_decoder_test.go index 8471ff5e5..e66b05c7d 100644 --- a/pkg/tools/dnscontext/config_decoder_test.go +++ b/pkg/tools/dnsconfig/config_decoder_test.go @@ -1,5 +1,7 @@ // Copyright (c) 2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +15,7 @@ // 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 dnscontext_test +package dnsconfig_test import ( "testing" @@ -21,7 +23,7 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" - "github.com/networkservicemesh/sdk/pkg/tools/dnscontext" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" ) func Test_DNSConfigsDecoder_ShouldBeParsedFromJson(t *testing.T) { @@ -31,7 +33,7 @@ func Test_DNSConfigsDecoder_ShouldBeParsedFromJson(t *testing.T) { DnsServerIps: []string{"ip1", "ip2"}, }, } - var decoder dnscontext.Decoder + var decoder dnsconfig.Decoder var err = decoder.Decode(`[{"dns_server_ips": ["ip1", "ip2"], "search_domains": ["d1"]}]`) require.NoError(t, err) require.Equal(t, expected, []*networkservice.DNSConfig(decoder)) diff --git a/pkg/tools/dnsconfig/gen.go b/pkg/tools/dnsconfig/gen.go new file mode 100644 index 000000000..05acb1c82 --- /dev/null +++ b/pkg/tools/dnsconfig/gen.go @@ -0,0 +1,26 @@ +// 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 dnsconfig provides sync map like a Go map[string][]*DNSConfig but is safe for concurrent using +package dnsconfig + +import "sync" + +//go:generate go-syncmap -output sync_map.gen.go -type Map + +// Map is like a Go map[string][]*DNSConfig but is safe for concurrent use +// by multiple goroutines without additional locking or coordination +type Map sync.Map diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go b/pkg/tools/dnsconfig/sync_map.gen.go similarity index 66% rename from pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go rename to pkg/tools/dnsconfig/sync_map.gen.go index 64e2b83c2..db496e983 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/map.gen.go +++ b/pkg/tools/dnsconfig/sync_map.gen.go @@ -1,5 +1,5 @@ -// Code generated by "-output map.gen.go -type Map -output map.gen.go -type Map"; DO NOT EDIT. -package vl3dns +// Code generated by "-output sync_map.gen.go -type Map -output sync_map.gen.go -type Map"; DO NOT EDIT. +package dnsconfig import ( "sync" // Used by sync.Map. @@ -14,43 +14,43 @@ func _() { _ = (sync.Map)(Map{}) } -var _nil_Map_networkservice_DNSConfig_value = func() (val *networkservice.DNSConfig) { return }() +var _nil_Map_networkservice_DNSConfig_value = func() (val []*networkservice.DNSConfig) { return }() // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *Map) Load(key string) (*networkservice.DNSConfig, bool) { +func (m *Map) Load(key string) ([]*networkservice.DNSConfig, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { return _nil_Map_networkservice_DNSConfig_value, ok } - return value.(*networkservice.DNSConfig), ok + return value.([]*networkservice.DNSConfig), ok } // Store sets the value for a key. -func (m *Map) Store(key string, value *networkservice.DNSConfig) { +func (m *Map) Store(key string, value []*networkservice.DNSConfig) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *Map) LoadOrStore(key string, value *networkservice.DNSConfig) (*networkservice.DNSConfig, bool) { +func (m *Map) LoadOrStore(key string, value []*networkservice.DNSConfig) ([]*networkservice.DNSConfig, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { return _nil_Map_networkservice_DNSConfig_value, loaded } - return actual.(*networkservice.DNSConfig), loaded + return actual.([]*networkservice.DNSConfig), loaded } // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *Map) LoadAndDelete(key string) (value *networkservice.DNSConfig, loaded bool) { +func (m *Map) LoadAndDelete(key string) (value []*networkservice.DNSConfig, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { return _nil_Map_networkservice_DNSConfig_value, loaded } - return actual.(*networkservice.DNSConfig), loaded + return actual.([]*networkservice.DNSConfig), loaded } // Delete deletes the value for a key. @@ -68,8 +68,8 @@ func (m *Map) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *Map) Range(f func(key string, value *networkservice.DNSConfig) bool) { +func (m *Map) Range(f func(key string, value []*networkservice.DNSConfig) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(*networkservice.DNSConfig)) + return f(key.(string), value.([]*networkservice.DNSConfig)) }) } diff --git a/pkg/tools/dnscontext/manager.go b/pkg/tools/dnscontext/manager.go deleted file mode 100644 index f22de5788..000000000 --- a/pkg/tools/dnscontext/manager.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. -// -// 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 dnscontext - -import ( - "fmt" - "sort" - "strings" - "sync" - - "github.com/networkservicemesh/api/pkg/api/networkservice" -) - -// Manager can store, remove []dnscontext.Config and also present it as corefile. -// See what is corefile here: https://coredns.io/2017/07/23/corefile-explained/ -type Manager struct { - configs sync.Map -} - -func (m *Manager) String() string { - var keys []string - result := map[string][]string{} - conflict := map[string]bool{} - m.configs.Range(func(_, value interface{}) bool { - configs := value.([]*networkservice.DNSConfig) - for _, c := range configs { - k := strings.Join(c.SearchDomains, " ") - if len(result[k]) != 0 { - conflict[k] = true - } else { - keys = append(keys, k) - } - result[k] = removeDuplicates(append(result[k], c.DnsServerIps...)) - } - return true - }) - sort.Strings(keys) - sb := strings.Builder{} - i := 0 - for _, k := range keys { - v := result[k] - plugin := defaultPlugin - sort.Strings(v) - if k == "" { - _, _ = sb.WriteString(fmt.Sprintf(serverBlockTemplate, AnyDomain, plugin, strings.Join(v, " "), "log\n\treload\n\tcache {\n\t\tdenial 0\n\t}")) - } else { - _, _ = sb.WriteString(fmt.Sprintf(serverBlockTemplate, k, plugin, strings.Join(v, " "), "log\n\tcache {\n\t\tdenial 0\n\t}")) - } - i++ - if i < len(result) { - _, _ = sb.WriteRune('\n') - } - } - return sb.String() -} - -// Store stores new config with specific id -func (m *Manager) Store(id string, configs ...*networkservice.DNSConfig) { - m.configs.Store(id, configs) -} - -// Remove removes dns config by id -func (m *Manager) Remove(id string) { - m.configs.Delete(id) -} - -func removeDuplicates(words []string) []string { - set := make(map[string]bool) - var result []string - for i := 0; i < len(words); i++ { - if set[words[i]] { - continue - } - set[words[i]] = true - result = append(result, words[i]) - } - return result -} diff --git a/pkg/tools/dnscontext/manager_test.go b/pkg/tools/dnscontext/manager_test.go deleted file mode 100644 index 36a943688..000000000 --- a/pkg/tools/dnscontext/manager_test.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. -// -// 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 dnscontext_test - -import ( - "testing" - - "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/stretchr/testify/require" - - "github.com/networkservicemesh/sdk/pkg/tools/dnscontext" -) - -func TestManager_StoreAnyDomain(t *testing.T) { - const expected = `. { - fanout . IP1 IP2 - log - reload - cache { - denial 0 - } -}` - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - DnsServerIps: []string{"IP1", "IP2"}, - }) - require.Equal(t, m.String(), expected) -} - -func TestManager_StoreAnyDomainConflict(t *testing.T) { - const expected = `. { - fanout . IP1 IP2 IP3 - log - reload - cache { - denial 0 - } -}` - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - DnsServerIps: []string{"IP1", "IP2"}, - }) - m.Store("1", &networkservice.DNSConfig{ - DnsServerIps: []string{"IP3"}, - }) - actual := m.String() - require.Len(t, actual, len(expected)) - require.Contains(t, actual, "IP1") - require.Contains(t, actual, "IP2") -} - -func TestManager_Store(t *testing.T) { - expected := []string{`zone-a { - fanout . IP1 IP2 - log - cache { - denial 0 - } -}`, `zone-b zone-c { - fanout . IP3 IP4 - log - cache { - denial 0 - } -}`} - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP1", "IP2"}, - }) - m.Store("1", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-b", "zone-c"}, - DnsServerIps: []string{"IP3", "IP4"}, - }) - actual := m.String() - require.Contains(t, actual, expected[0]) - require.Contains(t, actual, expected[1]) - require.Len(t, actual, len(expected[0])+len(expected[1])+len("\n")) -} - -func TestManager_StoreConflict(t *testing.T) { - const expected = `zone-a { - fanout . IP1 IP2 IP3 - log - cache { - denial 0 - } -}` - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP1", "IP2"}, - }) - m.Store("1", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP3", "IP1"}, - }) - actual := m.String() - require.Equal(t, expected, actual) -} - -func TestManger_Remove(t *testing.T) { - const expected = `zone-a { - fanout . IP1 IP2 - log - cache { - denial 0 - } -}` - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP1", "IP2"}, - }) - m.Store("1", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-b", "zone-c"}, - DnsServerIps: []string{"IP3", "IP4"}, - }) - m.Remove("1") - require.Equal(t, m.String(), expected) -} -func TestManger_RemoveConflict(t *testing.T) { - const expected = `zone-a { - fanout . IP1 IP2 - log - cache { - denial 0 - } -}` - var m dnscontext.Manager - m.Store("0", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP1", "IP2"}, - }) - m.Store("1", &networkservice.DNSConfig{ - SearchDomains: []string{"zone-a"}, - DnsServerIps: []string{"IP3", "IP1"}, - }) - require.NotEqual(t, m.String(), expected) - m.Remove("1") - require.Equal(t, m.String(), expected) -} diff --git a/pkg/tools/dnscontext/doc.go b/pkg/tools/dnsutils/cache/gen.go similarity index 64% rename from pkg/tools/dnscontext/doc.go rename to pkg/tools/dnsutils/cache/gen.go index 7a439a87f..8cca2f3a5 100644 --- a/pkg/tools/dnscontext/doc.go +++ b/pkg/tools/dnsutils/cache/gen.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // @@ -14,5 +14,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package dnscontext provides a DNS specific tools. -package dnscontext +package cache + +import "sync" + +//go:generate go-syncmap -output sync_map.gen.go -type msgMap + +// msgMap is like a Go map[string]*dns.Msg but is safe for concurrent use +// by multiple goroutines without additional locking or coordination +type msgMap sync.Map diff --git a/pkg/tools/dnsutils/cache/handler.go b/pkg/tools/dnsutils/cache/handler.go new file mode 100644 index 000000000..644fb6607 --- /dev/null +++ b/pkg/tools/dnsutils/cache/handler.go @@ -0,0 +1,97 @@ +// 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 cache stores successful requests to DNS server +package cache + +import ( + "context" + "time" + + "github.com/miekg/dns" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +type dnsCacheHandler struct { + cache *msgMap + lastTTLUpdate time.Time +} + +func (h *dnsCacheHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { + h.updateTTL() + if v, ok := h.cache.Load(m.Question[0].Name); ok { + if validateMsg(v) { + v.Id = m.Id + if err := rw.WriteMsg(v); err != nil { + log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + dns.HandleFailed(rw, v) + return + } + return + } + + h.cache.Delete(m.Question[0].Name) + } + + wrapper := responseWriterWrapper{ + ResponseWriter: rw, + cache: h.cache, + } + + next.Handler(ctx).ServeDNS(ctx, &wrapper, m) +} + +func (h *dnsCacheHandler) updateTTL() { + now := time.Now() + + diff := uint32(now.Sub(h.lastTTLUpdate).Seconds()) + if diff == 0 { + return + } + + h.cache.Range(func(key string, value *dns.Msg) bool { + for i := range value.Answer { + if value.Answer[i].Header().Ttl < diff { + value.Answer[i].Header().Ttl = 0 + } else { + value.Answer[i].Header().Ttl -= diff + } + } + return true + }) + h.lastTTLUpdate = now +} + +func validateMsg(m *dns.Msg) bool { + for _, answer := range m.Answer { + if answer.Header().Ttl <= 0 { + return false + } + } + + return true +} + +// NewDNSHandler creates a new dns handler that stores successful requests to DNS server +func NewDNSHandler() dnsutils.Handler { + return &dnsCacheHandler{ + cache: new(msgMap), + lastTTLUpdate: time.Now(), + } +} diff --git a/pkg/tools/dnsutils/cache/handler_test.go b/pkg/tools/dnsutils/cache/handler_test.go new file mode 100644 index 000000000..9e825d29c --- /dev/null +++ b/pkg/tools/dnsutils/cache/handler_test.go @@ -0,0 +1,79 @@ +// 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 cache_test + +import ( + "net" + "testing" + "time" + + "github.com/miekg/dns" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/cache" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/memory" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" +) + +type ResponseWriter struct { + dns.ResponseWriter + Response *dns.Msg +} + +func (r *ResponseWriter) WriteMsg(m *dns.Msg) error { + r.Response = m + return nil +} + +type checkHandler struct { + Count int +} + +func (h *checkHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { + h.Count++ + next.Handler(ctx).ServeDNS(ctx, rw, m) +} + +func TestCache(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + records := new(memory.Map) + records.Store("example.com.", []net.IP{net.ParseIP("1.1.1.1")}) + + check := &checkHandler{} + handler := next.NewDNSHandler( + cache.NewDNSHandler(), + check, + memory.NewDNSHandler(records), + ) + + rw := &ResponseWriter{} + m := &dns.Msg{} + m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA) + handler.ServeDNS(ctx, rw, m) + resp1 := rw.Response.Copy() + + time.Sleep(time.Second) + + handler.ServeDNS(ctx, rw, m) + resp2 := rw.Response.Copy() + + require.Equal(t, check.Count, 1) + require.Equal(t, resp1.Answer[0].Header().Ttl-resp2.Answer[0].Header().Ttl, uint32(1)) +} diff --git a/pkg/tools/dnscontext/const.go b/pkg/tools/dnsutils/cache/response_writer_wrapper.go similarity index 56% rename from pkg/tools/dnscontext/const.go rename to pkg/tools/dnsutils/cache/response_writer_wrapper.go index f8dd60753..9646ab7aa 100644 --- a/pkg/tools/dnscontext/const.go +++ b/pkg/tools/dnsutils/cache/response_writer_wrapper.go @@ -1,5 +1,3 @@ -// Copyright (c) 2020 Doc.ai and/or its affiliates. -// // Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 @@ -16,20 +14,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dnscontext +package cache -const ( - // SearchProperty means search list for host-name lookup - SearchProperty = "search" - // NameserverProperty means name server IP address - NameserverProperty = "nameserver" - // OptionsProperty allows certain internal resolver variables to be modified - OptionsProperty = "options" - // AnyDomain means that allowed any host-name - AnyDomain = "." - defaultPlugin = "fanout" - serverBlockTemplate = `%v { - %v . %v - %v -}` +import ( + "github.com/miekg/dns" ) + +type responseWriterWrapper struct { + dns.ResponseWriter + cache *msgMap +} + +func (r *responseWriterWrapper) WriteMsg(m *dns.Msg) error { + if m != nil && m.Rcode == dns.RcodeSuccess { + r.cache.Store(m.Question[0].Name, m) + } + return r.ResponseWriter.WriteMsg(m) +} diff --git a/pkg/tools/dnsutils/cache/sync_map.gen.go b/pkg/tools/dnsutils/cache/sync_map.gen.go new file mode 100644 index 000000000..01a69d1d1 --- /dev/null +++ b/pkg/tools/dnsutils/cache/sync_map.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output sync_map.gen.go -type msgMap -output sync_map.gen.go -type msgMap"; DO NOT EDIT. +package cache + +import ( + "sync" // Used by sync.Map. + + "github.com/miekg/dns" +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert msgMap literal (type msgMap) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(msgMap{}) +} + +var _nil_msgMap_dns_Msg_value = func() (val *dns.Msg) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *msgMap) Load(key string) (*dns.Msg, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_msgMap_dns_Msg_value, ok + } + return value.(*dns.Msg), ok +} + +// Store sets the value for a key. +func (m *msgMap) Store(key string, value *dns.Msg) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *msgMap) LoadOrStore(key string, value *dns.Msg) (*dns.Msg, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_msgMap_dns_Msg_value, loaded + } + return actual.(*dns.Msg), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *msgMap) LoadAndDelete(key string) (value *dns.Msg, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_msgMap_dns_Msg_value, loaded + } + return actual.(*dns.Msg), loaded +} + +// Delete deletes the value for a key. +func (m *msgMap) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *msgMap) Range(f func(key string, value *dns.Msg) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.(*dns.Msg)) + }) +} diff --git a/pkg/tools/dnsutils/checkmsg/handler.go b/pkg/tools/dnsutils/checkmsg/handler.go new file mode 100644 index 000000000..97fd10ac3 --- /dev/null +++ b/pkg/tools/dnsutils/checkmsg/handler.go @@ -0,0 +1,43 @@ +// 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 checkmsg checks if dns message is correct +package checkmsg + +import ( + "context" + + "github.com/miekg/dns" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" +) + +type checkMsgHandler struct { +} + +func (h *checkMsgHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, m *dns.Msg) { + if m == nil { + dns.HandleFailed(rp, &dns.Msg{}) + return + } + next.Handler(ctx).ServeDNS(ctx, rp, m) +} + +// NewDNSHandler creates a new dns handler that checks if dns message is correct +func NewDNSHandler() dnsutils.Handler { + return new(checkMsgHandler) +} diff --git a/pkg/tools/dnsutils/checkmsg/handler_test.go b/pkg/tools/dnsutils/checkmsg/handler_test.go new file mode 100644 index 000000000..59efe36ef --- /dev/null +++ b/pkg/tools/dnsutils/checkmsg/handler_test.go @@ -0,0 +1,48 @@ +// 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 checkmsg_test + +import ( + "testing" + "time" + + "github.com/miekg/dns" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/checkmsg" +) + +type responseWriter struct { + dns.ResponseWriter + Response *dns.Msg +} + +func (r *responseWriter) WriteMsg(m *dns.Msg) error { + r.Response = m + return nil +} + +func TestCheckMsgHandler(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + handler := checkmsg.NewDNSHandler() + rw := &responseWriter{} + handler.ServeDNS(ctx, rw, nil) + require.NotEqual(t, rw.Response.Rcode, dns.RcodeSuccess) +} diff --git a/pkg/tools/dnsutils/connect/handler.go b/pkg/tools/dnsutils/connect/handler.go index b19b7bbc8..beaad4a68 100644 --- a/pkg/tools/dnsutils/connect/handler.go +++ b/pkg/tools/dnsutils/connect/handler.go @@ -28,7 +28,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/log" ) -// NewDNSHandler creates a new dnshandler that simply connects to the ednpoint by passed url +// NewDNSHandler creates a new dnshandler that simply connects to the endpoint by passed url // connectTO is endpoint url func NewDNSHandler(connectTO *url.URL) dnsutils.Handler { return &connectDNSHandler{connectTO: connectTO} diff --git a/pkg/tools/dnsutils/dnsconfigs/handler.go b/pkg/tools/dnsutils/dnsconfigs/handler.go new file mode 100644 index 000000000..275a01b8b --- /dev/null +++ b/pkg/tools/dnsutils/dnsconfigs/handler.go @@ -0,0 +1,67 @@ +// 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 dnsconfigs stores DNS configs +package dnsconfigs + +import ( + "context" + "net/url" + + "github.com/miekg/dns" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/searches" +) + +type dnsConfigsHandler struct { + configs *dnsconfig.Map +} + +func (h *dnsConfigsHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, m *dns.Msg) { + dnsIPs := make([]url.URL, 0) + searchDomains := make([]string, 0) + + h.configs.Range(func(key string, value []*networkservice.DNSConfig) bool { + for _, conf := range value { + ips := make([]url.URL, len(conf.DnsServerIps)) + for i, ip := range conf.DnsServerIps { + ips[i] = url.URL{Scheme: "tcp", Host: ip} + } + + dnsIPs = append(dnsIPs, ips...) + searchDomains = append(searchDomains, conf.SearchDomains...) + } + + return true + }) + + ctx = clienturlctx.WithClientURLs(ctx, dnsIPs) + ctx = searches.WithSearchDomains(ctx, searchDomains) + next.Handler(ctx).ServeDNS(ctx, rp, m) +} + +// NewDNSHandler creates a new dns handler that stores DNS configs +func NewDNSHandler(configs *dnsconfig.Map) dnsutils.Handler { + return &dnsConfigsHandler{ + configs: configs, + } +} diff --git a/pkg/tools/dnsutils/dnsconfigs/handler_test.go b/pkg/tools/dnsutils/dnsconfigs/handler_test.go new file mode 100644 index 000000000..da3eb0c07 --- /dev/null +++ b/pkg/tools/dnsutils/dnsconfigs/handler_test.go @@ -0,0 +1,93 @@ +// 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 dnsconfigs_test + +import ( + "testing" + "time" + + "github.com/miekg/dns" + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + + "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/dnsconfigs" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/searches" +) + +type checkHandler struct { + Domains []string + URLs []string +} + +func (h *checkHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { + h.Domains = searches.SearchDomains(ctx) + + urls := clienturlctx.ClientURLs(ctx) + + for i := range urls { + h.URLs = append(h.URLs, urls[i].String()) + } +} + +func TestDNSConfigs(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + configs := new(dnsconfig.Map) + + configs.Store("1", []*networkservice.DNSConfig{ + { + SearchDomains: []string{"example.com"}, + DnsServerIps: []string{"7.7.7.7"}, + }, + { + SearchDomains: []string{"net"}, + DnsServerIps: []string{"1.1.1.1"}, + }, + }) + + configs.Store("2", []*networkservice.DNSConfig{ + { + SearchDomains: []string{"my.domain"}, + DnsServerIps: []string{"9.9.9.9"}, + }, + }) + + check := &checkHandler{} + handler := next.NewDNSHandler( + dnsconfigs.NewDNSHandler(configs), + check, + ) + + handler.ServeDNS(ctx, nil, new(dns.Msg)) + + domains := check.Domains + require.Equal(t, len(domains), 3) + require.Contains(t, domains, "example.com") + require.Contains(t, domains, "my.domain") + require.Contains(t, domains, "net") + + urls := check.URLs + require.Equal(t, len(urls), 3) + require.Contains(t, urls, "tcp://7.7.7.7") + require.Contains(t, urls, "tcp://1.1.1.1") + require.Contains(t, urls, "tcp://9.9.9.9") +} diff --git a/pkg/tools/dnsutils/fanout/fanout.go b/pkg/tools/dnsutils/fanout/handler.go similarity index 72% rename from pkg/tools/dnsutils/fanout/fanout.go rename to pkg/tools/dnsutils/fanout/handler.go index 6003e22d1..a598e7c30 100644 --- a/pkg/tools/dnsutils/fanout/fanout.go +++ b/pkg/tools/dnsutils/fanout/handler.go @@ -19,23 +19,29 @@ package fanout import ( "context" + "fmt" "net/url" + "time" "github.com/miekg/dns" + "github.com/networkservicemesh/sdk/pkg/tools/clienturlctx" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" "github.com/networkservicemesh/sdk/pkg/tools/log" ) type fanoutHandler struct { - getAddressesFn GetAddressesFn + dnsPort uint16 } -func (f *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg *dns.Msg) { - var connectTO = f.getAddressesFn() +func (h *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg *dns.Msg) { + var connectTO = clienturlctx.ClientURLs(ctx) var responseCh = make(chan *dns.Msg, len(connectTO)) + deadline, _ := ctx.Deadline() + timeout := time.Until(deadline) + if len(connectTO) == 0 { log.FromContext(ctx).Error("no urls to fanout") dns.HandleFailed(rw, msg) @@ -45,11 +51,16 @@ func (f *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg for i := 0; i < len(connectTO); i++ { go func(u *url.URL, msg *dns.Msg) { var client = dns.Client{ - Net: u.Scheme, + Net: u.Scheme, + Timeout: timeout, } - var resp, _, err = client.Exchange(msg, u.Host) + address := u.Host + if u.Port() == "" { + address += fmt.Sprintf(":%d", h.dnsPort) + } + var resp, _, err = client.Exchange(msg, address) if err != nil { log.FromContext(ctx).Warnf("got an error during exchanging: %v", err.Error()) responseCh <- nil @@ -60,7 +71,7 @@ func (f *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg }(&connectTO[i], msg.Copy()) } - var resp = f.waitResponse(ctx, responseCh) + var resp = h.waitResponse(ctx, responseCh) if resp == nil { dns.HandleFailed(rw, msg) @@ -76,7 +87,7 @@ func (f *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg next.Handler(ctx).ServeDNS(ctx, rw, resp) } -func (f *fanoutHandler) waitResponse(ctx context.Context, respCh <-chan *dns.Msg) *dns.Msg { +func (h *fanoutHandler) waitResponse(ctx context.Context, respCh <-chan *dns.Msg) *dns.Msg { var respCount = cap(respCh) for { select { @@ -104,24 +115,13 @@ func (f *fanoutHandler) waitResponse(ctx context.Context, respCh <-chan *dns.Msg } } -// WithStaticAddresses sets endpoints as static addresses -func WithStaticAddresses(addresses ...url.URL) GetAddressesFn { - if len(addresses) == 0 { - panic("zero addresses are not supported") - } - return func() []url.URL { - return addresses - } -} - // NewDNSHandler creates a new dns handler instance that sends incoming queries in parallel to few endpoints -// getAddressesFn gets endpoints for fanout -func NewDNSHandler(getAddressesFn GetAddressesFn) dnsutils.Handler { - if getAddressesFn == nil { - panic("no addresses provided") +func NewDNSHandler(opts ...Option) dnsutils.Handler { + var h = &fanoutHandler{ + dnsPort: 53, } - return &fanoutHandler{getAddressesFn: getAddressesFn} + for _, o := range opts { + o(h) + } + return h } - -// GetAddressesFn is alias for urls getter function -type GetAddressesFn = func() []url.URL diff --git a/pkg/tools/dnsutils/fanout/options.go b/pkg/tools/dnsutils/fanout/options.go new file mode 100644 index 000000000..c33462c21 --- /dev/null +++ b/pkg/tools/dnsutils/fanout/options.go @@ -0,0 +1,27 @@ +// 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 fanout + +// Option modifies default fanout dns handler values +type Option func(*fanoutHandler) + +// WithDefaultDNSPort sets default DNS port for fanout dns handler if it is not presented in the client's URL +func WithDefaultDNSPort(port uint16) Option { + return func(h *fanoutHandler) { + h.dnsPort = port + } +} diff --git a/pkg/tools/dnsutils/memory/handler.go b/pkg/tools/dnsutils/memory/handler.go index b234de5a7..35dabea38 100644 --- a/pkg/tools/dnsutils/memory/handler.go +++ b/pkg/tools/dnsutils/memory/handler.go @@ -34,7 +34,7 @@ type memoryHandler struct { } func (f *memoryHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg *dns.Msg) { - if msg == nil || len(msg.Question) == 0 { + if len(msg.Question) == 0 { next.Handler(ctx).ServeDNS(ctx, rw, msg) return } diff --git a/pkg/tools/dnsutils/noloop/handler.go b/pkg/tools/dnsutils/noloop/handler.go index 2aa44f61a..ceff25bb4 100644 --- a/pkg/tools/dnsutils/noloop/handler.go +++ b/pkg/tools/dnsutils/noloop/handler.go @@ -32,10 +32,6 @@ import ( type noloopDNSHandler struct{ ids sync.Map } func (n *noloopDNSHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, m *dns.Msg) { - if m == nil { - dns.HandleFailed(rp, m) - return - } if _, loaded := n.ids.LoadOrStore(m.Id, struct{}{}); loaded { log.FromContext(ctx).Errorf("loop is not allowed: query: %v", m.String()) dns.HandleFailed(rp, m) diff --git a/pkg/tools/dnsutils/searches/context.go b/pkg/tools/dnsutils/searches/context.go new file mode 100644 index 000000000..278b7c2dc --- /dev/null +++ b/pkg/tools/dnsutils/searches/context.go @@ -0,0 +1,43 @@ +// 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 searches + +import ( + "context" +) + +const ( + searchDomainsKey contextKeyType = "SearchDomains" +) + +type contextKeyType string + +// WithSearchDomains wraps 'parent' in a new Context that has search domains +func WithSearchDomains(parent context.Context, domains []string) context.Context { + if parent == nil { + panic("cannot create context from nil parent") + } + return context.WithValue(parent, searchDomainsKey, domains) +} + +// SearchDomains returns search domains +func SearchDomains(ctx context.Context) []string { + if rv, ok := ctx.Value(searchDomainsKey).([]string); ok { + return rv + } + return nil +} diff --git a/pkg/tools/dnsutils/searches/handler.go b/pkg/tools/dnsutils/searches/handler.go new file mode 100644 index 000000000..d61056be0 --- /dev/null +++ b/pkg/tools/dnsutils/searches/handler.go @@ -0,0 +1,76 @@ +// 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 searches makes requests to all subdomains received from DNS configs +package searches + +import ( + "context" + "time" + + "github.com/miekg/dns" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +const ( + timeout = 5 * time.Second +) + +type searchDomainsHandler struct { +} + +func (h *searchDomainsHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { + domains := SearchDomains(ctx) + + r := &responseWriter{ + ResponseWriter: rw, + Responses: make([]*dns.Msg, len(domains)+1), + index: 0, + } + + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + next.Handler(ctx).ServeDNS(ctx, r, m) + + for _, d := range SearchDomains(ctx) { + newMsg := m.Copy() + newMsg.Question[0].Name = dns.Fqdn(newMsg.Question[0].Name + d) + next.Handler(ctx).ServeDNS(ctx, r, newMsg) + } + + for _, resp := range r.Responses { + if resp != nil && resp.Rcode == dns.RcodeSuccess { + resp.Question = m.Question + if err := rw.WriteMsg(resp); err != nil { + log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + dns.HandleFailed(rw, resp) + return + } + return + } + } + + dns.HandleFailed(rw, m) +} + +// NewDNSHandler creates a new dns handler that makes requests to all subdomains received from dns configs +func NewDNSHandler() dnsutils.Handler { + return new(searchDomainsHandler) +} diff --git a/pkg/tools/dnsutils/searches/handler_test.go b/pkg/tools/dnsutils/searches/handler_test.go new file mode 100644 index 000000000..1df36d676 --- /dev/null +++ b/pkg/tools/dnsutils/searches/handler_test.go @@ -0,0 +1,87 @@ +// 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 searches_test + +import ( + "net" + "testing" + "time" + + "github.com/miekg/dns" + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + + "github.com/networkservicemesh/sdk/pkg/tools/dnsconfig" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/dnsconfigs" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/memory" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/next" + "github.com/networkservicemesh/sdk/pkg/tools/dnsutils/searches" +) + +type responseWriter struct { + dns.ResponseWriter + Response *dns.Msg +} + +func (r *responseWriter) WriteMsg(m *dns.Msg) error { + r.Response = m + return nil +} + +type checkHandler struct { + Count int +} + +func (h *checkHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { + h.Count++ + next.Handler(ctx).ServeDNS(ctx, rw, m) +} + +func TestDomainSearches(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + configs := new(dnsconfig.Map) + + configs.Store("1", []*networkservice.DNSConfig{ + {SearchDomains: []string{"com", "net", "org"}, DnsServerIps: []string{"8.8.4.4"}}, + }) + + records := new(memory.Map) + records.Store("example.com.", []net.IP{net.ParseIP("1.1.1.1")}) + + check := &checkHandler{} + handler := next.NewDNSHandler( + dnsconfigs.NewDNSHandler(configs), + searches.NewDNSHandler(), + check, + memory.NewDNSHandler(records), + ) + + m := &dns.Msg{} + m.SetQuestion(dns.Fqdn("example"), dns.TypeA) + + rw := &responseWriter{} + handler.ServeDNS(ctx, rw, m) + + resp := rw.Response.Copy() + require.Equal(t, check.Count, 4) + require.Equal(t, resp.MsgHdr.Rcode, dns.RcodeSuccess) + require.NotNil(t, resp.Answer) + require.Equal(t, resp.Answer[0].(*dns.A).A.String(), "1.1.1.1") +} diff --git a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go b/pkg/tools/dnsutils/searches/response_writer.go similarity index 73% rename from pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go rename to pkg/tools/dnsutils/searches/response_writer.go index 7c26deb73..acbe6c787 100644 --- a/pkg/networkservice/connectioncontext/dnscontext/vl3dns/gen.go +++ b/pkg/tools/dnsutils/searches/response_writer.go @@ -14,13 +14,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package vl3dns +package searches import ( - "sync" + "github.com/miekg/dns" ) -//go:generate go-syncmap -output map.gen.go -type Map +type responseWriter struct { + dns.ResponseWriter + Responses []*dns.Msg + index int +} -// Map - sync.Map with key == string and value == networkservice.DNSConfig -type Map sync.Map +func (r *responseWriter) WriteMsg(m *dns.Msg) error { + r.Responses[r.index] = m + r.index++ + return nil +} From 34b2302e39212403ca4a2c6eea7a30cf5511af7b Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Tue, 19 Jul 2022 00:14:14 +0700 Subject: [PATCH 24/39] Fix upstream notifier (#1327) Signed-off-by: Artem Glazychev Signed-off-by: anastasia.malysheva --- .../chains/nsmgr/upstreamrefresh_test.go | 246 ++++++++++++++++++ .../common/upstreamrefresh/client.go | 6 + .../common/upstreamrefresh/eventloop.go | 2 +- .../common/upstreamrefresh/gen.go | 28 -- .../common/upstreamrefresh/metadata.go | 17 ++ .../common/upstreamrefresh/notifier.go | 56 ++-- .../upstreamrefresh/notifier_map.gen.go | 73 ------ .../connectioncontext/mtu/vl3mtu/client.go | 19 +- .../mtu/vl3mtu/client_test.go | 2 + 9 files changed, 324 insertions(+), 125 deletions(-) create mode 100644 pkg/networkservice/chains/nsmgr/upstreamrefresh_test.go delete mode 100644 pkg/networkservice/common/upstreamrefresh/gen.go delete mode 100644 pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go diff --git a/pkg/networkservice/chains/nsmgr/upstreamrefresh_test.go b/pkg/networkservice/chains/nsmgr/upstreamrefresh_test.go new file mode 100644 index 000000000..57a93093e --- /dev/null +++ b/pkg/networkservice/chains/nsmgr/upstreamrefresh_test.go @@ -0,0 +1,246 @@ +// 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 nsmgr_test + +import ( + "context" + "testing" + "time" + + "github.com/google/uuid" + "go.uber.org/goleak" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/api/pkg/api/registry" + "github.com/stretchr/testify/require" + + "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/upstreamrefresh" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/count" + "github.com/networkservicemesh/sdk/pkg/tools/sandbox" +) + +func Test_UpstreamRefreshClient(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + domain := sandbox.NewBuilder(ctx, t). + SetNodesCount(1). + SetNSMgrProxySupplier(nil). + SetRegistryProxySupplier(nil). + Build() + + nsRegistryClient := domain.NewNSRegistryClient(ctx, sandbox.GenerateTestToken) + + nsReg, err := nsRegistryClient.Register(ctx, defaultRegistryService("my-service")) + require.NoError(t, err) + + nseReg := defaultRegistryEndpoint(nsReg.Name) + + // This NSE will send REFRESH_REQUESTED events if mtu will be changed + counter := new(count.Server) + _ = domain.Nodes[0].NewEndpoint( + ctx, + nseReg, + sandbox.GenerateTestToken, + newRefreshSenderServer(), + counter, + ) + + // Create the first client + nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(upstreamrefresh.NewClient(ctx))) + reqCtx, reqClose := context.WithTimeout(ctx, time.Second) + defer reqClose() + + req := defaultRequest(nsReg.Name) + req.Connection.Id = uuid.New().String() + req.GetConnection().GetContext().MTU = defaultMtu + + conn, err := nsc.Request(reqCtx, req) + require.NoError(t, err) + require.Equal(t, 1, counter.UniqueRequests()) + + // Create the second client + nsc2 := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(upstreamrefresh.NewClient(ctx))) + reqCtx2, reqClose2 := context.WithTimeout(ctx, time.Second) + defer reqClose2() + + // Change MTU for the second client + req2 := defaultRequest(nsReg.Name) + req2.Connection.Id = uuid.New().String() + req2.GetConnection().GetContext().MTU = 1000 + + conn2, err := nsc2.Request(reqCtx2, req2) + require.NoError(t, err) + require.Equal(t, 2, counter.UniqueRequests()) + + // The request from the second client should trigger refresh on the first one + require.Eventually(t, func() bool { return counter.Requests() == 3 }, timeout, tick) + + _, err = nsc.Close(ctx, conn) + require.NoError(t, err) + _, err = nsc.Close(ctx, conn2) + require.NoError(t, err) +} + +func Test_UpstreamRefreshClient_LocalNotifications(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + domain := sandbox.NewBuilder(ctx, t). + SetNodesCount(1). + SetNSMgrProxySupplier(nil). + SetRegistryProxySupplier(nil). + Build() + + nsRegistryClient := domain.NewNSRegistryClient(ctx, sandbox.GenerateTestToken) + + nsReg, err := nsRegistryClient.Register(ctx, defaultRegistryService("my-service")) + require.NoError(t, err) + + // Create the first NSE + nseReg := ®istry.NetworkServiceEndpoint{ + Name: "final-endpoint1", + NetworkServiceNames: []string{nsReg.Name}, + } + counter1 := new(count.Server) + _ = domain.Nodes[0].NewEndpoint( + ctx, + nseReg, + sandbox.GenerateTestToken, + newRefreshSenderServer(), + counter1, + ) + + // Create the second NSE + nseReg2 := ®istry.NetworkServiceEndpoint{ + Name: "final-endpoint2", + NetworkServiceNames: []string{nsReg.Name}, + } + counter2 := new(count.Server) + _ = domain.Nodes[0].NewEndpoint( + ctx, + nseReg2, + sandbox.GenerateTestToken, + newRefreshSenderServer(), + counter2, + ) + + // Create the client + nsc := domain.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, client.WithAdditionalFunctionality(upstreamrefresh.NewClient(ctx, upstreamrefresh.WithLocalNotifications()))) + + // Send request --> NSE1 + reqCtx, reqClose := context.WithTimeout(ctx, time.Second) + defer reqClose() + + req := defaultRequest(nsReg.Name) + req.Connection.Id = "1" + req.GetConnection().NetworkServiceEndpointName = nseReg.Name + req.GetConnection().GetContext().MTU = defaultMtu + + conn, err := nsc.Request(reqCtx, req) + require.NoError(t, err) + require.Equal(t, 1, counter1.UniqueRequests()) + + // Send request2 --> NSE2 + reqCtx2, reqClose2 := context.WithTimeout(ctx, time.Second) + defer reqClose2() + + req2 := defaultRequest(nsReg.Name) + req2.Connection.Id = "2" + req2.GetConnection().NetworkServiceEndpointName = nseReg2.Name + req2.GetConnection().GetContext().MTU = defaultMtu + + conn2, err := nsc.Request(reqCtx2, req2) + require.NoError(t, err) + require.Equal(t, 1, counter2.UniqueRequests()) + + // Send request3 --> NSE1 with different MTU + reqCtx3, reqClose3 := context.WithTimeout(ctx, time.Second) + defer reqClose3() + + req3 := defaultRequest(nsReg.Name) + req3.Connection.Id = "3" + req3.GetConnection().NetworkServiceEndpointName = nseReg.Name + req3.GetConnection().GetContext().MTU = 1000 + + conn3, err := nsc.Request(reqCtx3, req3) + require.NoError(t, err) + require.Equal(t, 2, counter1.UniqueRequests()) + + // Third request should trigger the first and the second to refresh their connections even if they connected to different endpoints + require.Eventually(t, func() bool { return counter2.Requests() == 2 }, timeout, tick) + require.Equal(t, 1, counter2.UniqueRequests()) + + _, err = nsc.Close(ctx, conn) + require.NoError(t, err) + _, err = nsc.Close(ctx, conn2) + require.NoError(t, err) + _, err = nsc.Close(ctx, conn3) + require.NoError(t, err) +} + +type refreshSenderServer struct { + m map[string]*networkservice.Connection + mtu uint32 +} + +const defaultMtu = 9000 + +func newRefreshSenderServer() *refreshSenderServer { + return &refreshSenderServer{ + m: make(map[string]*networkservice.Connection), + mtu: defaultMtu, + } +} + +func (r *refreshSenderServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { + conn, err := next.Server(ctx).Request(ctx, request) + if err != nil { + return nil, err + } + if conn.GetContext().GetMTU() != r.mtu { + if _, ok := r.m[conn.Id]; ok { + return conn, err + } + ec, _ := monitor.LoadEventConsumer(ctx, false) + + connectionsToSend := make(map[string]*networkservice.Connection) + for k, v := range r.m { + connectionsToSend[k] = v.Clone() + connectionsToSend[k].State = networkservice.State_REFRESH_REQUESTED + } + _ = ec.Send(&networkservice.ConnectionEvent{ + Type: networkservice.ConnectionEventType_UPDATE, + Connections: connectionsToSend, + }) + } + r.m[conn.Id] = conn + + return conn, err +} + +func (r *refreshSenderServer) Close(ctx context.Context, conn *networkservice.Connection) (*emptypb.Empty, error) { + return next.Server(ctx).Close(ctx, conn) +} diff --git a/pkg/networkservice/common/upstreamrefresh/client.go b/pkg/networkservice/common/upstreamrefresh/client.go index 37b5a24c0..823353946 100644 --- a/pkg/networkservice/common/upstreamrefresh/client.go +++ b/pkg/networkservice/common/upstreamrefresh/client.go @@ -27,6 +27,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/clientconn" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" "github.com/networkservicemesh/sdk/pkg/tools/extend" "github.com/networkservicemesh/sdk/pkg/tools/postpone" ) @@ -55,6 +56,11 @@ func (u *upstreamRefreshClient) Request(ctx context.Context, request *networkser if cancelEventLoop, loaded := loadAndDelete(ctx); loaded { cancelEventLoop() } + u.localNotifier.unsubscribe(request.GetConnection().GetId()) + + if u.localNotifier != nil { + storeLocalNotifier(ctx, metadata.IsClient(u), u.localNotifier) + } conn, err := next.Client(ctx).Request(ctx, request, opts...) if err != nil { diff --git a/pkg/networkservice/common/upstreamrefresh/eventloop.go b/pkg/networkservice/common/upstreamrefresh/eventloop.go index b16b111e7..3d4e297a6 100644 --- a/pkg/networkservice/common/upstreamrefresh/eventloop.go +++ b/pkg/networkservice/common/upstreamrefresh/eventloop.go @@ -103,7 +103,7 @@ func (cev *eventLoop) eventLoop() { cev.logger.Debug("refresh requested from upstream") <-cev.eventFactory.Request() - cev.localNotifier.notify(cev.eventLoopCtx, cev.conn.GetId()) + cev.localNotifier.Notify(cev.eventLoopCtx, cev.conn.GetId()) case _, ok := <-localCh: if !ok { diff --git a/pkg/networkservice/common/upstreamrefresh/gen.go b/pkg/networkservice/common/upstreamrefresh/gen.go deleted file mode 100644 index 722e08ed2..000000000 --- a/pkg/networkservice/common/upstreamrefresh/gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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 upstreamrefresh - -import ( - "sync" -) - -type typeCh = chan struct{} - -//go:generate go-syncmap -output notifier_map.gen.go -type notifierMap - -// clientMap - sync.Map with key == string and value == chan struct{} -type notifierMap sync.Map diff --git a/pkg/networkservice/common/upstreamrefresh/metadata.go b/pkg/networkservice/common/upstreamrefresh/metadata.go index c368f456f..1cc58f508 100644 --- a/pkg/networkservice/common/upstreamrefresh/metadata.go +++ b/pkg/networkservice/common/upstreamrefresh/metadata.go @@ -23,6 +23,7 @@ import ( ) type key struct{} +type keyNotifier struct{} // store sets the context.CancelFunc stored in per Connection.Id metadata. func store(ctx context.Context, cancel context.CancelFunc) { @@ -39,3 +40,19 @@ func loadAndDelete(ctx context.Context) (value context.CancelFunc, ok bool) { value, ok = rawValue.(context.CancelFunc) return value, ok } + +// storeLocalNotifier sets the Notifier stored in per Connection.Id metadata. +func storeLocalNotifier(ctx context.Context, isClient bool, notifier Notifier) { + metadata.Map(ctx, isClient).Store(keyNotifier{}, notifier) +} + +// LoadLocalNotifier loads Notifier stored in per Connection.Id metadata. +// The loaded result reports whether the key was present. +func LoadLocalNotifier(ctx context.Context, isClient bool) (value Notifier, ok bool) { + rawValue, ok := metadata.Map(ctx, isClient).Load(keyNotifier{}) + if !ok { + return + } + value, ok = rawValue.(Notifier) + return value, ok +} diff --git a/pkg/networkservice/common/upstreamrefresh/notifier.go b/pkg/networkservice/common/upstreamrefresh/notifier.go index 7288e2b7d..d45188411 100644 --- a/pkg/networkservice/common/upstreamrefresh/notifier.go +++ b/pkg/networkservice/common/upstreamrefresh/notifier.go @@ -19,55 +19,75 @@ package upstreamrefresh import ( "context" + "github.com/edwarnicke/serialize" + "github.com/networkservicemesh/sdk/pkg/tools/log" ) // notifier - notifies all subscribers of an event type notifier struct { - channels notifierMap + executor serialize.Executor + channels map[string]chan struct{} } func newNotifier() *notifier { - return ¬ifier{} + return ¬ifier{ + channels: make(map[string]chan struct{}), + } } func (n *notifier) subscribe(id string) { if n == nil { return } - n.unsubscribe(id) - n.channels.Store(id, make(chan struct{})) + <-n.executor.AsyncExec(func() { + n.channels[id] = make(chan struct{}) + }) } func (n *notifier) get(id string) <-chan struct{} { if n == nil { return nil } - if v, ok := n.channels.Load(id); ok { - return v - } - return nil + var ch chan struct{} = nil + <-n.executor.AsyncExec(func() { + if v, ok := n.channels[id]; ok { + ch = v + } + }) + return ch } func (n *notifier) unsubscribe(id string) { if n == nil { return } - if v, ok := n.channels.LoadAndDelete(id); ok { - close(v) - } + <-n.executor.AsyncExec(func() { + if v, ok := n.channels[id]; ok { + close(v) + } + delete(n.channels, id) + }) } -func (n *notifier) notify(ctx context.Context, initiatorID string) { +func (n *notifier) Notify(ctx context.Context, initiatorID string) { if n == nil { return } - n.channels.Range(func(key string, value typeCh) bool { - if initiatorID == key { - return true + <-n.executor.AsyncExec(func() { + for k, v := range n.channels { + if initiatorID == k { + continue + } + log.FromContext(ctx).WithField("upstreamrefresh", "notifier").Debugf("send notification to: %v", k) + v <- struct{}{} } - log.FromContext(ctx).WithField("upstreamrefresh", "notifier").Debug("send notification to: %v", key) - value <- struct{}{} - return true }) } + +// Notifier - interface for local notifications sending +type Notifier interface { + Notify(ctx context.Context, initiatorID string) +} + +var _ Notifier = ¬ifier{} diff --git a/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go b/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go deleted file mode 100644 index a4f0e7753..000000000 --- a/pkg/networkservice/common/upstreamrefresh/notifier_map.gen.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by "-output notifier_map.gen.go -type notifierMap -output notifier_map.gen.go -type notifierMap"; DO NOT EDIT. -package upstreamrefresh - -import ( - "sync" // Used by sync.Map. -) - -// Generate code that will fail if the constants change value. -func _() { - // An "cannot convert notifierMap literal (type notifierMap) to type sync.Map" compiler error signifies that the base type have changed. - // Re-run the go-syncmap command to generate them again. - _ = (sync.Map)(notifierMap{}) -} - -var _nil_notifierMap_typeCh_value = func() (val typeCh) { return }() - -// Load returns the value stored in the map for a key, or nil if no -// value is present. -// The ok result indicates whether value was found in the map. -func (m *notifierMap) Load(key string) (typeCh, bool) { - value, ok := (*sync.Map)(m).Load(key) - if value == nil { - return _nil_notifierMap_typeCh_value, ok - } - return value.(typeCh), ok -} - -// Store sets the value for a key. -func (m *notifierMap) Store(key string, value typeCh) { - (*sync.Map)(m).Store(key, value) -} - -// LoadOrStore returns the existing value for the key if present. -// Otherwise, it stores and returns the given value. -// The loaded result is true if the value was loaded, false if stored. -func (m *notifierMap) LoadOrStore(key string, value typeCh) (typeCh, bool) { - actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) - if actual == nil { - return _nil_notifierMap_typeCh_value, loaded - } - return actual.(typeCh), loaded -} - -// LoadAndDelete deletes the value for a key, returning the previous value if any. -// The loaded result reports whether the key was present. -func (m *notifierMap) LoadAndDelete(key string) (value typeCh, loaded bool) { - actual, loaded := (*sync.Map)(m).LoadAndDelete(key) - if actual == nil { - return _nil_notifierMap_typeCh_value, loaded - } - return actual.(typeCh), loaded -} - -// Delete deletes the value for a key. -func (m *notifierMap) Delete(key string) { - (*sync.Map)(m).Delete(key) -} - -// Range calls f sequentially for each key and value present in the map. -// If f returns false, range stops the iteration. -// -// Range does not necessarily correspond to any consistent snapshot of the Map's -// contents: no key will be visited more than once, but if the value for any key -// is stored or deleted concurrently, Range may reflect any mapping for that key -// from any point during the Range call. -// -// Range may be O(N) with the number of elements in the map even if f returns -// false after a constant number of calls. -func (m *notifierMap) Range(f func(key string, value typeCh) bool) { - (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(typeCh)) - }) -} diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go index 3d4b0eb25..706dcb44e 100644 --- a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client.go @@ -21,11 +21,14 @@ import ( "sync" "sync/atomic" - "github.com/networkservicemesh/api/pkg/api/networkservice" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/emptypb" + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/upstreamrefresh" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" ) type vl3MtuClient struct { @@ -59,7 +62,11 @@ func (v *vl3MtuClient) Request(ctx context.Context, request *networkservice.Netw } // Update MTU of the vl3 - v.updateMinMTU(conn) + if v.updateMinMTU(conn) { + if ln, ok := upstreamrefresh.LoadLocalNotifier(ctx, metadata.IsClient(v)); ok { + ln.Notify(ctx, conn.GetId()) + } + } return conn, nil } @@ -68,15 +75,17 @@ func (v *vl3MtuClient) Close(ctx context.Context, conn *networkservice.Connectio return next.Client(ctx).Close(ctx, conn, opts...) } -func (v *vl3MtuClient) updateMinMTU(conn *networkservice.Connection) { +// updateMinMTU - returns true if mtu was updated +func (v *vl3MtuClient) updateMinMTU(conn *networkservice.Connection) bool { if atomic.LoadUint32(&v.minMtu) <= conn.GetContext().GetMTU() { - return + return false } v.m.Lock() defer v.m.Unlock() if atomic.LoadUint32(&v.minMtu) <= conn.GetContext().GetMTU() { - return + return false } atomic.StoreUint32(&v.minMtu, conn.GetContext().GetMTU()) + return true } diff --git a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go index 28e98a5b2..dba5063f9 100644 --- a/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go +++ b/pkg/networkservice/connectioncontext/mtu/vl3mtu/client_test.go @@ -27,6 +27,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/mtu/vl3mtu" "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" ) func Test_vl3MtuClient(t *testing.T) { @@ -36,6 +37,7 @@ func Test_vl3MtuClient(t *testing.T) { defer cancel() client := next.NewNetworkServiceClient( + metadata.NewClient(), vl3mtu.NewClient(), ) From a306cb12513a77e1a22ed2cb36722c8dc7f9c396 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Thu, 21 Jul 2022 12:02:22 +0700 Subject: [PATCH 25/39] replace spiffeIdmap syncMap with nested map. fix headers. Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/authorize/server.go | 24 ++++++++++--- .../common/authorize/server_test.go | 5 +-- .../common/monitor/server_test.go | 36 ++----------------- pkg/tools/monitor/authorize/common.go | 2 +- pkg/tools/monitor/authorize/options.go | 4 +-- pkg/tools/monitor/authorize/server.go | 18 +++++++--- pkg/tools/monitor/authorize/server_test.go | 16 ++++++--- pkg/tools/monitor/next/client.go | 2 +- pkg/tools/monitor/next/client_test.go | 2 +- pkg/tools/monitor/next/common_test.go | 2 +- pkg/tools/monitor/next/context.go | 2 +- pkg/tools/monitor/next/server.go | 2 +- pkg/tools/monitor/next/server_test.go | 2 +- pkg/tools/monitor/next/tail_client.go | 2 +- pkg/tools/monitor/next/tail_server.go | 2 +- .../monitor/streamcontext/stream_context.go | 4 +-- .../opa/policies/service_connection.rego | 2 ++ pkg/tools/spire/connection_map.gen.go | 36 +++++++++---------- pkg/tools/spire/gen_conn_map.go | 26 ++++++++++++++ .../{gen.go => gen_spiffeid_conn_map.go} | 4 +-- 20 files changed, 109 insertions(+), 84 deletions(-) create mode 100644 pkg/tools/spire/gen_conn_map.go rename pkg/tools/spire/{gen.go => gen_spiffeid_conn_map.go} (85%) diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index 1da8f6655..32396c4fa 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -74,9 +74,19 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N return nil, err } } + if spiffeID, err := getSpiffeID(ctx); err == nil { - ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) - a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + connID := conn.GetPath().GetPathSegments()[index-1].GetId() + ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) + if !ok { + ids = spire.ConnectionMap{} + ids.Store(connID, true) + }else { + if present, ok := ids.Load(connID); !present && !ok { + ids.Store(connID, true) + } + } + a.spiffeIDConnectionMap.Store(spiffeID, ids) } return next.Server(ctx).Request(ctx, request) } @@ -88,8 +98,14 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec PathSegments: conn.GetPath().GetPathSegments()[:index+1], } if spiffeID, err := getSpiffeID(ctx); err == nil { - ids, _ := a.spiffeIDConnectionMap.Load(spiffeID) - a.spiffeIDConnectionMap.LoadOrStore(spiffeID, append(ids, conn.GetId())) + connID := conn.GetPath().GetPathSegments()[index-1].GetId() + ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) + if ok { + if present, ok := ids.Load(connID); present && ok { + ids.Delete(connID) + } + } + a.spiffeIDConnectionMap.Store(spiffeID, ids) } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index 98e4b3686..515b93c61 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.go @@ -21,8 +21,6 @@ import ( "testing" "github.com/networkservicemesh/sdk/pkg/tools/opa" - "github.com/networkservicemesh/sdk/pkg/tools/spire" - "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -104,11 +102,10 @@ func TestAuthzEndpoint(t *testing.T) { denied: true, }, } - spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} for i := range suits { s := suits[i] t.Run(s.name, func(t *testing.T) { - srv := authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap), authorize.WithPolicies(s.policy)) + srv := authorize.NewServer(authorize.WithPolicies(s.policy)) checkResult := func(err error) { if !s.denied { require.Nil(t, err, "request expected to be not denied: ") diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index c1916d66a..30bb185be 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -18,17 +18,12 @@ package monitor_test import ( "context" - "crypto/tls" - "crypto/x509" - "encoding/pem" "testing" "time" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" "go.uber.org/goleak" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" "github.com/networkservicemesh/sdk/pkg/networkservice/common/monitor" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" @@ -37,39 +32,12 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters" ) -const ( - // certPem is a X.509 certificate with spiffeId = "spiffe://test.com/workload" - certPem = `-----BEGIN CERTIFICATE----- -MIIBvjCCAWWgAwIBAgIQbnFakUhzr52nHoLGltZDyDAKBggqhkjOPQQDAjAdMQsw -CQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwHhcNMjAwMTAxMDEwMTAxWhcNMzAw -MTAxMDEwMTAxWjAdMQswCQYDVQQGEwJVUzEOMAwGA1UEChMFU1BJUkUwWTATBgcq -hkjOPQIBBggqhkjOPQMBBwNCAASlFpbASv+NIyVdFwTp22JR5gx7D6LJ01Z8Wz0S -ZiBneWRAcYUBBQY6zKwr/RQtCDxUcFfFyq4zEfUD29a5Phnoo4GGMIGDMA4GA1Ud -DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T -AQH/BAIwADAdBgNVHQ4EFgQUJJpYlJa1eNEcks+zJcwKClopSAowJQYDVR0RBB4w -HIYac3BpZmZlOi8vdGVzdC5jb20vd29ya2xvYWQwCgYIKoZIzj0EAwIDRwAwRAIg -Dk6tlURSF8ULhNbnyUxFQ33rDic2dX8jOIstV2dWErwCIDRH2yw0swTcUMQWYgHy -aMp+T747AZGjOEfwHb9/w+7m ------END CERTIFICATE----- -` -) func TestMonitorServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) - // Put peer Certificate to context - block, _ := pem.Decode([]byte(certPem)) - x509cert, err := x509.ParseCertificate(block.Bytes) - require.NoError(t, err) - authInfo := &credentials.TLSInfo{ - State: tls.ConnectionState{ - PeerCertificates: []*x509.Certificate{x509cert}, - }} - ctx, cancel := context.WithTimeout( - peer.NewContext( - context.Background(), &peer.Peer{AuthInfo: authInfo}), - time.Second, - ) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() // Specify pathSegments to test diff --git a/pkg/tools/monitor/authorize/common.go b/pkg/tools/monitor/authorize/common.go index 1ce8d5286..7a1c792ba 100644 --- a/pkg/tools/monitor/authorize/common.go +++ b/pkg/tools/monitor/authorize/common.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/authorize/options.go b/pkg/tools/monitor/authorize/options.go index e618e7761..d0435d485 100644 --- a/pkg/tools/monitor/authorize/options.go +++ b/pkg/tools/monitor/authorize/options.go @@ -1,6 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. -// -// Copyright (c) 2022 Cisco Systems, Inc. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index a7e72f2c0..7abcee211 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -72,8 +72,15 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic } simpleMap := make(map[string][]string) a.spiffeIDConnectionMap.Range( - func(k string, v []string) bool { - simpleMap[k] = v + func(sid string, connIds spire.ConnectionMap) bool { + connIds.Range( + func(connId string, _ bool) bool { + ids := simpleMap[sid] + ids = append(ids, connId) + simpleMap[sid] = ids + return true + }, + ) return true }, ) @@ -83,7 +90,10 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic SpiffeIDConnectionMap: simpleMap, PathSegments: in.PathSegments, } - + var seg []string + for _, v := range in.PathSegments{ + seg = append(seg, v.GetId()) + } if err := a.policies.check(ctx, input); err != nil { return err } diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go index 67b3f77e4..268f24c2d 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitor/authorize/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -176,8 +176,14 @@ func TestAuthzEndpoint(t *testing.T) { require.NoError(t, err) } spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} - for k, v := range s.spiffeIDConnMap { - spiffeIDConnectionMap.Store(k, v) + + for spiffeID, connIds := range s.spiffeIDConnMap { + connIDMap := spire.ConnectionMap{} + for _, connID := range connIds { + + connIDMap.Store(connID, true) + } + spiffeIDConnectionMap.Store(spiffeID, connIDMap) } ctx, cancel := context.WithTimeout(baseCtx, time.Second) defer cancel() @@ -218,7 +224,9 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { require.NoError(t, err) spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} - spiffeIDConnectionMap.Store(spiffeID1, []string{"conn1"}) + connMap := spire.ConnectionMap{} + connMap.Store("conn1", true) + spiffeIDConnectionMap.Store(spiffeID1, connMap) err = authorize.NewMonitorConnectionServer( authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap)).MonitorConnections( selector, &testEmptyMCMCServer{context: ctx}) diff --git a/pkg/tools/monitor/next/client.go b/pkg/tools/monitor/next/client.go index bf5aa77dd..5b8e62d55 100644 --- a/pkg/tools/monitor/next/client.go +++ b/pkg/tools/monitor/next/client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/client_test.go b/pkg/tools/monitor/next/client_test.go index d620406d8..797294215 100644 --- a/pkg/tools/monitor/next/client_test.go +++ b/pkg/tools/monitor/next/client_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/common_test.go b/pkg/tools/monitor/next/common_test.go index a86443de0..d95798d6d 100644 --- a/pkg/tools/monitor/next/common_test.go +++ b/pkg/tools/monitor/next/common_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/context.go b/pkg/tools/monitor/next/context.go index e4da7e57e..24f22e1d6 100644 --- a/pkg/tools/monitor/next/context.go +++ b/pkg/tools/monitor/next/context.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/server.go b/pkg/tools/monitor/next/server.go index 1d0cf573e..86ec3dd8a 100644 --- a/pkg/tools/monitor/next/server.go +++ b/pkg/tools/monitor/next/server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/server_test.go b/pkg/tools/monitor/next/server_test.go index 7afd4b52f..3e4158bfb 100644 --- a/pkg/tools/monitor/next/server_test.go +++ b/pkg/tools/monitor/next/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/tail_client.go b/pkg/tools/monitor/next/tail_client.go index 60539b648..15d44474d 100644 --- a/pkg/tools/monitor/next/tail_client.go +++ b/pkg/tools/monitor/next/tail_client.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Cisco Systems, Inc. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/next/tail_server.go b/pkg/tools/monitor/next/tail_server.go index 2e4fdf182..04ba87a86 100644 --- a/pkg/tools/monitor/next/tail_server.go +++ b/pkg/tools/monitor/next/tail_server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Cisco Systems, Inc. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/tools/monitor/streamcontext/stream_context.go b/pkg/tools/monitor/streamcontext/stream_context.go index 17715440d..8b2b6f2d7 100644 --- a/pkg/tools/monitor/streamcontext/stream_context.go +++ b/pkg/tools/monitor/streamcontext/stream_context.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Doc.ai and/or its affiliates. +// Copyright (c) 2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package streamcontext provides API to extend context for authorize server +// Package streamcontext provides API to extend context for authorize monitor connection server package streamcontext import ( diff --git a/pkg/tools/opa/policies/service_connection.rego b/pkg/tools/opa/policies/service_connection.rego index 45af96a96..1299a0c86 100644 --- a/pkg/tools/opa/policies/service_connection.rego +++ b/pkg/tools/opa/policies/service_connection.rego @@ -21,5 +21,7 @@ default service_connection = false service_connection { conn_ids := {y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]} path_conn_ids := {x | x = input.path_segments[_].id} + count(path_conn_ids) > 0 + count(conn_ids) > 0 conn_ids == path_conn_ids } diff --git a/pkg/tools/spire/connection_map.gen.go b/pkg/tools/spire/connection_map.gen.go index b6efae4ad..1897586d7 100644 --- a/pkg/tools/spire/connection_map.gen.go +++ b/pkg/tools/spire/connection_map.gen.go @@ -1,5 +1,5 @@ -// Code generated by "-output connection_map.gen.go -type SpiffeIDConnectionMap -output connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. -// Install -output connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output connection_map.gen.go -type SpiffeIDConnectionMap" +// Code generated by "-output connection_map.gen.go -type ConnectionMap -output connection_map.gen.go -type ConnectionMap"; DO NOT EDIT. +// Install -output connection_map.gen.go -type ConnectionMap by "go get -u github.com/searKing/golang/tools/-output connection_map.gen.go -type ConnectionMap" package spire @@ -9,52 +9,52 @@ import ( // Generate code that will fail if the constants change value. func _() { - // An "cannot convert SpiffeIDConnectionMap literal (type SpiffeIDConnectionMap) to type sync.Map" compiler error signifies that the base type have changed. + // An "cannot convert ConnectionMap literal (type ConnectionMap) to type sync.Map" compiler error signifies that the base type have changed. // Re-run the go-syncmap command to generate them again. - _ = (sync.Map)(SpiffeIDConnectionMap{}) + _ = (sync.Map)(ConnectionMap{}) } -var _nil_SpiffeIDConnectionMap_string_value = func() (val []string) { return }() +var _nil_ConnectionMap_bool_value = func() (val bool) { return }() // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *SpiffeIDConnectionMap) Load(key string) ([]string, bool) { +func (m *ConnectionMap) Load(key string) (bool, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { - return _nil_SpiffeIDConnectionMap_string_value, ok + return _nil_ConnectionMap_bool_value, ok } - return value.([]string), ok + return value.(bool), ok } // Store sets the value for a key. -func (m *SpiffeIDConnectionMap) Store(key string, value []string) { +func (m *ConnectionMap) Store(key string, value bool) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value []string) ([]string, bool) { +func (m *ConnectionMap) LoadOrStore(key string, value bool) (bool, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { - return _nil_SpiffeIDConnectionMap_string_value, loaded + return _nil_ConnectionMap_bool_value, loaded } - return actual.([]string), loaded + return actual.(bool), loaded } // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value []string, loaded bool) { +func (m *ConnectionMap) LoadAndDelete(key string) (value bool, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { - return _nil_SpiffeIDConnectionMap_string_value, loaded + return _nil_ConnectionMap_bool_value, loaded } - return actual.([]string), loaded + return actual.(bool), loaded } // Delete deletes the value for a key. -func (m *SpiffeIDConnectionMap) Delete(key string) { +func (m *ConnectionMap) Delete(key string) { (*sync.Map)(m).Delete(key) } @@ -68,8 +68,8 @@ func (m *SpiffeIDConnectionMap) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *SpiffeIDConnectionMap) Range(f func(key string, value []string) bool) { +func (m *ConnectionMap) Range(f func(key string, value bool) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.([]string)) + return f(key.(string), value.(bool)) }) } diff --git a/pkg/tools/spire/gen_conn_map.go b/pkg/tools/spire/gen_conn_map.go new file mode 100644 index 000000000..a791a02ad --- /dev/null +++ b/pkg/tools/spire/gen_conn_map.go @@ -0,0 +1,26 @@ +// 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 spire + +import ( + "sync" +) + +//go:generate go-syncmap -output connection_map.gen.go -type ConnectionMap + +// ConnectionMap - sync.Map with key == string and value == bool +type ConnectionMap sync.Map diff --git a/pkg/tools/spire/gen.go b/pkg/tools/spire/gen_spiffeid_conn_map.go similarity index 85% rename from pkg/tools/spire/gen.go rename to pkg/tools/spire/gen_spiffeid_conn_map.go index 0881bcc09..725904701 100644 --- a/pkg/tools/spire/gen.go +++ b/pkg/tools/spire/gen_spiffeid_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output connection_map.gen.go -type SpiffeIDConnectionMap +//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -// SpiffeIDConnectionMap - sync.Map with key == string and value == []string +// SpiffeIDConnectionMap - sync.Map with key == string and value == ConnectionMap type SpiffeIDConnectionMap sync.Map From 6a8fb144649d6c99469d2626dfc3bd3dcd89bf24 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Thu, 21 Jul 2022 16:02:45 +0700 Subject: [PATCH 26/39] small fixes Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/authorize/server.go | 6 ++--- .../common/authorize/server_test.go | 3 ++- .../common/monitor/server_test.go | 1 - pkg/tools/monitor/authorize/server.go | 18 +++++++-------- pkg/tools/monitor/authorize/server_test.go | 23 +++++++++---------- .../opa/policies/service_connection.rego | 7 +++--- .../opa/service_connection_policy_test.go | 8 +------ pkg/tools/spire/gen_spiffeid_conn_map.go | 4 ++-- 8 files changed, 31 insertions(+), 39 deletions(-) diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index 32396c4fa..e92bb7cae 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -74,14 +74,14 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N return nil, err } } - + if spiffeID, err := getSpiffeID(ctx); err == nil { connID := conn.GetPath().GetPathSegments()[index-1].GetId() ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) if !ok { - ids = spire.ConnectionMap{} + ids = &spire.ConnectionMap{} ids.Store(connID, true) - }else { + } else { if present, ok := ids.Load(connID); !present && !ok { ids.Store(connID, true) } diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index 515b93c61..ba19809d6 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.go @@ -20,7 +20,6 @@ import ( "context" "testing" - "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -28,6 +27,8 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/status" + "github.com/networkservicemesh/sdk/pkg/tools/opa" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" ) diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index 30bb185be..5bf3b0953 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -32,7 +32,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/core/adapters" ) - func TestMonitorServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index 7abcee211..4a67cb5fb 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -53,9 +53,9 @@ func NewMonitorConnectionServer(opts ...Option) networkservice.MonitorConnection // MonitorOpaInput - used to pass complex structure to monitor policies type MonitorOpaInput struct { - SpiffeIDConnectionMap map[string][]string `json:"spiffe_id_connection_map"` - PathSegments []*networkservice.PathSegment `json:"path_segments"` - ServiceSpiffeID string `json:"service_spiffe_id"` + SpiffeIDConnectionMap map[string][]string `json:"spiffe_id_connection_map"` + PathSegments []string `json:"path_segments"` + ServiceSpiffeID string `json:"service_spiffe_id"` } func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { @@ -72,7 +72,7 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic } simpleMap := make(map[string][]string) a.spiffeIDConnectionMap.Range( - func(sid string, connIds spire.ConnectionMap) bool { + func(sid string, connIds *spire.ConnectionMap) bool { connIds.Range( func(connId string, _ bool) bool { ids := simpleMap[sid] @@ -85,14 +85,14 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic }, ) + seg := make([]string, 0) + for _, v := range in.PathSegments { + seg = append(seg, v.GetId()) + } input = MonitorOpaInput{ ServiceSpiffeID: spiffeID.String(), SpiffeIDConnectionMap: simpleMap, - PathSegments: in.PathSegments, - } - var seg []string - for _, v := range in.PathSegments{ - seg = append(seg, v.GetId()) + PathSegments: seg, } if err := a.policies.check(ctx, input); err != nil { return err diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go index 268f24c2d..60142db46 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitor/authorize/server_test.go @@ -81,9 +81,10 @@ func testPolicy() authorize.Policy { default allow = false allow { - conn_ids := {y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]} - path_conn_ids := {x | x = input.path_segments[_].id} - conn_ids == path_conn_ids + conn_ids := [y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]] + count(input.path_segments) > 0 + count(conn_ids) > 0 + conn_ids == input.path_segments } `, "allow", opa.True) } @@ -110,16 +111,16 @@ func TestAuthzEndpoint(t *testing.T) { denied bool }{ { - name: "simple positive test without peer context", + name: "simple negative test without peer context", baseCtx: false, pathSegments: make([]*networkservice.PathSegment, 0), - denied: false, + denied: true, }, { - name: "simple positive test with peer context", - baseCtx: false, + name: "simple negative test with peer context", + baseCtx: true, pathSegments: make([]*networkservice.PathSegment, 0), - denied: false, + denied: true, }, { name: "positive test with nonempty objects", @@ -176,14 +177,12 @@ func TestAuthzEndpoint(t *testing.T) { require.NoError(t, err) } spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} - for spiffeID, connIds := range s.spiffeIDConnMap { connIDMap := spire.ConnectionMap{} for _, connID := range connIds { - connIDMap.Store(connID, true) } - spiffeIDConnectionMap.Store(spiffeID, connIDMap) + spiffeIDConnectionMap.Store(spiffeID, &connIDMap) } ctx, cancel := context.WithTimeout(baseCtx, time.Second) defer cancel() @@ -226,7 +225,7 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} connMap := spire.ConnectionMap{} connMap.Store("conn1", true) - spiffeIDConnectionMap.Store(spiffeID1, connMap) + spiffeIDConnectionMap.Store(spiffeID1, &connMap) err = authorize.NewMonitorConnectionServer( authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap)).MonitorConnections( selector, &testEmptyMCMCServer{context: ctx}) diff --git a/pkg/tools/opa/policies/service_connection.rego b/pkg/tools/opa/policies/service_connection.rego index 1299a0c86..787117c1b 100644 --- a/pkg/tools/opa/policies/service_connection.rego +++ b/pkg/tools/opa/policies/service_connection.rego @@ -19,9 +19,8 @@ package nsm default service_connection = false service_connection { - conn_ids := {y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]} - path_conn_ids := {x | x = input.path_segments[_].id} - count(path_conn_ids) > 0 + conn_ids := [y | y = input.spiffe_id_connection_map[input.service_spiffe_id][_]] + count(input.path_segments) > 0 count(conn_ids) > 0 - conn_ids == path_conn_ids + conn_ids == input.path_segments } diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go index a316ba348..c071956e7 100644 --- a/pkg/tools/opa/service_connection_policy_test.go +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -20,7 +20,6 @@ import ( "context" "testing" - "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" @@ -30,12 +29,7 @@ import ( func TestWithServiceConnectionPolicy(t *testing.T) { var p = opa.WithServiceOwnConnectionPolicy() var input = authorize.MonitorOpaInput{ - PathSegments: []*networkservice.PathSegment{ - {}, - { - Id: "conn1", - }, - }, + PathSegments: []string{"conn1"}, SpiffeIDConnectionMap: map[string][]string{ spiffeID: {"conn1"}, }, diff --git a/pkg/tools/spire/gen_spiffeid_conn_map.go b/pkg/tools/spire/gen_spiffeid_conn_map.go index 725904701..99ed27644 100644 --- a/pkg/tools/spire/gen_spiffeid_conn_map.go +++ b/pkg/tools/spire/gen_spiffeid_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap +//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -// SpiffeIDConnectionMap - sync.Map with key == string and value == ConnectionMap +// SpiffeIDConnectionMap - sync.Map with key == string and value == *ConnectionMap type SpiffeIDConnectionMap sync.Map From ec3563bdc25d53487992f0b9db5f1303f9f8e376 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Thu, 21 Jul 2022 16:41:19 +0700 Subject: [PATCH 27/39] add sunc map generated file Signed-off-by: anastasia.malysheva --- .../spire/spiffe_id_connection_map.gen.go | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 pkg/tools/spire/spiffe_id_connection_map.gen.go diff --git a/pkg/tools/spire/spiffe_id_connection_map.gen.go b/pkg/tools/spire/spiffe_id_connection_map.gen.go new file mode 100644 index 000000000..62e2f6c08 --- /dev/null +++ b/pkg/tools/spire/spiffe_id_connection_map.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. +// Install -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap" + +package spire + +import ( + "sync" // Used by sync.Map. +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert SpiffeIDConnectionMap literal (type SpiffeIDConnectionMap) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(SpiffeIDConnectionMap{}) +} + +var _nil_SpiffeIDConnectionMap_ConnectionMap_value = func() (val *ConnectionMap) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *SpiffeIDConnectionMap) Load(key string) (*ConnectionMap, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_SpiffeIDConnectionMap_ConnectionMap_value, ok + } + return value.(*ConnectionMap), ok +} + +// Store sets the value for a key. +func (m *SpiffeIDConnectionMap) Store(key string, value *ConnectionMap) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value *ConnectionMap) (*ConnectionMap, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_SpiffeIDConnectionMap_ConnectionMap_value, loaded + } + return actual.(*ConnectionMap), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value *ConnectionMap, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_SpiffeIDConnectionMap_ConnectionMap_value, loaded + } + return actual.(*ConnectionMap), loaded +} + +// Delete deletes the value for a key. +func (m *SpiffeIDConnectionMap) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *SpiffeIDConnectionMap) Range(f func(key string, value *ConnectionMap) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.(*ConnectionMap)) + }) +} From 849c70acd5ac611916623945ae7927d0f937483f Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Wed, 20 Jul 2022 16:29:51 +0700 Subject: [PATCH 28/39] Add replaceNSEName chain element (#1328) * Add replaceNSEName chain element Signed-off-by: Artem Glazychev * Create passthrough chain element Signed-off-by: Artem Glazychev Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/nsmgr/suite_test.go | 4 +- .../common/passthrough/client.go | 34 ++++++++ .../{ => passthrough}/replacelabels/client.go | 41 ++++----- .../passthrough/replacelabels/client_test.go | 61 ++++++++++++++ .../passthrough/replacensename/client.go | 56 +++++++++++++ .../passthrough/replacensename/client_test.go | 83 +++++++++++++++++++ .../passthrough/replacensename/metadata.go | 50 +++++++++++ .../utils/checks/checkclose/client.go | 53 ++++++++++++ 8 files changed, 353 insertions(+), 29 deletions(-) create mode 100644 pkg/networkservice/common/passthrough/client.go rename pkg/networkservice/common/{ => passthrough}/replacelabels/client.go (72%) create mode 100644 pkg/networkservice/common/passthrough/replacelabels/client_test.go create mode 100644 pkg/networkservice/common/passthrough/replacensename/client.go create mode 100644 pkg/networkservice/common/passthrough/replacensename/client_test.go create mode 100644 pkg/networkservice/common/passthrough/replacensename/metadata.go create mode 100644 pkg/networkservice/utils/checks/checkclose/client.go diff --git a/pkg/networkservice/chains/nsmgr/suite_test.go b/pkg/networkservice/chains/nsmgr/suite_test.go index e484f1fdd..294a06e5a 100644 --- a/pkg/networkservice/chains/nsmgr/suite_test.go +++ b/pkg/networkservice/chains/nsmgr/suite_test.go @@ -42,7 +42,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms/kernel" "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanismtranslation" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/replacelabels" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/passthrough" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/count" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/inject/injecterror" @@ -794,7 +794,7 @@ func additionalFunctionalityChain(ctx context.Context, clientURL *url.URL, clien client.WithName(fmt.Sprintf("endpoint-client-%v", clientName)), client.WithAdditionalFunctionality( mechanismtranslation.NewClient(), - replacelabels.NewClient(labels), + passthrough.NewClient(labels), kernel.NewClient(), ), client.WithDialOptions(sandbox.DialOptions()...), diff --git a/pkg/networkservice/common/passthrough/client.go b/pkg/networkservice/common/passthrough/client.go new file mode 100644 index 000000000..a4e47b150 --- /dev/null +++ b/pkg/networkservice/common/passthrough/client.go @@ -0,0 +1,34 @@ +// 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 passthrough combines chain elements used in passthrough cases +package passthrough + +import ( + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/passthrough/replacelabels" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/passthrough/replacensename" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" +) + +// NewClient returns a combination for passthrough cases +func NewClient(labels map[string]string) networkservice.NetworkServiceClient { + return chain.NewNetworkServiceClient( + replacelabels.NewClient(labels), + replacensename.NewClient(), + ) +} diff --git a/pkg/networkservice/common/replacelabels/client.go b/pkg/networkservice/common/passthrough/replacelabels/client.go similarity index 72% rename from pkg/networkservice/common/replacelabels/client.go rename to pkg/networkservice/common/passthrough/replacelabels/client.go index 14a944978..f6c60badb 100644 --- a/pkg/networkservice/common/replacelabels/client.go +++ b/pkg/networkservice/common/passthrough/replacelabels/client.go @@ -1,5 +1,7 @@ // Copyright (c) 2021 Doc.ai and/or its affiliates. // +// Copyright (c) 2022 Cisco and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,45 +31,30 @@ import ( ) type replaceLabelsClient struct { - labels map[string]string - oldConnLabels map[string]string - oldNseName string + labels map[string]string } -func (s *replaceLabelsClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (conn *networkservice.Connection, err error) { - s.oldConnLabels = request.Connection.Labels - s.oldNseName = request.Connection.NetworkServiceEndpointName +// NewClient creates new instance of NetworkServiceClient chain element, which replaces labels in the connection +func NewClient(labels map[string]string) networkservice.NetworkServiceClient { + return &replaceLabelsClient{ + labels: labels, + } +} +func (s *replaceLabelsClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (conn *networkservice.Connection, err error) { + prevConnLabels := request.Connection.Labels request.Connection.Labels = s.labels - request.Connection.NetworkServiceEndpointName = "" conn, err = next.Client(ctx).Request(ctx, request, opts...) if err != nil { return nil, err } - - conn.Labels = s.oldConnLabels - conn.NetworkServiceEndpointName = s.oldNseName + conn.Labels = prevConnLabels return conn, nil } func (s *replaceLabelsClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { - s.oldConnLabels = conn.Labels - s.oldNseName = conn.NetworkServiceEndpointName - - rv, err := next.Client(ctx).Close(ctx, conn, opts...) - - conn.Labels = s.oldConnLabels - conn.NetworkServiceEndpointName = s.oldNseName - - return rv, err -} - -// NewClient creates new instance of NetworkServiceClient chain element, which replaces labels in the connection -func NewClient(labels map[string]string) networkservice.NetworkServiceClient { - return &replaceLabelsClient{ - labels: labels, - oldConnLabels: make(map[string]string), - } + conn.Labels = s.labels + return next.Client(ctx).Close(ctx, conn, opts...) } diff --git a/pkg/networkservice/common/passthrough/replacelabels/client_test.go b/pkg/networkservice/common/passthrough/replacelabels/client_test.go new file mode 100644 index 000000000..945275692 --- /dev/null +++ b/pkg/networkservice/common/passthrough/replacelabels/client_test.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 replacelabels_test + +import ( + "context" + "testing" + + "go.uber.org/goleak" + + "github.com/stretchr/testify/require" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/passthrough/replacelabels" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkclose" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkrequest" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +func TestClient(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + chainLabels := map[string]string{"1": "A", "2": "B"} + client := chain.NewNetworkServiceClient( + metadata.NewClient(), + replacelabels.NewClient(chainLabels), + checkrequest.NewClient(t, func(t *testing.T, r *networkservice.NetworkServiceRequest) { + require.Equal(t, chainLabels, r.Connection.Labels) + }), + checkclose.NewClient(t, func(t *testing.T, c *networkservice.Connection) { + require.Equal(t, chainLabels, c.Labels) + }), + ) + + // Create the request with any labels + req := &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{Id: "nsc-1", Labels: map[string]string{"3": "C"}}, + } + conn, err := client.Request(context.Background(), req) + require.NoError(t, err) + require.Equal(t, map[string]string{"3": "C"}, conn.Labels) + + _, err = client.Close(context.Background(), conn) + require.NoError(t, err) +} diff --git a/pkg/networkservice/common/passthrough/replacensename/client.go b/pkg/networkservice/common/passthrough/replacensename/client.go new file mode 100644 index 000000000..62ff9cbaf --- /dev/null +++ b/pkg/networkservice/common/passthrough/replacensename/client.go @@ -0,0 +1,56 @@ +// 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 replacensename replaces NetworkServiceEndpointName if it was discovered before +package replacensename + +import ( + "context" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type replaceNSEClient struct{} + +// NewClient creates new instance of NetworkServiceClient chain element, which replaces NetworkServiceEndpointName in the connection +func NewClient() networkservice.NetworkServiceClient { + return &replaceNSEClient{} +} + +func (s *replaceNSEClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (conn *networkservice.Connection, err error) { + prevNseName := request.Connection.NetworkServiceEndpointName + request.Connection.NetworkServiceEndpointName, _ = load(ctx) + + conn, err = next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + store(ctx, conn.NetworkServiceEndpointName) + conn.NetworkServiceEndpointName = prevNseName + + return conn, nil +} + +func (s *replaceNSEClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + conn.NetworkServiceEndpointName, _ = loadAndDelete(ctx) + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/networkservice/common/passthrough/replacensename/client_test.go b/pkg/networkservice/common/passthrough/replacensename/client_test.go new file mode 100644 index 000000000..2f1841a14 --- /dev/null +++ b/pkg/networkservice/common/passthrough/replacensename/client_test.go @@ -0,0 +1,83 @@ +// 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 replacensename_test + +import ( + "context" + "testing" + + "go.uber.org/goleak" + "google.golang.org/grpc" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/stretchr/testify/require" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + + "github.com/networkservicemesh/sdk/pkg/networkservice/common/passthrough/replacensename" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkclose" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/checks/checkrequest" + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +func TestClient(t *testing.T) { + t.Cleanup(func() { goleak.VerifyNone(t) }) + + client := chain.NewNetworkServiceClient( + metadata.NewClient(), + replacensename.NewClient(), + &setNSENameClient{name: "nse-name1"}, + checkrequest.NewClient(t, func(t *testing.T, r *networkservice.NetworkServiceRequest) { + require.Equal(t, "nse-name1", r.Connection.NetworkServiceEndpointName) + }), + checkclose.NewClient(t, func(t *testing.T, c *networkservice.Connection) { + require.Equal(t, "nse-name1", c.NetworkServiceEndpointName) + }), + ) + req := &networkservice.NetworkServiceRequest{ + Connection: &networkservice.Connection{Id: "nsc-1"}, + } + conn, err := client.Request(context.Background(), req) + require.NoError(t, err) + + // Change NetworkServiceEndpointName to another name + conn.NetworkServiceEndpointName = "nse-name2" + conn, err = client.Request(context.Background(), req) + require.Equal(t, "nse-name2", conn.NetworkServiceEndpointName) + require.NoError(t, err) + + _, err = client.Close(context.Background(), conn) + require.NoError(t, err) +} + +// setNSENameClient sets NetworkServiceEndpointName only if it is empty +type setNSENameClient struct { + name string +} + +func (s *setNSENameClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + if request.GetConnection().NetworkServiceEndpointName == "" { + request.GetConnection().NetworkServiceEndpointName = s.name + } + return next.Client(ctx).Request(ctx, request, opts...) +} + +func (s *setNSENameClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + return next.Client(ctx).Close(ctx, conn, opts...) +} diff --git a/pkg/networkservice/common/passthrough/replacensename/metadata.go b/pkg/networkservice/common/passthrough/replacensename/metadata.go new file mode 100644 index 000000000..80931a536 --- /dev/null +++ b/pkg/networkservice/common/passthrough/replacensename/metadata.go @@ -0,0 +1,50 @@ +// 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 replacensename + +import ( + "context" + + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +type keyType struct{} + +// store - stores the next network service endpoint name +func store(ctx context.Context, nseName string) { + metadata.Map(ctx, true).Store(keyType{}, nseName) +} + +// load - returns the next network service endpoint name +func load(ctx context.Context) (value string, ok bool) { + rawValue, ok := metadata.Map(ctx, true).Load(keyType{}) + if !ok { + return + } + value, ok = rawValue.(string) + return value, ok +} + +// loadAndDelete - returns the next network service endpoint name and deletes it from the metadata +func loadAndDelete(ctx context.Context) (value string, ok bool) { + rawValue, ok := metadata.Map(ctx, true).LoadAndDelete(keyType{}) + if !ok { + return + } + value, ok = rawValue.(string) + return value, ok +} diff --git a/pkg/networkservice/utils/checks/checkclose/client.go b/pkg/networkservice/utils/checks/checkclose/client.go new file mode 100644 index 000000000..354aeefb2 --- /dev/null +++ b/pkg/networkservice/utils/checks/checkclose/client.go @@ -0,0 +1,53 @@ +// 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 checkclose - provides networkservice chain elements to check the Close received from the previous element in the chain +package checkclose + +import ( + "context" + "testing" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/networkservicemesh/api/pkg/api/networkservice" + "google.golang.org/grpc" + + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" +) + +type checkCloseClient struct { + *testing.T + check func(*testing.T, *networkservice.Connection) +} + +// NewClient - returns NetworkServiceClient chain elements to check the Close received from the previous element in the chain +// t - *testing.T for checks +// check - function to check the Connection +func NewClient(t *testing.T, check func(*testing.T, *networkservice.Connection)) networkservice.NetworkServiceClient { + return &checkCloseClient{ + T: t, + check: check, + } +} + +func (c *checkCloseClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + return next.Client(ctx).Request(ctx, request, opts...) +} + +func (c *checkCloseClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + c.check(c.T, conn) + return next.Client(ctx).Close(ctx, conn, opts...) +} From 44aa575dc587016c19b8ccabde766aba3151b826 Mon Sep 17 00:00:00 2001 From: Nikita Skrynnik <93182827+NikitaSkrynnik@users.noreply.github.com> Date: Fri, 22 Jul 2022 10:38:46 +1100 Subject: [PATCH 29/39] add cmd-cluster-info-k8s repo to dependency list (#1329) Signed-off-by: Nikita Skrynnik Signed-off-by: anastasia.malysheva --- .github/workflows/update-dependent-repositories-gomod.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-dependent-repositories-gomod.yaml b/.github/workflows/update-dependent-repositories-gomod.yaml index 9a47cb5b4..471d27a83 100644 --- a/.github/workflows/update-dependent-repositories-gomod.yaml +++ b/.github/workflows/update-dependent-repositories-gomod.yaml @@ -26,6 +26,7 @@ jobs: "cmd-nsc-init", "cmd-ipam-vl3", "cmd-map-ip-k8s", - "cmd-admission-webhook-k8s"] + "cmd-admission-webhook-k8s", + "cmd-cluster-info-k8s"] secrets: token: ${{ secrets.NSM_BOT_GITHUB_TOKEN }} From faab09867da91fb681364a81abc29dc0fd147d8f Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 22 Jul 2022 15:14:17 +0700 Subject: [PATCH 30/39] fixes after comments Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/authorize/server.go | 2 +- .../common/authorize/server_test.go | 7 +- pkg/networkservice/common/monitor/server.go | 17 ++--- .../common/monitor/server_test.go | 3 +- pkg/tools/monitor/authorize/server.go | 2 +- pkg/tools/monitor/authorize/server_test.go | 4 +- pkg/tools/opa/opainput.go | 2 +- .../opa/service_connection_policy_test.go | 10 +++ pkg/tools/spire/connection_map.gen.go | 75 ------------------- pkg/tools/spire/gen_conn_map.go | 6 +- pkg/tools/spire/gen_spiffeid_conn_map.go | 4 +- .../spire/spiffe_id_connection_map.gen.go | 30 ++++---- 12 files changed, 47 insertions(+), 115 deletions(-) delete mode 100644 pkg/tools/spire/connection_map.gen.go diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index e92bb7cae..5aa44afed 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -79,7 +79,7 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N connID := conn.GetPath().GetPathSegments()[index-1].GetId() ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) if !ok { - ids = &spire.ConnectionMap{} + ids = &spire.ConnectionIDSet{} ids.Store(connID, true) } else { if present, ok := ids.Load(connID); !present && !ok { diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index ba19809d6..f4bb6f9a0 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -20,6 +20,8 @@ import ( "context" "testing" + "github.com/networkservicemesh/sdk/pkg/tools/opa" + "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -27,8 +29,6 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/status" - "github.com/networkservicemesh/sdk/pkg/tools/opa" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" ) @@ -103,6 +103,7 @@ func TestAuthzEndpoint(t *testing.T) { denied: true, }, } + for i := range suits { s := suits[i] t.Run(s.name, func(t *testing.T) { diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 7f5e47c8a..1d5f8bd31 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -39,7 +39,7 @@ import ( type monitorServer struct { chainCtx context.Context filters map[string]*monitorFilter - executor *serialize.Executor + executor serialize.Executor connections map[string]*networkservice.Connection networkservice.MonitorConnectionServer } @@ -54,18 +54,15 @@ type monitorServer struct { // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { - filters := make(map[string]*monitorFilter) - executor := serialize.Executor{} - connections := make(map[string]*networkservice.Connection) - - *monitorServerPtr = newMonitorConnectionServer(chainCtx, &executor, filters, connections) - return &monitorServer{ + var rv = &monitorServer{ chainCtx: chainCtx, MonitorConnectionServer: *monitorServerPtr, - filters: filters, - executor: &executor, - connections: connections, + filters: make(map[string]*monitorFilter), + executor: serialize.Executor{}, + connections: make(map[string]*networkservice.Connection), } + rv.MonitorConnectionServer = newMonitorConnectionServer(rv.chainCtx, &rv.executor, rv.filters, rv.connections) + return rv } func (m *monitorServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { diff --git a/pkg/networkservice/common/monitor/server_test.go b/pkg/networkservice/common/monitor/server_test.go index 5bf3b0953..580ac2b46 100644 --- a/pkg/networkservice/common/monitor/server_test.go +++ b/pkg/networkservice/common/monitor/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Cisco and/or its affiliates. +// Copyright (c) 2020-2021 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -36,7 +36,6 @@ func TestMonitorServer(t *testing.T) { t.Cleanup(func() { goleak.VerifyNone(t) }) ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() // Specify pathSegments to test diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitor/authorize/server.go index 4a67cb5fb..eccc58026 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitor/authorize/server.go @@ -72,7 +72,7 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic } simpleMap := make(map[string][]string) a.spiffeIDConnectionMap.Range( - func(sid string, connIds *spire.ConnectionMap) bool { + func(sid string, connIds *spire.ConnectionIDSet) bool { connIds.Range( func(connId string, _ bool) bool { ids := simpleMap[sid] diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitor/authorize/server_test.go index 60142db46..fd99b6af5 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitor/authorize/server_test.go @@ -178,7 +178,7 @@ func TestAuthzEndpoint(t *testing.T) { } spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} for spiffeID, connIds := range s.spiffeIDConnMap { - connIDMap := spire.ConnectionMap{} + connIDMap := spire.ConnectionIDSet{} for _, connID := range connIds { connIDMap.Store(connID, true) } @@ -223,7 +223,7 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { require.NoError(t, err) spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} - connMap := spire.ConnectionMap{} + connMap := spire.ConnectionIDSet{} connMap.Store("conn1", true) spiffeIDConnectionMap.Store(spiffeID1, &connMap) err = authorize.NewMonitorConnectionServer( diff --git a/pkg/tools/opa/opainput.go b/pkg/tools/opa/opainput.go index 4ad2243d8..24e11a5d7 100644 --- a/pkg/tools/opa/opainput.go +++ b/pkg/tools/opa/opainput.go @@ -54,7 +54,7 @@ func pemEncodingX509Cert(cert *x509.Certificate) string { return string(certpem) } -// ParseX509Cert - parse authinfo to get peer sertificate +// ParseX509Cert - parses x509 certificate from the passed credentials.AuthInfo func ParseX509Cert(authInfo credentials.AuthInfo) *x509.Certificate { var peerCert *x509.Certificate diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go index c071956e7..9e473b84a 100644 --- a/pkg/tools/opa/service_connection_policy_test.go +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -35,9 +35,19 @@ func TestWithServiceConnectionPolicy(t *testing.T) { }, ServiceSpiffeID: spiffeID, } + var invalidInput = authorize.MonitorOpaInput{ + PathSegments: []string{"conn1"}, + SpiffeIDConnectionMap: map[string][]string{ + spiffeID: {"conn2"}, + }, + ServiceSpiffeID: spiffeID, + } ctx := context.Background() err := p.Check(ctx, input) require.NoError(t, err) + + err = p.Check(ctx, invalidInput) + require.Error(t, err) } diff --git a/pkg/tools/spire/connection_map.gen.go b/pkg/tools/spire/connection_map.gen.go deleted file mode 100644 index 1897586d7..000000000 --- a/pkg/tools/spire/connection_map.gen.go +++ /dev/null @@ -1,75 +0,0 @@ -// Code generated by "-output connection_map.gen.go -type ConnectionMap -output connection_map.gen.go -type ConnectionMap"; DO NOT EDIT. -// Install -output connection_map.gen.go -type ConnectionMap by "go get -u github.com/searKing/golang/tools/-output connection_map.gen.go -type ConnectionMap" - -package spire - -import ( - "sync" // Used by sync.Map. -) - -// Generate code that will fail if the constants change value. -func _() { - // An "cannot convert ConnectionMap literal (type ConnectionMap) to type sync.Map" compiler error signifies that the base type have changed. - // Re-run the go-syncmap command to generate them again. - _ = (sync.Map)(ConnectionMap{}) -} - -var _nil_ConnectionMap_bool_value = func() (val bool) { return }() - -// Load returns the value stored in the map for a key, or nil if no -// value is present. -// The ok result indicates whether value was found in the map. -func (m *ConnectionMap) Load(key string) (bool, bool) { - value, ok := (*sync.Map)(m).Load(key) - if value == nil { - return _nil_ConnectionMap_bool_value, ok - } - return value.(bool), ok -} - -// Store sets the value for a key. -func (m *ConnectionMap) Store(key string, value bool) { - (*sync.Map)(m).Store(key, value) -} - -// LoadOrStore returns the existing value for the key if present. -// Otherwise, it stores and returns the given value. -// The loaded result is true if the value was loaded, false if stored. -func (m *ConnectionMap) LoadOrStore(key string, value bool) (bool, bool) { - actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) - if actual == nil { - return _nil_ConnectionMap_bool_value, loaded - } - return actual.(bool), loaded -} - -// LoadAndDelete deletes the value for a key, returning the previous value if any. -// The loaded result reports whether the key was present. -func (m *ConnectionMap) LoadAndDelete(key string) (value bool, loaded bool) { - actual, loaded := (*sync.Map)(m).LoadAndDelete(key) - if actual == nil { - return _nil_ConnectionMap_bool_value, loaded - } - return actual.(bool), loaded -} - -// Delete deletes the value for a key. -func (m *ConnectionMap) Delete(key string) { - (*sync.Map)(m).Delete(key) -} - -// Range calls f sequentially for each key and value present in the map. -// If f returns false, range stops the iteration. -// -// Range does not necessarily correspond to any consistent snapshot of the Map's -// contents: no key will be visited more than once, but if the value for any key -// is stored or deleted concurrently, Range may reflect any mapping for that key -// from any point during the Range call. -// -// Range may be O(N) with the number of elements in the map even if f returns -// false after a constant number of calls. -func (m *ConnectionMap) Range(f func(key string, value bool) bool) { - (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(bool)) - }) -} diff --git a/pkg/tools/spire/gen_conn_map.go b/pkg/tools/spire/gen_conn_map.go index a791a02ad..5dca182e7 100644 --- a/pkg/tools/spire/gen_conn_map.go +++ b/pkg/tools/spire/gen_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output connection_map.gen.go -type ConnectionMap +//go:generate go-syncmap -output connection_id_set.gen.go -type ConnectionIDSet -// ConnectionMap - sync.Map with key == string and value == bool -type ConnectionMap sync.Map +// ConnectionIDSet - sync.Map with key == string and value == bool +type ConnectionIDSet sync.Map diff --git a/pkg/tools/spire/gen_spiffeid_conn_map.go b/pkg/tools/spire/gen_spiffeid_conn_map.go index 99ed27644..2e4785202 100644 --- a/pkg/tools/spire/gen_spiffeid_conn_map.go +++ b/pkg/tools/spire/gen_spiffeid_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap +//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -// SpiffeIDConnectionMap - sync.Map with key == string and value == *ConnectionMap +// SpiffeIDConnectionMap - sync.Map with key == string and value == *ConnectionIDSet type SpiffeIDConnectionMap sync.Map diff --git a/pkg/tools/spire/spiffe_id_connection_map.gen.go b/pkg/tools/spire/spiffe_id_connection_map.gen.go index 62e2f6c08..4887d3bf5 100644 --- a/pkg/tools/spire/spiffe_id_connection_map.gen.go +++ b/pkg/tools/spire/spiffe_id_connection_map.gen.go @@ -1,5 +1,5 @@ -// Code generated by "-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. -// Install -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap" +// Code generated by "-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. +// Install -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap" package spire @@ -14,43 +14,43 @@ func _() { _ = (sync.Map)(SpiffeIDConnectionMap{}) } -var _nil_SpiffeIDConnectionMap_ConnectionMap_value = func() (val *ConnectionMap) { return }() +var _nil_SpiffeIDConnectionMap_ConnectionIDSet_value = func() (val *ConnectionIDSet) { return }() // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *SpiffeIDConnectionMap) Load(key string) (*ConnectionMap, bool) { +func (m *SpiffeIDConnectionMap) Load(key string) (*ConnectionIDSet, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { - return _nil_SpiffeIDConnectionMap_ConnectionMap_value, ok + return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, ok } - return value.(*ConnectionMap), ok + return value.(*ConnectionIDSet), ok } // Store sets the value for a key. -func (m *SpiffeIDConnectionMap) Store(key string, value *ConnectionMap) { +func (m *SpiffeIDConnectionMap) Store(key string, value *ConnectionIDSet) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value *ConnectionMap) (*ConnectionMap, bool) { +func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value *ConnectionIDSet) (*ConnectionIDSet, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { - return _nil_SpiffeIDConnectionMap_ConnectionMap_value, loaded + return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, loaded } - return actual.(*ConnectionMap), loaded + return actual.(*ConnectionIDSet), loaded } // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value *ConnectionMap, loaded bool) { +func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value *ConnectionIDSet, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { - return _nil_SpiffeIDConnectionMap_ConnectionMap_value, loaded + return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, loaded } - return actual.(*ConnectionMap), loaded + return actual.(*ConnectionIDSet), loaded } // Delete deletes the value for a key. @@ -68,8 +68,8 @@ func (m *SpiffeIDConnectionMap) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *SpiffeIDConnectionMap) Range(f func(key string, value *ConnectionMap) bool) { +func (m *SpiffeIDConnectionMap) Range(f func(key string, value *ConnectionIDSet) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(*ConnectionMap)) + return f(key.(string), value.(*ConnectionIDSet)) }) } From d3f3c606d3d088e825f9fde61416fb9e75150606 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 22 Jul 2022 16:47:54 +0700 Subject: [PATCH 31/39] add updated connection map Signed-off-by: anastasia.malysheva --- pkg/tools/spire/connection_id_set.gen.go | 75 ++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 pkg/tools/spire/connection_id_set.gen.go diff --git a/pkg/tools/spire/connection_id_set.gen.go b/pkg/tools/spire/connection_id_set.gen.go new file mode 100644 index 000000000..1629f4a4f --- /dev/null +++ b/pkg/tools/spire/connection_id_set.gen.go @@ -0,0 +1,75 @@ +// Code generated by "-output connection_id_set.gen.go -type ConnectionIDSet -output connection_id_set.gen.go -type ConnectionIDSet"; DO NOT EDIT. +// Install -output connection_id_set.gen.go -type ConnectionIDSet by "go get -u github.com/searKing/golang/tools/-output connection_id_set.gen.go -type ConnectionIDSet" + +package spire + +import ( + "sync" // Used by sync.Map. +) + +// Generate code that will fail if the constants change value. +func _() { + // An "cannot convert ConnectionIDSet literal (type ConnectionIDSet) to type sync.Map" compiler error signifies that the base type have changed. + // Re-run the go-syncmap command to generate them again. + _ = (sync.Map)(ConnectionIDSet{}) +} + +var _nil_ConnectionIDSet_bool_value = func() (val bool) { return }() + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (m *ConnectionIDSet) Load(key string) (bool, bool) { + value, ok := (*sync.Map)(m).Load(key) + if value == nil { + return _nil_ConnectionIDSet_bool_value, ok + } + return value.(bool), ok +} + +// Store sets the value for a key. +func (m *ConnectionIDSet) Store(key string, value bool) { + (*sync.Map)(m).Store(key, value) +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (m *ConnectionIDSet) LoadOrStore(key string, value bool) (bool, bool) { + actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) + if actual == nil { + return _nil_ConnectionIDSet_bool_value, loaded + } + return actual.(bool), loaded +} + +// LoadAndDelete deletes the value for a key, returning the previous value if any. +// The loaded result reports whether the key was present. +func (m *ConnectionIDSet) LoadAndDelete(key string) (value bool, loaded bool) { + actual, loaded := (*sync.Map)(m).LoadAndDelete(key) + if actual == nil { + return _nil_ConnectionIDSet_bool_value, loaded + } + return actual.(bool), loaded +} + +// Delete deletes the value for a key. +func (m *ConnectionIDSet) Delete(key string) { + (*sync.Map)(m).Delete(key) +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +// +// Range does not necessarily correspond to any consistent snapshot of the Map's +// contents: no key will be visited more than once, but if the value for any key +// is stored or deleted concurrently, Range may reflect any mapping for that key +// from any point during the Range call. +// +// Range may be O(N) with the number of elements in the map even if f returns +// false after a constant number of calls. +func (m *ConnectionIDSet) Range(f func(key string, value bool) bool) { + (*sync.Map)(m).Range(func(key, value interface{}) bool { + return f(key.(string), value.(bool)) + }) +} From 80eeb63d619f3c4c732961cf6f94e8d7fe04f68a Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Fri, 22 Jul 2022 17:03:15 +0700 Subject: [PATCH 32/39] lint fix Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/monitor/server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index 1d5f8bd31..bbe4a7a51 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -54,15 +54,15 @@ type monitorServer struct { // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { - var rv = &monitorServer{ + var rv = monitorServer{ chainCtx: chainCtx, MonitorConnectionServer: *monitorServerPtr, filters: make(map[string]*monitorFilter), executor: serialize.Executor{}, connections: make(map[string]*networkservice.Connection), } - rv.MonitorConnectionServer = newMonitorConnectionServer(rv.chainCtx, &rv.executor, rv.filters, rv.connections) - return rv + *monitorServerPtr = newMonitorConnectionServer(rv.chainCtx, &rv.executor, rv.filters, rv.connections) + return &rv } func (m *monitorServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { From 4b71f3dfa352449bb8547c1680ef31c47e945fef Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 25 Jul 2022 10:11:48 +0700 Subject: [PATCH 33/39] remove next monitorconnection client and other fixes after comments Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 4 +- pkg/networkservice/chains/nsmgr/server.go | 2 +- .../chains/nsmgrproxy/server.go | 2 +- pkg/networkservice/common/authorize/server.go | 41 +++---- .../monitor/monitor_connection_server.go | 64 +++++++++-- pkg/tools/monitor/next/client.go | 72 ------------ pkg/tools/monitor/next/client_test.go | 106 ------------------ .../authorize/common.go | 0 .../authorize/options.go | 0 .../authorize/server.go | 26 +---- .../authorize/server_test.go | 2 +- .../next/common_test.go | 0 .../next/context.go | 20 ---- .../next/server.go | 2 +- .../next/server_test.go | 4 +- .../next/tail_client.go | 0 .../next/tail_server.go | 0 .../streamcontext/stream_context.go | 0 .../opa/service_connection_policy_test.go | 2 +- pkg/tools/sandbox/node.go | 2 +- pkg/tools/spire/start.go | 24 ++++ 21 files changed, 106 insertions(+), 267 deletions(-) delete mode 100644 pkg/tools/monitor/next/client.go delete mode 100644 pkg/tools/monitor/next/client_test.go rename pkg/tools/{monitor => monitorconnection}/authorize/common.go (100%) rename pkg/tools/{monitor => monitorconnection}/authorize/options.go (100%) rename pkg/tools/{monitor => monitorconnection}/authorize/server.go (82%) rename pkg/tools/{monitor => monitorconnection}/authorize/server_test.go (98%) rename pkg/tools/{monitor => monitorconnection}/next/common_test.go (100%) rename pkg/tools/{monitor => monitorconnection}/next/context.go (66%) rename pkg/tools/{monitor => monitorconnection}/next/server.go (97%) rename pkg/tools/{monitor => monitorconnection}/next/server_test.go (95%) rename pkg/tools/{monitor => monitorconnection}/next/tail_client.go (100%) rename pkg/tools/{monitor => monitorconnection}/next/tail_server.go (100%) rename pkg/tools/{monitor => monitorconnection}/streamcontext/stream_context.go (100%) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index ca4e79cac..2da549cf9 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -41,8 +41,8 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/updatetoken" "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" "github.com/networkservicemesh/sdk/pkg/tools/token" ) diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index ca8577545..75219bbae 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -58,7 +58,7 @@ import ( registryadapter "github.com/networkservicemesh/sdk/pkg/registry/core/adapters" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index 111466082..810f025a3 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -50,7 +50,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/fs" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index 5aa44afed..c6502d275 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -21,11 +21,8 @@ package authorize import ( "context" - "crypto/x509" "github.com/golang/protobuf/ptypes/empty" - "github.com/pkg/errors" - "github.com/spiffe/go-spiffe/v2/svid/x509svid" "google.golang.org/grpc/peer" "github.com/networkservicemesh/api/pkg/api/networkservice" @@ -75,17 +72,13 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N } } - if spiffeID, err := getSpiffeID(ctx); err == nil { + if spiffeID, err := spire.SpiffeIDFromContext(ctx); err == nil { connID := conn.GetPath().GetPathSegments()[index-1].GetId() ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) if !ok { ids = &spire.ConnectionIDSet{} - ids.Store(connID, true) - } else { - if present, ok := ids.Load(connID); !present && !ok { - ids.Store(connID, true) - } } + ids.Store(connID, true) a.spiffeIDConnectionMap.Store(spiffeID, ids) } return next.Server(ctx).Request(ctx, request) @@ -97,7 +90,7 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec Index: index, PathSegments: conn.GetPath().GetPathSegments()[:index+1], } - if spiffeID, err := getSpiffeID(ctx); err == nil { + if spiffeID, err := spire.SpiffeIDFromContext(ctx); err == nil { connID := conn.GetPath().GetPathSegments()[index-1].GetId() ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) if ok { @@ -105,7 +98,16 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec ids.Delete(connID) } } - a.spiffeIDConnectionMap.Store(spiffeID, ids) + idsEmpty := true + ids.Range(func(_ string, _ bool) bool { + idsEmpty = false + return true + }) + if idsEmpty { + a.spiffeIDConnectionMap.Delete(spiffeID) + } else { + a.spiffeIDConnectionMap.Store(spiffeID, ids) + } } if _, ok := peer.FromContext(ctx); ok { if err := a.policies.check(ctx, leftSide); err != nil { @@ -114,20 +116,3 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec } return next.Server(ctx).Close(ctx, conn) } - -func getSpiffeID(ctx context.Context) (string, error) { - p, ok := peer.FromContext(ctx) - var cert *x509.Certificate - if !ok { - return "", errors.New("fail to get peer from context") - } - cert = opa.ParseX509Cert(p.AuthInfo) - if cert != nil { - spiffeID, err := x509svid.IDFromCert(cert) - if err == nil { - return spiffeID.String(), nil - } - return "", errors.New("fail to get Spiffe ID from certificate") - } - return "", errors.New("fail to get certificate from peer") -} diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index eb54a7b21..8e31bf8bb 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -22,31 +22,24 @@ import ( "github.com/edwarnicke/serialize" "github.com/google/uuid" "github.com/networkservicemesh/api/pkg/api/networkservice" - - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" ) type monitorConnectionServer struct { chainCtx context.Context connections map[string]*networkservice.Connection filters map[string]*monitorFilter - executor *serialize.Executor + executor serialize.Executor } -func newMonitorConnectionServer(chainCtx context.Context, executor *serialize.Executor, - filters map[string]*monitorFilter, connections map[string]*networkservice.Connection) networkservice.MonitorConnectionServer { +func newMonitorConnectionServer(chainCtx context.Context) networkservice.MonitorConnectionServer { return &monitorConnectionServer{ chainCtx: chainCtx, - connections: connections, - filters: filters, - executor: executor, + connections: make(map[string]*networkservice.Connection), + filters: make(map[string]*monitorFilter), } } func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { - if err := next.MonitorConnectionServer(srv.Context()).MonitorConnections(selector, srv); err != nil { - return err - } m.executor.AsyncExec(func() { filter := newMonitorFilter(selector, srv) m.filters[uuid.New().String()] = filter @@ -69,3 +62,52 @@ func (m *monitorConnectionServer) MonitorConnections(selector *networkservice.Mo return nil } + +var _ networkservice.MonitorConnectionServer = &monitorConnectionServer{} + +func (m *monitorConnectionServer) Send(event *networkservice.ConnectionEvent) (_ error) { + m.executor.AsyncExec(func() { + if event.Type == networkservice.ConnectionEventType_UPDATE { + for _, conn := range event.GetConnections() { + m.connections[conn.GetId()] = conn.Clone() + } + } + if event.Type == networkservice.ConnectionEventType_DELETE { + for _, conn := range event.GetConnections() { + delete(m.connections, conn.GetId()) + } + } + if event.Type == networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER { + // sending event with INIITIAL_STATE_TRANSFER not permitted + return + } + for id, filter := range m.filters { + id, filter := id, filter + e := event.Clone() + filter.executor.AsyncExec(func() { + var err error + select { + case <-filter.Context().Done(): + m.executor.AsyncExec(func() { + delete(m.filters, id) + }) + default: + err = filter.Send(e) + } + if err != nil { + m.executor.AsyncExec(func() { + delete(m.filters, id) + }) + } + }) + } + }) + return nil +} + +// EventConsumer - interface for monitor events sending +type EventConsumer interface { + Send(event *networkservice.ConnectionEvent) (err error) +} + +var _ EventConsumer = &monitorConnectionServer{} diff --git a/pkg/tools/monitor/next/client.go b/pkg/tools/monitor/next/client.go deleted file mode 100644 index 5b8e62d55..000000000 --- a/pkg/tools/monitor/next/client.go +++ /dev/null @@ -1,72 +0,0 @@ -// 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 next - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/networkservicemesh/api/pkg/api/networkservice" -) - -type nextMonitorConnectionClient struct { - clients []networkservice.MonitorConnectionClient - index int - nextParent networkservice.MonitorConnectionClient -} - -// MonitorConnectionClientWrapper - a function that wraps around a networkservice.MonitorConnectionClient -type MonitorConnectionClientWrapper func(networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient - -// MonitorConnectionClientChainer - a function that chains together a list of networkservice.MonitorConnectionClient -type MonitorConnectionClientChainer func(...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient - -// NewWrappedMonitorConnectionClient chains together clients with wrapper wrapped around each one -func NewWrappedMonitorConnectionClient(wrapper MonitorConnectionClientWrapper, clients ...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { - rv := &nextMonitorConnectionClient{clients: make([]networkservice.MonitorConnectionClient, 0, len(clients))} - for _, c := range clients { - rv.clients = append(rv.clients, wrapper(c)) - } - return rv -} - -// NewMonitorConnectionClient - chains together clients into a single networkservice.MonitorConnectionClient -func NewMonitorConnectionClient(clients ...networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { - return NewWrappedMonitorConnectionClient(func(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { - return client - }, clients...) -} - -func (n *nextMonitorConnectionClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { - client, ctx := n.getClientAndContext(ctx) - return client.MonitorConnections(ctx, in, opts...) -} - -func (n *nextMonitorConnectionClient) getClientAndContext(ctx context.Context) (networkservice.MonitorConnectionClient, context.Context) { - nextParent := n.nextParent - if n.index == 0 { - nextParent = MonitorConnectionClient(ctx) - if len(n.clients) == 0 { - return nextParent, ctx - } - } - if n.index+1 < len(n.clients) { - return n.clients[n.index], withNextMonitorConnectionClient(ctx, &nextMonitorConnectionClient{nextParent: nextParent, clients: n.clients, index: n.index + 1}) - } - return n.clients[n.index], withNextMonitorConnectionClient(ctx, nextParent) -} diff --git a/pkg/tools/monitor/next/client_test.go b/pkg/tools/monitor/next/client_test.go deleted file mode 100644 index 797294215..000000000 --- a/pkg/tools/monitor/next/client_test.go +++ /dev/null @@ -1,106 +0,0 @@ -// 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 next_test - -import ( - "context" - "fmt" - "io" - "sync" - "testing" - - "google.golang.org/grpc" - - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" - - "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/stretchr/testify/assert" -) - -type testEmptyMCMCClient struct { - ctx context.Context - grpc.ClientStream -} - -func (t *testEmptyMCMCClient) Recv() (*networkservice.ConnectionEvent, error) { - return nil, io.EOF -} - -func (t *testEmptyMCMCClient) Context() context.Context { - return t.ctx -} - -type testEmptyMCClient struct{} - -func (t *testEmptyMCClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { - return &testEmptyMCMCClient{ctx: ctx}, nil -} -func emptyMCClient() networkservice.MonitorConnectionClient { - return &testEmptyMCClient{} -} - -type testVisitMCClient struct{} - -// MonitorConnections(ctx context.Context, in *MonitorScopeSelector, opts ...grpc.CallOption) (MonitorConnection_MonitorConnectionsClient, error) -func (t *testVisitMCClient) MonitorConnections(ctx context.Context, in *networkservice.MonitorScopeSelector, opts ...grpc.CallOption) (networkservice.MonitorConnection_MonitorConnectionsClient, error) { - return next.MonitorConnectionClient(ctx).MonitorConnections(visit(ctx), in, opts...) -} - -func visitMCClient() networkservice.MonitorConnectionClient { - return &testVisitMCClient{} -} - -func TestNewMonitorConnectionClientShouldNotPanic(t *testing.T) { - assert.NotPanics(t, func() { - _, _ = next.NewMonitorConnectionClient().MonitorConnections(context.Background(), nil) - _, _ = next.NewWrappedMonitorConnectionClient(func(client networkservice.MonitorConnectionClient) networkservice.MonitorConnectionClient { - return client - }).MonitorConnections(context.Background(), nil) - }) -} - -func TestDataRaceMonitorConnectionClient(t *testing.T) { - c := next.NewMonitorConnectionClient(emptyMCClient()) - wg := sync.WaitGroup{} - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - _, _ = c.MonitorConnections(context.Background(), nil) - }() - } - wg.Wait() -} - -func TestNSClientBranches(t *testing.T) { - servers := [][]networkservice.MonitorConnectionClient{ - {visitMCClient()}, - {visitMCClient(), visitMCClient()}, - {visitMCClient(), visitMCClient(), visitMCClient()}, - {emptyMCClient(), visitMCClient(), visitMCClient()}, - {visitMCClient(), emptyMCClient(), visitMCClient()}, - {visitMCClient(), visitMCClient(), emptyMCClient()}, - {next.NewMonitorConnectionClient(), next.NewMonitorConnectionClient(visitMCClient(), next.NewMonitorConnectionClient()), visitMCClient()}, - } - expects := []int{1, 2, 3, 0, 1, 2, 2, 2} - for i, sample := range servers { - s := next.NewMonitorConnectionClient(sample...) - ctx := visit(context.Background()) - _, _ = s.MonitorConnections(ctx, nil) - assert.Equal(t, expects[i], visitValue(ctx), fmt.Sprintf("sample index: %v", i)) - } -} diff --git a/pkg/tools/monitor/authorize/common.go b/pkg/tools/monitorconnection/authorize/common.go similarity index 100% rename from pkg/tools/monitor/authorize/common.go rename to pkg/tools/monitorconnection/authorize/common.go diff --git a/pkg/tools/monitor/authorize/options.go b/pkg/tools/monitorconnection/authorize/options.go similarity index 100% rename from pkg/tools/monitor/authorize/options.go rename to pkg/tools/monitorconnection/authorize/options.go diff --git a/pkg/tools/monitor/authorize/server.go b/pkg/tools/monitorconnection/authorize/server.go similarity index 82% rename from pkg/tools/monitor/authorize/server.go rename to pkg/tools/monitorconnection/authorize/server.go index eccc58026..0969ac8f4 100644 --- a/pkg/tools/monitor/authorize/server.go +++ b/pkg/tools/monitorconnection/authorize/server.go @@ -18,14 +18,9 @@ package authorize import ( - "crypto/x509" - "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/spiffe/go-spiffe/v2/svid/x509svid" - "google.golang.org/grpc/peer" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/sdk/pkg/tools/spire" ) @@ -60,16 +55,6 @@ type MonitorOpaInput struct { func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservice.MonitorScopeSelector, srv networkservice.MonitorConnection_MonitorConnectionsServer) error { ctx := srv.Context() - p, ok := peer.FromContext(ctx) - var cert *x509.Certificate - if ok { - cert = opa.ParseX509Cert(p.AuthInfo) - } - var input MonitorOpaInput - var spiffeID spiffeid.ID - if cert != nil { - spiffeID, _ = x509svid.IDFromCert(cert) - } simpleMap := make(map[string][]string) a.spiffeIDConnectionMap.Range( func(sid string, connIds *spire.ConnectionIDSet) bool { @@ -89,12 +74,13 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic for _, v := range in.PathSegments { seg = append(seg, v.GetId()) } - input = MonitorOpaInput{ - ServiceSpiffeID: spiffeID.String(), + spiffeID, _ := spire.SpiffeIDFromContext(ctx) + err := a.policies.check(ctx, MonitorOpaInput{ + ServiceSpiffeID: spiffeID, SpiffeIDConnectionMap: simpleMap, PathSegments: seg, - } - if err := a.policies.check(ctx, input); err != nil { + }) + if err != nil { return err } diff --git a/pkg/tools/monitor/authorize/server_test.go b/pkg/tools/monitorconnection/authorize/server_test.go similarity index 98% rename from pkg/tools/monitor/authorize/server_test.go rename to pkg/tools/monitorconnection/authorize/server_test.go index fd99b6af5..5ac045ec5 100644 --- a/pkg/tools/monitor/authorize/server_test.go +++ b/pkg/tools/monitorconnection/authorize/server_test.go @@ -30,7 +30,7 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/status" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/sdk/pkg/tools/spire" diff --git a/pkg/tools/monitor/next/common_test.go b/pkg/tools/monitorconnection/next/common_test.go similarity index 100% rename from pkg/tools/monitor/next/common_test.go rename to pkg/tools/monitorconnection/next/common_test.go diff --git a/pkg/tools/monitor/next/context.go b/pkg/tools/monitorconnection/next/context.go similarity index 66% rename from pkg/tools/monitor/next/context.go rename to pkg/tools/monitorconnection/next/context.go index 24f22e1d6..14f8d4f23 100644 --- a/pkg/tools/monitor/next/context.go +++ b/pkg/tools/monitorconnection/next/context.go @@ -28,7 +28,6 @@ type contextKeyType string const ( nextMonitorConnectionServerKey contextKeyType = "NextMonitorConnectionServer" - nextMonitorConnectionClientKey contextKeyType = "NextMonitorConnectionClient" ) // withNextMonitorConnectionServer - @@ -49,22 +48,3 @@ func MonitorConnectionServer(ctx context.Context) networkservice.MonitorConnecti } return &tailMonitorConnectionsServer{} } - -// withNextMonitorConnectionClient - -// Wraps 'parent' in a new Context that has the Client networkservice.MonitorConnectionClient to be called in the chain -func withNextMonitorConnectionClient(parent context.Context, next networkservice.MonitorConnectionClient) context.Context { - if parent == nil { - panic("cannot create context from nil parent") - } - return context.WithValue(parent, nextMonitorConnectionClientKey, next) -} - -// MonitorConnectionClient - -// Returns the networkservice.MonitorConnectionClient to be called in the chain from the context.Context -func MonitorConnectionClient(ctx context.Context) networkservice.MonitorConnectionClient { - rv, ok := ctx.Value(nextMonitorConnectionClientKey).(networkservice.MonitorConnectionClient) - if ok && rv != nil { - return rv - } - return &tailMonitorConnectionClient{} -} diff --git a/pkg/tools/monitor/next/server.go b/pkg/tools/monitorconnection/next/server.go similarity index 97% rename from pkg/tools/monitor/next/server.go rename to pkg/tools/monitorconnection/next/server.go index 86ec3dd8a..adcb3ce50 100644 --- a/pkg/tools/monitor/next/server.go +++ b/pkg/tools/monitorconnection/next/server.go @@ -21,7 +21,7 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/streamcontext" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/streamcontext" ) // MonitorConnectionsServerWrapper - a function that wraps around a networkservice.MonitorConnectionServer diff --git a/pkg/tools/monitor/next/server_test.go b/pkg/tools/monitorconnection/next/server_test.go similarity index 95% rename from pkg/tools/monitor/next/server_test.go rename to pkg/tools/monitorconnection/next/server_test.go index 3e4158bfb..50d2b0066 100644 --- a/pkg/tools/monitor/next/server_test.go +++ b/pkg/tools/monitorconnection/next/server_test.go @@ -22,8 +22,8 @@ import ( "sync" "testing" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/next" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/streamcontext" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/streamcontext" "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/stretchr/testify/assert" diff --git a/pkg/tools/monitor/next/tail_client.go b/pkg/tools/monitorconnection/next/tail_client.go similarity index 100% rename from pkg/tools/monitor/next/tail_client.go rename to pkg/tools/monitorconnection/next/tail_client.go diff --git a/pkg/tools/monitor/next/tail_server.go b/pkg/tools/monitorconnection/next/tail_server.go similarity index 100% rename from pkg/tools/monitor/next/tail_server.go rename to pkg/tools/monitorconnection/next/tail_server.go diff --git a/pkg/tools/monitor/streamcontext/stream_context.go b/pkg/tools/monitorconnection/streamcontext/stream_context.go similarity index 100% rename from pkg/tools/monitor/streamcontext/stream_context.go rename to pkg/tools/monitorconnection/streamcontext/stream_context.go diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go index 9e473b84a..ecca75b47 100644 --- a/pkg/tools/opa/service_connection_policy_test.go +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/opa" ) diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index e897f70c0..951701768 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -40,7 +40,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/common/sendfd" "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/log" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitor/authorize" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) diff --git a/pkg/tools/spire/start.go b/pkg/tools/spire/start.go index b26d18fcc..7cd496d21 100644 --- a/pkg/tools/spire/start.go +++ b/pkg/tools/spire/start.go @@ -23,6 +23,8 @@ package spire import ( "context" + "crypto/x509" + "errors" "fmt" "io/ioutil" "os" @@ -33,7 +35,11 @@ import ( "github.com/edwarnicke/exechelper" "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/svid/x509svid" "github.com/spiffe/go-spiffe/v2/workloadapi" + "google.golang.org/grpc/peer" + + "github.com/networkservicemesh/sdk/pkg/tools/opa" ) type contextKeyType string @@ -273,3 +279,21 @@ func execHealthCheck(ctx context.Context, cmdStr string, options ...*exechelper. } } } + +// SpiffeIDFromContext - returns spiffe ID of the service from the peer context +func SpiffeIDFromContext(ctx context.Context) (string, error) { + p, ok := peer.FromContext(ctx) + var cert *x509.Certificate + if !ok { + return "", errors.New("fail to get peer from context") + } + cert = opa.ParseX509Cert(p.AuthInfo) + if cert != nil { + spiffeID, err := x509svid.IDFromCert(cert) + if err == nil { + return spiffeID.String(), nil + } + return "", errors.New("fail to get Spiffe ID from certificate") + } + return "", errors.New("fail to get certificate from peer") +} From f29472b35734aad625bed744d1d7e8433317a128 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 25 Jul 2022 18:19:58 +0700 Subject: [PATCH 34/39] fixes after comments Signed-off-by: anastasia.malysheva --- .../monitorconnection/authorize/server.go | 11 ++++++----- .../authorize/server_test.go | 12 ++++++++++-- pkg/tools/opa/policies.go | 2 +- .../opa/service_connection_policy_test.go | 2 +- pkg/tools/spire/gen_spiffeid_conn_map.go | 4 ++-- .../spire/spiffe_id_connection_map.gen.go | 19 ++++++++++--------- pkg/tools/spire/start.go | 11 ++++++----- 7 files changed, 36 insertions(+), 25 deletions(-) diff --git a/pkg/tools/monitorconnection/authorize/server.go b/pkg/tools/monitorconnection/authorize/server.go index 0969ac8f4..8c3141bb9 100644 --- a/pkg/tools/monitorconnection/authorize/server.go +++ b/pkg/tools/monitorconnection/authorize/server.go @@ -19,6 +19,7 @@ package authorize import ( "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" "github.com/networkservicemesh/sdk/pkg/tools/opa" @@ -33,7 +34,7 @@ type authorizeMonitorConnectionsServer struct { // NewMonitorConnectionServer - returns a new authorization networkservicemesh.MonitorConnectionServer func NewMonitorConnectionServer(opts ...Option) networkservice.MonitorConnectionServer { o := &options{ - policies: policiesList{opa.WithServiceOwnConnectionPolicy()}, + policies: policiesList{opa.WithMonitorConnectionServerPolicy()}, spiffeIDConnectionMap: &spire.SpiffeIDConnectionMap{}, } for _, opt := range opts { @@ -57,12 +58,12 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic ctx := srv.Context() simpleMap := make(map[string][]string) a.spiffeIDConnectionMap.Range( - func(sid string, connIds *spire.ConnectionIDSet) bool { + func(sid spiffeid.ID, connIds *spire.ConnectionIDSet) bool { connIds.Range( func(connId string, _ bool) bool { - ids := simpleMap[sid] + ids := simpleMap[sid.String()] ids = append(ids, connId) - simpleMap[sid] = ids + simpleMap[sid.String()] = ids return true }, ) @@ -76,7 +77,7 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic } spiffeID, _ := spire.SpiffeIDFromContext(ctx) err := a.policies.check(ctx, MonitorOpaInput{ - ServiceSpiffeID: spiffeID, + ServiceSpiffeID: spiffeID.String(), SpiffeIDConnectionMap: simpleMap, PathSegments: seg, }) diff --git a/pkg/tools/monitorconnection/authorize/server_test.go b/pkg/tools/monitorconnection/authorize/server_test.go index 5ac045ec5..6ad39d6f7 100644 --- a/pkg/tools/monitorconnection/authorize/server_test.go +++ b/pkg/tools/monitorconnection/authorize/server_test.go @@ -30,6 +30,8 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/status" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/opa" "github.com/networkservicemesh/sdk/pkg/tools/spire" @@ -177,11 +179,14 @@ func TestAuthzEndpoint(t *testing.T) { require.NoError(t, err) } spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} - for spiffeID, connIds := range s.spiffeIDConnMap { + for spiffeIDstr, connIds := range s.spiffeIDConnMap { connIDMap := spire.ConnectionIDSet{} for _, connID := range connIds { connIDMap.Store(connID, true) } + var spiffeID spiffeid.ID + spiffeID, err = spiffeid.FromString(spiffeIDstr) + require.NoError(t, err) spiffeIDConnectionMap.Store(spiffeID, &connIDMap) } ctx, cancel := context.WithTimeout(baseCtx, time.Second) @@ -225,7 +230,10 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} connMap := spire.ConnectionIDSet{} connMap.Store("conn1", true) - spiffeIDConnectionMap.Store(spiffeID1, &connMap) + var spiffeID spiffeid.ID + spiffeID, err = spiffeid.FromString(spiffeID1) + require.NoError(t, err) + spiffeIDConnectionMap.Store(spiffeID, &connMap) err = authorize.NewMonitorConnectionServer( authorize.WithSpiffeIDConnectionMap(&spiffeIDConnectionMap)).MonitorConnections( selector, &testEmptyMCMCServer{context: ctx}) diff --git a/pkg/tools/opa/policies.go b/pkg/tools/opa/policies.go index 1fe1d45a9..aac4f5c48 100644 --- a/pkg/tools/opa/policies.go +++ b/pkg/tools/opa/policies.go @@ -81,7 +81,7 @@ func WithTokensExpiredPolicy() *AuthorizationPolicy { } } -func WithServiceOwnConnectionPolicy() *AuthorizationPolicy { +func WithMonitorConnectionServerPolicy() *AuthorizationPolicy { return &AuthorizationPolicy{ policySource: tokensServiceConnectionPolicySource, query: "service_connection", diff --git a/pkg/tools/opa/service_connection_policy_test.go b/pkg/tools/opa/service_connection_policy_test.go index ecca75b47..d440f2d6f 100644 --- a/pkg/tools/opa/service_connection_policy_test.go +++ b/pkg/tools/opa/service_connection_policy_test.go @@ -27,7 +27,7 @@ import ( ) func TestWithServiceConnectionPolicy(t *testing.T) { - var p = opa.WithServiceOwnConnectionPolicy() + var p = opa.WithMonitorConnectionServerPolicy() var input = authorize.MonitorOpaInput{ PathSegments: []string{"conn1"}, SpiffeIDConnectionMap: map[string][]string{ diff --git a/pkg/tools/spire/gen_spiffeid_conn_map.go b/pkg/tools/spire/gen_spiffeid_conn_map.go index 2e4785202..694ef6c26 100644 --- a/pkg/tools/spire/gen_spiffeid_conn_map.go +++ b/pkg/tools/spire/gen_spiffeid_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap +//go:generate go-syncmap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -// SpiffeIDConnectionMap - sync.Map with key == string and value == *ConnectionIDSet +// SpiffeIDConnectionMap - sync.Map with key == spiffeid.ID and value == *ConnectionIDSet type SpiffeIDConnectionMap sync.Map diff --git a/pkg/tools/spire/spiffe_id_connection_map.gen.go b/pkg/tools/spire/spiffe_id_connection_map.gen.go index 4887d3bf5..4d89119ba 100644 --- a/pkg/tools/spire/spiffe_id_connection_map.gen.go +++ b/pkg/tools/spire/spiffe_id_connection_map.gen.go @@ -1,9 +1,10 @@ -// Code generated by "-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. -// Install -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap" +// Code generated by "-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap"; DO NOT EDIT. +// Install -output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap by "go get -u github.com/searKing/golang/tools/-output spiffe_id_connection_map.gen.go -type SpiffeIDConnectionMap" package spire import ( + "github.com/spiffe/go-spiffe/v2/spiffeid" "sync" // Used by sync.Map. ) @@ -19,7 +20,7 @@ var _nil_SpiffeIDConnectionMap_ConnectionIDSet_value = func() (val *ConnectionID // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *SpiffeIDConnectionMap) Load(key string) (*ConnectionIDSet, bool) { +func (m *SpiffeIDConnectionMap) Load(key spiffeid.ID) (*ConnectionIDSet, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, ok @@ -28,14 +29,14 @@ func (m *SpiffeIDConnectionMap) Load(key string) (*ConnectionIDSet, bool) { } // Store sets the value for a key. -func (m *SpiffeIDConnectionMap) Store(key string, value *ConnectionIDSet) { +func (m *SpiffeIDConnectionMap) Store(key spiffeid.ID, value *ConnectionIDSet) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value *ConnectionIDSet) (*ConnectionIDSet, bool) { +func (m *SpiffeIDConnectionMap) LoadOrStore(key spiffeid.ID, value *ConnectionIDSet) (*ConnectionIDSet, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, loaded @@ -45,7 +46,7 @@ func (m *SpiffeIDConnectionMap) LoadOrStore(key string, value *ConnectionIDSet) // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value *ConnectionIDSet, loaded bool) { +func (m *SpiffeIDConnectionMap) LoadAndDelete(key spiffeid.ID) (value *ConnectionIDSet, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { return _nil_SpiffeIDConnectionMap_ConnectionIDSet_value, loaded @@ -54,7 +55,7 @@ func (m *SpiffeIDConnectionMap) LoadAndDelete(key string) (value *ConnectionIDSe } // Delete deletes the value for a key. -func (m *SpiffeIDConnectionMap) Delete(key string) { +func (m *SpiffeIDConnectionMap) Delete(key spiffeid.ID) { (*sync.Map)(m).Delete(key) } @@ -68,8 +69,8 @@ func (m *SpiffeIDConnectionMap) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *SpiffeIDConnectionMap) Range(f func(key string, value *ConnectionIDSet) bool) { +func (m *SpiffeIDConnectionMap) Range(f func(key spiffeid.ID, value *ConnectionIDSet) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(*ConnectionIDSet)) + return f(key.(spiffeid.ID), value.(*ConnectionIDSet)) }) } diff --git a/pkg/tools/spire/start.go b/pkg/tools/spire/start.go index 7cd496d21..3ea394c08 100644 --- a/pkg/tools/spire/start.go +++ b/pkg/tools/spire/start.go @@ -35,6 +35,7 @@ import ( "github.com/edwarnicke/exechelper" "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/svid/x509svid" "github.com/spiffe/go-spiffe/v2/workloadapi" "google.golang.org/grpc/peer" @@ -281,19 +282,19 @@ func execHealthCheck(ctx context.Context, cmdStr string, options ...*exechelper. } // SpiffeIDFromContext - returns spiffe ID of the service from the peer context -func SpiffeIDFromContext(ctx context.Context) (string, error) { +func SpiffeIDFromContext(ctx context.Context) (spiffeid.ID, error) { p, ok := peer.FromContext(ctx) var cert *x509.Certificate if !ok { - return "", errors.New("fail to get peer from context") + return spiffeid.ID{}, errors.New("fail to get peer from context") } cert = opa.ParseX509Cert(p.AuthInfo) if cert != nil { spiffeID, err := x509svid.IDFromCert(cert) if err == nil { - return spiffeID.String(), nil + return spiffeID, nil } - return "", errors.New("fail to get Spiffe ID from certificate") + return spiffeid.ID{}, errors.New("fail to get Spiffe ID from certificate") } - return "", errors.New("fail to get certificate from peer") + return spiffeid.ID{}, errors.New("fail to get certificate from peer") } From 161fbbdb504e5d643d3dbfa7ab81159d010bbcde Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Mon, 25 Jul 2022 22:51:40 +0700 Subject: [PATCH 35/39] fixes after comments Signed-off-by: anastasia.malysheva --- pkg/networkservice/common/authorize/server.go | 7 +++-- .../monitorconnection/authorize/server.go | 2 +- .../authorize/server_test.go | 6 ++-- pkg/tools/opa/opainput.go | 2 +- pkg/tools/spire/connection_id_set.gen.go | 30 +++++++++---------- pkg/tools/spire/gen_conn_map.go | 2 +- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/pkg/networkservice/common/authorize/server.go b/pkg/networkservice/common/authorize/server.go index c6502d275..24e6add40 100644 --- a/pkg/networkservice/common/authorize/server.go +++ b/pkg/networkservice/common/authorize/server.go @@ -78,7 +78,8 @@ func (a *authorizeServer) Request(ctx context.Context, request *networkservice.N if !ok { ids = &spire.ConnectionIDSet{} } - ids.Store(connID, true) + var placer struct{} + ids.Store(connID, placer) a.spiffeIDConnectionMap.Store(spiffeID, ids) } return next.Server(ctx).Request(ctx, request) @@ -94,12 +95,12 @@ func (a *authorizeServer) Close(ctx context.Context, conn *networkservice.Connec connID := conn.GetPath().GetPathSegments()[index-1].GetId() ids, ok := a.spiffeIDConnectionMap.Load(spiffeID) if ok { - if present, ok := ids.Load(connID); present && ok { + if _, ok := ids.Load(connID); ok { ids.Delete(connID) } } idsEmpty := true - ids.Range(func(_ string, _ bool) bool { + ids.Range(func(_ string, _ struct{}) bool { idsEmpty = false return true }) diff --git a/pkg/tools/monitorconnection/authorize/server.go b/pkg/tools/monitorconnection/authorize/server.go index 8c3141bb9..ec42b88ab 100644 --- a/pkg/tools/monitorconnection/authorize/server.go +++ b/pkg/tools/monitorconnection/authorize/server.go @@ -60,7 +60,7 @@ func (a *authorizeMonitorConnectionsServer) MonitorConnections(in *networkservic a.spiffeIDConnectionMap.Range( func(sid spiffeid.ID, connIds *spire.ConnectionIDSet) bool { connIds.Range( - func(connId string, _ bool) bool { + func(connId string, _ struct{}) bool { ids := simpleMap[sid.String()] ids = append(ids, connId) simpleMap[sid.String()] = ids diff --git a/pkg/tools/monitorconnection/authorize/server_test.go b/pkg/tools/monitorconnection/authorize/server_test.go index 6ad39d6f7..5767066c6 100644 --- a/pkg/tools/monitorconnection/authorize/server_test.go +++ b/pkg/tools/monitorconnection/authorize/server_test.go @@ -182,7 +182,8 @@ func TestAuthzEndpoint(t *testing.T) { for spiffeIDstr, connIds := range s.spiffeIDConnMap { connIDMap := spire.ConnectionIDSet{} for _, connID := range connIds { - connIDMap.Store(connID, true) + var placer struct{} + connIDMap.Store(connID, placer) } var spiffeID spiffeid.ID spiffeID, err = spiffeid.FromString(spiffeIDstr) @@ -229,7 +230,8 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) { spiffeIDConnectionMap := spire.SpiffeIDConnectionMap{} connMap := spire.ConnectionIDSet{} - connMap.Store("conn1", true) + var placer struct{} + connMap.Store("conn1", placer) var spiffeID spiffeid.ID spiffeID, err = spiffeid.FromString(spiffeID1) require.NoError(t, err) diff --git a/pkg/tools/opa/opainput.go b/pkg/tools/opa/opainput.go index 24e11a5d7..87fed58a2 100644 --- a/pkg/tools/opa/opainput.go +++ b/pkg/tools/opa/opainput.go @@ -54,7 +54,7 @@ func pemEncodingX509Cert(cert *x509.Certificate) string { return string(certpem) } -// ParseX509Cert - parses x509 certificate from the passed credentials.AuthInfo +// ParseX509Cert - parses x509 certificate from the passed credentials.AuthInfo func ParseX509Cert(authInfo credentials.AuthInfo) *x509.Certificate { var peerCert *x509.Certificate diff --git a/pkg/tools/spire/connection_id_set.gen.go b/pkg/tools/spire/connection_id_set.gen.go index 1629f4a4f..1526a87c7 100644 --- a/pkg/tools/spire/connection_id_set.gen.go +++ b/pkg/tools/spire/connection_id_set.gen.go @@ -1,5 +1,5 @@ -// Code generated by "-output connection_id_set.gen.go -type ConnectionIDSet -output connection_id_set.gen.go -type ConnectionIDSet"; DO NOT EDIT. -// Install -output connection_id_set.gen.go -type ConnectionIDSet by "go get -u github.com/searKing/golang/tools/-output connection_id_set.gen.go -type ConnectionIDSet" +// Code generated by "-output connection_id_set.gen.go -type ConnectionIDSet -output connection_id_set.gen.go -type ConnectionIDSet"; DO NOT EDIT. +// Install -output connection_id_set.gen.go -type ConnectionIDSet by "go get -u github.com/searKing/golang/tools/-output connection_id_set.gen.go -type ConnectionIDSet" package spire @@ -14,43 +14,43 @@ func _() { _ = (sync.Map)(ConnectionIDSet{}) } -var _nil_ConnectionIDSet_bool_value = func() (val bool) { return }() +var _nil_ConnectionIDSet_struct___value = func() (val struct{}) { return }() // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *ConnectionIDSet) Load(key string) (bool, bool) { +func (m *ConnectionIDSet) Load(key string) (struct{}, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { - return _nil_ConnectionIDSet_bool_value, ok + return _nil_ConnectionIDSet_struct___value, ok } - return value.(bool), ok + return value.(struct{}), ok } // Store sets the value for a key. -func (m *ConnectionIDSet) Store(key string, value bool) { +func (m *ConnectionIDSet) Store(key string, value struct{}) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *ConnectionIDSet) LoadOrStore(key string, value bool) (bool, bool) { +func (m *ConnectionIDSet) LoadOrStore(key string, value struct{}) (struct{}, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { - return _nil_ConnectionIDSet_bool_value, loaded + return _nil_ConnectionIDSet_struct___value, loaded } - return actual.(bool), loaded + return actual.(struct{}), loaded } // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *ConnectionIDSet) LoadAndDelete(key string) (value bool, loaded bool) { +func (m *ConnectionIDSet) LoadAndDelete(key string) (value struct{}, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { - return _nil_ConnectionIDSet_bool_value, loaded + return _nil_ConnectionIDSet_struct___value, loaded } - return actual.(bool), loaded + return actual.(struct{}), loaded } // Delete deletes the value for a key. @@ -68,8 +68,8 @@ func (m *ConnectionIDSet) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *ConnectionIDSet) Range(f func(key string, value bool) bool) { +func (m *ConnectionIDSet) Range(f func(key string, value struct{}) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(bool)) + return f(key.(string), value.(struct{})) }) } diff --git a/pkg/tools/spire/gen_conn_map.go b/pkg/tools/spire/gen_conn_map.go index 5dca182e7..f63e7d2f5 100644 --- a/pkg/tools/spire/gen_conn_map.go +++ b/pkg/tools/spire/gen_conn_map.go @@ -20,7 +20,7 @@ import ( "sync" ) -//go:generate go-syncmap -output connection_id_set.gen.go -type ConnectionIDSet +//go:generate go-syncmap -output connection_id_set.gen.go -type ConnectionIDSet // ConnectionIDSet - sync.Map with key == string and value == bool type ConnectionIDSet sync.Map From 80bdb3175f3e70b3a65cf3e80abb5a1a6787d173 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Wed, 27 Jul 2022 12:12:57 +0700 Subject: [PATCH 36/39] Add NS and monitorConnection authorize servers by default. update tests Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 6 ++++-- pkg/networkservice/chains/nsmgr/server.go | 6 ++++-- pkg/networkservice/chains/nsmgr/suite_test.go | 7 ++++++- pkg/networkservice/chains/nsmgrproxy/server.go | 6 ++++-- pkg/networkservice/common/authorize/server_test.go | 2 +- pkg/networkservice/common/monitor/passthrough_test.go | 10 +++++++--- pkg/tools/sandbox/builder.go | 4 ++++ pkg/tools/sandbox/node.go | 4 ++++ 8 files changed, 34 insertions(+), 11 deletions(-) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index 2da549cf9..8ea0a445b 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -43,6 +43,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" + "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -107,10 +108,11 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { + spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "endpoint-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), } for _, opt := range options { opt(opts) diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index 75219bbae..fd926a374 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -59,6 +59,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -158,9 +159,10 @@ var _ Nsmgr = (*nsmgrServer)(nil) // tokenGenerator - authorization token generator // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { + spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ - authorizeServer: authorize.NewServer(authorize.Any()), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), name: "nsmgr-" + uuid.New().String(), forwarderServiceName: "forwarder", } diff --git a/pkg/networkservice/chains/nsmgr/suite_test.go b/pkg/networkservice/chains/nsmgr/suite_test.go index 294a06e5a..ba40fa500 100644 --- a/pkg/networkservice/chains/nsmgr/suite_test.go +++ b/pkg/networkservice/chains/nsmgr/suite_test.go @@ -38,6 +38,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clienturl" "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms/kernel" @@ -47,6 +48,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/utils/count" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/inject/injecterror" registryclient "github.com/networkservicemesh/sdk/pkg/registry/chains/client" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" ) @@ -171,7 +173,10 @@ func (s *nsmgrSuite) Test_SelectsRestartingEndpointUsecase() { // 2. Postpone endpoint start time.AfterFunc(time.Second, func() { serv := grpc.NewServer() - endpoint.NewServer(ctx, sandbox.GenerateTestToken).Register(serv) + endpoint.NewServer(ctx, sandbox.GenerateTestToken, + endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), + ).Register(serv) _ = serv.Serve(netListener) }) diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index 810f025a3..c9f79536f 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -51,6 +51,7 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" + "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -160,10 +161,11 @@ func WithDialTimeout(dialTimeout time.Duration) Option { // NewServer creates new proxy NSMgr func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator token.GeneratorFunc, options ...Option) nsmgr.Nsmgr { rv := new(nsmgrProxyServer) + spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "nsmgr-proxy-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.Any()), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), + authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, mapipFilePath: "map-ip.yaml", } diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index f4bb6f9a0..e47a7578e 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.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 // diff --git a/pkg/networkservice/common/monitor/passthrough_test.go b/pkg/networkservice/common/monitor/passthrough_test.go index a36a1af1f..28fec4b77 100644 --- a/pkg/networkservice/common/monitor/passthrough_test.go +++ b/pkg/networkservice/common/monitor/passthrough_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -30,10 +30,12 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clienturl" "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/null" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" ) @@ -116,7 +118,8 @@ func (m *MonitorPassThroughSuite) StartPassThroughEndpoints(connectTo *url.URL) passThroughCtx, sandbox.GenerateExpiringToken(time.Second), endpoint.WithName(name), - endpoint.WithAuthorizeServer(null.NewServer()), + endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), endpoint.WithAdditionalFunctionality( clienturl.NewServer(passThroughConnectToURL), connect.NewServer( @@ -155,7 +158,8 @@ func (m *MonitorPassThroughSuite) StartEndPoint() { m.testCtx, sandbox.GenerateExpiringToken(time.Second), endpoint.WithName(name), - endpoint.WithAuthorizeServer(null.NewServer()), + endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) m.Require().NoError(startEndpoint(m.endpointCtx, m.endpointURL, m.endpoint)) } diff --git a/pkg/tools/sandbox/builder.go b/pkg/tools/sandbox/builder.go index 8f9517eab..1181955d8 100644 --- a/pkg/tools/sandbox/builder.go +++ b/pkg/tools/sandbox/builder.go @@ -31,11 +31,13 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgr" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgrproxy" + "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/registry/chains/memory" "github.com/networkservicemesh/sdk/pkg/registry/chains/proxydns" "github.com/networkservicemesh/sdk/pkg/registry/common/dnsresolve" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" + authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -293,6 +295,8 @@ func (b *Builder) newNSMgrProxy() *NSMgrEntry { nsmgrproxy.WithListenOn(entry.URL), nsmgrproxy.WithName(entry.Name), nsmgrproxy.WithDialOptions(dialOptions...), + nsmgrproxy.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + nsmgrproxy.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, b.t, entry.URL, entry.Register) diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index 951701768..27fb2be68 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -156,6 +156,8 @@ func (n *Node) NewForwarder( ), )..., ), + endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, n.t, entry.URL, entry.Endpoint.Register) @@ -203,6 +205,8 @@ func (n *Node) NewEndpoint( entry.Endpoint = endpoint.NewServer(ctx, generatorFunc, endpoint.WithName(entry.Name), endpoint.WithAdditionalFunctionality(additionalFunctionality...), + endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), + endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, n.t, entry.URL, entry.Endpoint.Register) From d1aa80820d92bbd1c38d609a56b693315cba5fed Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Wed, 27 Jul 2022 17:28:56 +0700 Subject: [PATCH 37/39] Revert "Add NS and monitorConnection authorize servers by default. update tests" This reverts commit 011714f176c1a7cae36f8ac49c19c9831bf59a3c. Signed-off-by: anastasia.malysheva --- pkg/networkservice/chains/endpoint/server.go | 6 ++---- pkg/networkservice/chains/nsmgr/server.go | 6 ++---- pkg/networkservice/chains/nsmgr/suite_test.go | 7 +------ pkg/networkservice/chains/nsmgrproxy/server.go | 6 ++---- pkg/networkservice/common/authorize/server_test.go | 2 +- pkg/networkservice/common/monitor/passthrough_test.go | 10 +++------- pkg/tools/sandbox/builder.go | 4 ---- pkg/tools/sandbox/node.go | 4 ---- 8 files changed, 11 insertions(+), 34 deletions(-) diff --git a/pkg/networkservice/chains/endpoint/server.go b/pkg/networkservice/chains/endpoint/server.go index 8ea0a445b..2da549cf9 100644 --- a/pkg/networkservice/chains/endpoint/server.go +++ b/pkg/networkservice/chains/endpoint/server.go @@ -43,7 +43,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/next" - "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -108,11 +107,10 @@ func WithAdditionalFunctionality(additionalFunctionality ...networkservice.Netwo // NewServer - returns a NetworkServiceMesh client as a chain of the standard Client pieces plus whatever func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Endpoint { - spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "endpoint-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeServer: authorize.NewServer(authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), } for _, opt := range options { opt(opts) diff --git a/pkg/networkservice/chains/nsmgr/server.go b/pkg/networkservice/chains/nsmgr/server.go index fd926a374..75219bbae 100644 --- a/pkg/networkservice/chains/nsmgr/server.go +++ b/pkg/networkservice/chains/nsmgr/server.go @@ -59,7 +59,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/registry/core/chain" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -159,10 +158,9 @@ var _ Nsmgr = (*nsmgrServer)(nil) // tokenGenerator - authorization token generator // options - a set of Nsmgr options. func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...Option) Nsmgr { - spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ - authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeServer: authorize.NewServer(authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), name: "nsmgr-" + uuid.New().String(), forwarderServiceName: "forwarder", } diff --git a/pkg/networkservice/chains/nsmgr/suite_test.go b/pkg/networkservice/chains/nsmgr/suite_test.go index ba40fa500..294a06e5a 100644 --- a/pkg/networkservice/chains/nsmgr/suite_test.go +++ b/pkg/networkservice/chains/nsmgr/suite_test.go @@ -38,7 +38,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clienturl" "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms/kernel" @@ -48,7 +47,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/utils/count" "github.com/networkservicemesh/sdk/pkg/networkservice/utils/inject/injecterror" registryclient "github.com/networkservicemesh/sdk/pkg/registry/chains/client" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" ) @@ -173,10 +171,7 @@ func (s *nsmgrSuite) Test_SelectsRestartingEndpointUsecase() { // 2. Postpone endpoint start time.AfterFunc(time.Second, func() { serv := grpc.NewServer() - endpoint.NewServer(ctx, sandbox.GenerateTestToken, - endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), - ).Register(serv) + endpoint.NewServer(ctx, sandbox.GenerateTestToken).Register(serv) _ = serv.Serve(netListener) }) diff --git a/pkg/networkservice/chains/nsmgrproxy/server.go b/pkg/networkservice/chains/nsmgrproxy/server.go index c9f79536f..810f025a3 100644 --- a/pkg/networkservice/chains/nsmgrproxy/server.go +++ b/pkg/networkservice/chains/nsmgrproxy/server.go @@ -51,7 +51,6 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" - "github.com/networkservicemesh/sdk/pkg/tools/spire" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -161,11 +160,10 @@ func WithDialTimeout(dialTimeout time.Duration) Option { // NewServer creates new proxy NSMgr func NewServer(ctx context.Context, regURL, proxyURL *url.URL, tokenGenerator token.GeneratorFunc, options ...Option) nsmgr.Nsmgr { rv := new(nsmgrProxyServer) - spiffeIDConnMap := spire.SpiffeIDConnectionMap{} opts := &serverOptions{ name: "nsmgr-proxy-" + uuid.New().String(), - authorizeServer: authorize.NewServer(authorize.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), - authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.WithSpiffeIDConnectionMap(&spiffeIDConnMap)), + authorizeServer: authorize.NewServer(authorize.Any()), + authorizeMonitorServer: authmonitor.NewMonitorConnectionServer(authmonitor.Any()), listenOn: &url.URL{Scheme: "unix", Host: "listen.on"}, mapipFilePath: "map-ip.yaml", } diff --git a/pkg/networkservice/common/authorize/server_test.go b/pkg/networkservice/common/authorize/server_test.go index e47a7578e..f4bb6f9a0 100644 --- a/pkg/networkservice/common/authorize/server_test.go +++ b/pkg/networkservice/common/authorize/server_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Doc.ai and/or its affiliates. +// Copyright (c) 2020-2021 Doc.ai and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/networkservice/common/monitor/passthrough_test.go b/pkg/networkservice/common/monitor/passthrough_test.go index 28fec4b77..a36a1af1f 100644 --- a/pkg/networkservice/common/monitor/passthrough_test.go +++ b/pkg/networkservice/common/monitor/passthrough_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2022 Cisco and/or its affiliates. +// Copyright (c) 2021 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // @@ -30,12 +30,10 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clienturl" "github.com/networkservicemesh/sdk/pkg/networkservice/common/connect" "github.com/networkservicemesh/sdk/pkg/networkservice/common/null" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/sandbox" ) @@ -118,8 +116,7 @@ func (m *MonitorPassThroughSuite) StartPassThroughEndpoints(connectTo *url.URL) passThroughCtx, sandbox.GenerateExpiringToken(time.Second), endpoint.WithName(name), - endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), + endpoint.WithAuthorizeServer(null.NewServer()), endpoint.WithAdditionalFunctionality( clienturl.NewServer(passThroughConnectToURL), connect.NewServer( @@ -158,8 +155,7 @@ func (m *MonitorPassThroughSuite) StartEndPoint() { m.testCtx, sandbox.GenerateExpiringToken(time.Second), endpoint.WithName(name), - endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), + endpoint.WithAuthorizeServer(null.NewServer()), ) m.Require().NoError(startEndpoint(m.endpointCtx, m.endpointURL, m.endpoint)) } diff --git a/pkg/tools/sandbox/builder.go b/pkg/tools/sandbox/builder.go index 1181955d8..8f9517eab 100644 --- a/pkg/tools/sandbox/builder.go +++ b/pkg/tools/sandbox/builder.go @@ -31,13 +31,11 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgr" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/nsmgrproxy" - "github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize" "github.com/networkservicemesh/sdk/pkg/registry/chains/memory" "github.com/networkservicemesh/sdk/pkg/registry/chains/proxydns" "github.com/networkservicemesh/sdk/pkg/registry/common/dnsresolve" "github.com/networkservicemesh/sdk/pkg/tools/grpcutils" "github.com/networkservicemesh/sdk/pkg/tools/log" - authmonitor "github.com/networkservicemesh/sdk/pkg/tools/monitorconnection/authorize" "github.com/networkservicemesh/sdk/pkg/tools/token" ) @@ -295,8 +293,6 @@ func (b *Builder) newNSMgrProxy() *NSMgrEntry { nsmgrproxy.WithListenOn(entry.URL), nsmgrproxy.WithName(entry.Name), nsmgrproxy.WithDialOptions(dialOptions...), - nsmgrproxy.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - nsmgrproxy.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, b.t, entry.URL, entry.Register) diff --git a/pkg/tools/sandbox/node.go b/pkg/tools/sandbox/node.go index 27fb2be68..951701768 100644 --- a/pkg/tools/sandbox/node.go +++ b/pkg/tools/sandbox/node.go @@ -156,8 +156,6 @@ func (n *Node) NewForwarder( ), )..., ), - endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, n.t, entry.URL, entry.Endpoint.Register) @@ -205,8 +203,6 @@ func (n *Node) NewEndpoint( entry.Endpoint = endpoint.NewServer(ctx, generatorFunc, endpoint.WithName(entry.Name), endpoint.WithAdditionalFunctionality(additionalFunctionality...), - endpoint.WithAuthorizeServer(authorize.NewServer(authorize.Any())), - endpoint.WithAuthorizeMonitorServer(authmonitor.NewMonitorConnectionServer(authmonitor.Any())), ) serve(ctx, n.t, entry.URL, entry.Endpoint.Register) From 8bf6e12b8371d783d125cc0bd03cc476b1aa440b Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Fri, 22 Jul 2022 17:21:55 +0700 Subject: [PATCH 38/39] dns: fix dnsutils (#1330) * dns: use upd instead of tcp Signed-off-by: Artem Glazychev * Add tcp Signed-off-by: Artem Glazychev * Fix cache chain element Signed-off-by: Artem Glazychev Signed-off-by: anastasia.malysheva --- pkg/tools/dnsutils/cache/gen.go | 4 ++-- pkg/tools/dnsutils/cache/handler.go | 16 +++++++++++----- .../dnsutils/cache/response_writer_wrapper.go | 2 +- pkg/tools/dnsutils/cache/sync_map.gen.go | 16 ++++++++-------- pkg/tools/dnsutils/connect/handler.go | 4 ++-- pkg/tools/dnsutils/dnsconfigs/handler.go | 9 ++++----- pkg/tools/dnsutils/dnsconfigs/handler_test.go | 5 ++++- pkg/tools/dnsutils/fanout/handler.go | 6 +++--- pkg/tools/dnsutils/noloop/handler.go | 2 +- pkg/tools/dnsutils/searches/handler.go | 2 +- 10 files changed, 37 insertions(+), 29 deletions(-) diff --git a/pkg/tools/dnsutils/cache/gen.go b/pkg/tools/dnsutils/cache/gen.go index 8cca2f3a5..19e4d40e0 100644 --- a/pkg/tools/dnsutils/cache/gen.go +++ b/pkg/tools/dnsutils/cache/gen.go @@ -18,8 +18,8 @@ package cache import "sync" -//go:generate go-syncmap -output sync_map.gen.go -type msgMap +//go:generate go-syncmap -output sync_map.gen.go -type msgMap -// msgMap is like a Go map[string]*dns.Msg but is safe for concurrent use +// msgMap is like a Go map[dns.Question]*dns.Msg but is safe for concurrent use // by multiple goroutines without additional locking or coordination type msgMap sync.Map diff --git a/pkg/tools/dnsutils/cache/handler.go b/pkg/tools/dnsutils/cache/handler.go index 644fb6607..da1032b7b 100644 --- a/pkg/tools/dnsutils/cache/handler.go +++ b/pkg/tools/dnsutils/cache/handler.go @@ -19,6 +19,7 @@ package cache import ( "context" + "sync" "time" "github.com/miekg/dns" @@ -29,24 +30,27 @@ import ( ) type dnsCacheHandler struct { - cache *msgMap + cache *msgMap + lastTTLUpdate time.Time + m sync.Mutex } func (h *dnsCacheHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m *dns.Msg) { h.updateTTL() - if v, ok := h.cache.Load(m.Question[0].Name); ok { + if val, ok := h.cache.Load(m.Question[0]); ok { + v := val.Copy() if validateMsg(v) { v.Id = m.Id if err := rw.WriteMsg(v); err != nil { - log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + log.FromContext(ctx).WithField("dnsCacheHandler", "ServeDNS").Warnf("got an error during write the message: %v", err.Error()) dns.HandleFailed(rw, v) return } return } - h.cache.Delete(m.Question[0].Name) + h.cache.Delete(m.Question[0]) } wrapper := responseWriterWrapper{ @@ -59,13 +63,15 @@ func (h *dnsCacheHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, m func (h *dnsCacheHandler) updateTTL() { now := time.Now() + h.m.Lock() + defer h.m.Unlock() diff := uint32(now.Sub(h.lastTTLUpdate).Seconds()) if diff == 0 { return } - h.cache.Range(func(key string, value *dns.Msg) bool { + h.cache.Range(func(key dns.Question, value *dns.Msg) bool { for i := range value.Answer { if value.Answer[i].Header().Ttl < diff { value.Answer[i].Header().Ttl = 0 diff --git a/pkg/tools/dnsutils/cache/response_writer_wrapper.go b/pkg/tools/dnsutils/cache/response_writer_wrapper.go index 9646ab7aa..d731e4b65 100644 --- a/pkg/tools/dnsutils/cache/response_writer_wrapper.go +++ b/pkg/tools/dnsutils/cache/response_writer_wrapper.go @@ -27,7 +27,7 @@ type responseWriterWrapper struct { func (r *responseWriterWrapper) WriteMsg(m *dns.Msg) error { if m != nil && m.Rcode == dns.RcodeSuccess { - r.cache.Store(m.Question[0].Name, m) + r.cache.Store(m.Question[0], m) } return r.ResponseWriter.WriteMsg(m) } diff --git a/pkg/tools/dnsutils/cache/sync_map.gen.go b/pkg/tools/dnsutils/cache/sync_map.gen.go index 01a69d1d1..34a919e36 100644 --- a/pkg/tools/dnsutils/cache/sync_map.gen.go +++ b/pkg/tools/dnsutils/cache/sync_map.gen.go @@ -1,4 +1,4 @@ -// Code generated by "-output sync_map.gen.go -type msgMap -output sync_map.gen.go -type msgMap"; DO NOT EDIT. +// Code generated by "-output sync_map.gen.go -type msgMap -output sync_map.gen.go -type msgMap"; DO NOT EDIT. package cache import ( @@ -19,7 +19,7 @@ var _nil_msgMap_dns_Msg_value = func() (val *dns.Msg) { return }() // Load returns the value stored in the map for a key, or nil if no // value is present. // The ok result indicates whether value was found in the map. -func (m *msgMap) Load(key string) (*dns.Msg, bool) { +func (m *msgMap) Load(key dns.Question) (*dns.Msg, bool) { value, ok := (*sync.Map)(m).Load(key) if value == nil { return _nil_msgMap_dns_Msg_value, ok @@ -28,14 +28,14 @@ func (m *msgMap) Load(key string) (*dns.Msg, bool) { } // Store sets the value for a key. -func (m *msgMap) Store(key string, value *dns.Msg) { +func (m *msgMap) Store(key dns.Question, value *dns.Msg) { (*sync.Map)(m).Store(key, value) } // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The loaded result is true if the value was loaded, false if stored. -func (m *msgMap) LoadOrStore(key string, value *dns.Msg) (*dns.Msg, bool) { +func (m *msgMap) LoadOrStore(key dns.Question, value *dns.Msg) (*dns.Msg, bool) { actual, loaded := (*sync.Map)(m).LoadOrStore(key, value) if actual == nil { return _nil_msgMap_dns_Msg_value, loaded @@ -45,7 +45,7 @@ func (m *msgMap) LoadOrStore(key string, value *dns.Msg) (*dns.Msg, bool) { // LoadAndDelete deletes the value for a key, returning the previous value if any. // The loaded result reports whether the key was present. -func (m *msgMap) LoadAndDelete(key string) (value *dns.Msg, loaded bool) { +func (m *msgMap) LoadAndDelete(key dns.Question) (value *dns.Msg, loaded bool) { actual, loaded := (*sync.Map)(m).LoadAndDelete(key) if actual == nil { return _nil_msgMap_dns_Msg_value, loaded @@ -54,7 +54,7 @@ func (m *msgMap) LoadAndDelete(key string) (value *dns.Msg, loaded bool) { } // Delete deletes the value for a key. -func (m *msgMap) Delete(key string) { +func (m *msgMap) Delete(key dns.Question) { (*sync.Map)(m).Delete(key) } @@ -68,8 +68,8 @@ func (m *msgMap) Delete(key string) { // // Range may be O(N) with the number of elements in the map even if f returns // false after a constant number of calls. -func (m *msgMap) Range(f func(key string, value *dns.Msg) bool) { +func (m *msgMap) Range(f func(key dns.Question, value *dns.Msg) bool) { (*sync.Map)(m).Range(func(key, value interface{}) bool { - return f(key.(string), value.(*dns.Msg)) + return f(key.(dns.Question), value.(*dns.Msg)) }) } diff --git a/pkg/tools/dnsutils/connect/handler.go b/pkg/tools/dnsutils/connect/handler.go index beaad4a68..907e815fd 100644 --- a/pkg/tools/dnsutils/connect/handler.go +++ b/pkg/tools/dnsutils/connect/handler.go @@ -44,13 +44,13 @@ func (c *connectDNSHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, var resp, _, err = client.Exchange(msg, c.connectTO.Host) if err != nil { - log.FromContext(ctx).Warnf("got an error during exchanging: %v", err.Error()) + log.FromContext(ctx).WithField("connectDNSHandler", "ServeDNS").Warnf("got an error during exchanging: %v", err.Error()) dns.HandleFailed(rp, msg) return } if err = rp.WriteMsg(resp); err != nil { - log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + log.FromContext(ctx).WithField("connectDNSHandler", "ServeDNS").Warnf("got an error during write the message: %v", err.Error()) dns.HandleFailed(rp, msg) return } diff --git a/pkg/tools/dnsutils/dnsconfigs/handler.go b/pkg/tools/dnsutils/dnsconfigs/handler.go index 275a01b8b..05c05d3fe 100644 --- a/pkg/tools/dnsutils/dnsconfigs/handler.go +++ b/pkg/tools/dnsutils/dnsconfigs/handler.go @@ -42,12 +42,11 @@ func (h *dnsConfigsHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, h.configs.Range(func(key string, value []*networkservice.DNSConfig) bool { for _, conf := range value { - ips := make([]url.URL, len(conf.DnsServerIps)) - for i, ip := range conf.DnsServerIps { - ips[i] = url.URL{Scheme: "tcp", Host: ip} + for _, ip := range conf.DnsServerIps { + dnsIPs = append(dnsIPs, + url.URL{Scheme: "udp", Host: ip}, + url.URL{Scheme: "tcp", Host: ip}) } - - dnsIPs = append(dnsIPs, ips...) searchDomains = append(searchDomains, conf.SearchDomains...) } diff --git a/pkg/tools/dnsutils/dnsconfigs/handler_test.go b/pkg/tools/dnsutils/dnsconfigs/handler_test.go index da3eb0c07..8abd74fc8 100644 --- a/pkg/tools/dnsutils/dnsconfigs/handler_test.go +++ b/pkg/tools/dnsutils/dnsconfigs/handler_test.go @@ -86,8 +86,11 @@ func TestDNSConfigs(t *testing.T) { require.Contains(t, domains, "net") urls := check.URLs - require.Equal(t, len(urls), 3) + require.Equal(t, len(urls), 6) + require.Contains(t, urls, "udp://7.7.7.7") require.Contains(t, urls, "tcp://7.7.7.7") + require.Contains(t, urls, "udp://1.1.1.1") require.Contains(t, urls, "tcp://1.1.1.1") + require.Contains(t, urls, "udp://9.9.9.9") require.Contains(t, urls, "tcp://9.9.9.9") } diff --git a/pkg/tools/dnsutils/fanout/handler.go b/pkg/tools/dnsutils/fanout/handler.go index a598e7c30..4a01be8e6 100644 --- a/pkg/tools/dnsutils/fanout/handler.go +++ b/pkg/tools/dnsutils/fanout/handler.go @@ -43,7 +43,7 @@ func (h *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg timeout := time.Until(deadline) if len(connectTO) == 0 { - log.FromContext(ctx).Error("no urls to fanout") + log.FromContext(ctx).WithField("fanoutHandler", "ServeDNS").Error("no urls to fanout") dns.HandleFailed(rw, msg) return } @@ -62,7 +62,7 @@ func (h *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg var resp, _, err = client.Exchange(msg, address) if err != nil { - log.FromContext(ctx).Warnf("got an error during exchanging: %v", err.Error()) + log.FromContext(ctx).WithField("fanoutHandler", "ServeDNS").Warnf("got an error during exchanging with address %v: %v", address, err.Error()) responseCh <- nil return } @@ -79,7 +79,7 @@ func (h *fanoutHandler) ServeDNS(ctx context.Context, rw dns.ResponseWriter, msg } if err := rw.WriteMsg(resp); err != nil { - log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + log.FromContext(ctx).WithField("fanoutHandler", "ServeDNS").Warnf("got an error during write the message: %v", err.Error()) dns.HandleFailed(rw, msg) return } diff --git a/pkg/tools/dnsutils/noloop/handler.go b/pkg/tools/dnsutils/noloop/handler.go index ceff25bb4..061831ab0 100644 --- a/pkg/tools/dnsutils/noloop/handler.go +++ b/pkg/tools/dnsutils/noloop/handler.go @@ -33,7 +33,7 @@ type noloopDNSHandler struct{ ids sync.Map } func (n *noloopDNSHandler) ServeDNS(ctx context.Context, rp dns.ResponseWriter, m *dns.Msg) { if _, loaded := n.ids.LoadOrStore(m.Id, struct{}{}); loaded { - log.FromContext(ctx).Errorf("loop is not allowed: query: %v", m.String()) + log.FromContext(ctx).WithField("noloopDNSHandler", "ServeDNS").Errorf("loop is not allowed: query: %v", m.String()) dns.HandleFailed(rp, m) return } diff --git a/pkg/tools/dnsutils/searches/handler.go b/pkg/tools/dnsutils/searches/handler.go index d61056be0..2ae7dcdff 100644 --- a/pkg/tools/dnsutils/searches/handler.go +++ b/pkg/tools/dnsutils/searches/handler.go @@ -59,7 +59,7 @@ func (h *searchDomainsHandler) ServeDNS(ctx context.Context, rw dns.ResponseWrit if resp != nil && resp.Rcode == dns.RcodeSuccess { resp.Question = m.Question if err := rw.WriteMsg(resp); err != nil { - log.FromContext(ctx).Warnf("got an error during write the message: %v", err.Error()) + log.FromContext(ctx).WithField("searchDomainsHandler", "ServeDNS").Warnf("got an error during write the message: %v", err.Error()) dns.HandleFailed(rw, resp) return } From dc225995427997ab6db728331db8ca9af70d1921 Mon Sep 17 00:00:00 2001 From: "anastasia.malysheva" Date: Wed, 27 Jul 2022 18:39:34 +0700 Subject: [PATCH 39/39] Resolve conflict Signed-off-by: anastasia.malysheva --- .../monitor/monitor_connection_server.go | 2 +- pkg/networkservice/common/monitor/server.go | 69 +++---------------- 2 files changed, 9 insertions(+), 62 deletions(-) diff --git a/pkg/networkservice/common/monitor/monitor_connection_server.go b/pkg/networkservice/common/monitor/monitor_connection_server.go index 8e31bf8bb..00f814793 100644 --- a/pkg/networkservice/common/monitor/monitor_connection_server.go +++ b/pkg/networkservice/common/monitor/monitor_connection_server.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Cisco and/or its affiliates. +// Copyright (c) 2021-2022 Cisco and/or its affiliates. // // SPDX-License-Identifier: Apache-2.0 // diff --git a/pkg/networkservice/common/monitor/server.go b/pkg/networkservice/common/monitor/server.go index bbe4a7a51..f56c32a90 100644 --- a/pkg/networkservice/common/monitor/server.go +++ b/pkg/networkservice/common/monitor/server.go @@ -23,7 +23,6 @@ package monitor import ( "context" - "github.com/edwarnicke/serialize" "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" @@ -37,10 +36,7 @@ import ( ) type monitorServer struct { - chainCtx context.Context - filters map[string]*monitorFilter - executor serialize.Executor - connections map[string]*networkservice.Connection + chainCtx context.Context networkservice.MonitorConnectionServer } @@ -54,15 +50,11 @@ type monitorServer struct { // networkservice.MonitorConnectionServer chain // chainCtx - context for lifecycle management func NewServer(chainCtx context.Context, monitorServerPtr *networkservice.MonitorConnectionServer) networkservice.NetworkServiceServer { - var rv = monitorServer{ + *monitorServerPtr = newMonitorConnectionServer(chainCtx) + return &monitorServer{ chainCtx: chainCtx, MonitorConnectionServer: *monitorServerPtr, - filters: make(map[string]*monitorFilter), - executor: serialize.Executor{}, - connections: make(map[string]*networkservice.Connection), } - *monitorServerPtr = newMonitorConnectionServer(rv.chainCtx, &rv.executor, rv.filters, rv.connections) - return &rv } func (m *monitorServer) Request(ctx context.Context, request *networkservice.NetworkServiceRequest) (*networkservice.Connection, error) { @@ -72,12 +64,13 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net cancelEventLoop() } + storeEventConsumer(ctx, metadata.IsClient(m), m.MonitorConnectionServer.(EventConsumer)) + conn, err := next.Server(ctx).Request(ctx, request) if err != nil { return nil, err } - - _ = m.Send(&networkservice.ConnectionEvent{ + _ = m.MonitorConnectionServer.(EventConsumer).Send(&networkservice.ConnectionEvent{ Type: networkservice.ConnectionEventType_UPDATE, Connections: map[string]*networkservice.Connection{conn.GetId(): conn.Clone()}, }) @@ -86,7 +79,7 @@ func (m *monitorServer) Request(ctx context.Context, request *networkservice.Net // events through from, so start an eventLoop cc, ccLoaded := clientconn.Load(ctx) if ccLoaded { - cancelEventLoop, eventLoopErr := newEventLoop(m.chainCtx, m, cc, conn) + cancelEventLoop, eventLoopErr := newEventLoop(m.chainCtx, m.MonitorConnectionServer.(EventConsumer), cc, conn) if eventLoopErr != nil { closeCtx, closeCancel := closeCtxFunc() defer closeCancel() @@ -104,56 +97,10 @@ func (m *monitorServer) Close(ctx context.Context, conn *networkservice.Connecti if cancelEventLoop, loaded := loadAndDelete(ctx, metadata.IsClient(m)); loaded { cancelEventLoop() } - rv, err := next.Server(ctx).Close(ctx, conn) - _ = m.Send(&networkservice.ConnectionEvent{ + _ = m.MonitorConnectionServer.(EventConsumer).Send(&networkservice.ConnectionEvent{ Type: networkservice.ConnectionEventType_DELETE, Connections: map[string]*networkservice.Connection{conn.GetId(): conn.Clone()}, }) return rv, err } - -func (m *monitorServer) Send(event *networkservice.ConnectionEvent) (_ error) { - m.executor.AsyncExec(func() { - if event.Type == networkservice.ConnectionEventType_UPDATE { - for _, conn := range event.GetConnections() { - m.connections[conn.GetId()] = conn.Clone() - } - } - if event.Type == networkservice.ConnectionEventType_DELETE { - for _, conn := range event.GetConnections() { - delete(m.connections, conn.GetId()) - } - } - if event.Type == networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER { - // sending event with INIITIAL_STATE_TRANSFER not permitted - return - } - for id, filter := range m.filters { - id, filter := id, filter - e := event.Clone() - filter.executor.AsyncExec(func() { - var err error - select { - case <-filter.Context().Done(): - m.executor.AsyncExec(func() { - delete(m.filters, id) - }) - default: - err = filter.Send(e) - } - if err != nil { - m.executor.AsyncExec(func() { - delete(m.filters, id) - }) - } - }) - } - }) - return nil -} - -// EventConsumer - interface for monitor events sending -type EventConsumer interface { - Send(event *networkservice.ConnectionEvent) (err error) -}