Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: Denis Tingaikin <denis.tingajkin@xored.com>
  • Loading branch information
denis-tingaikin committed Apr 24, 2021
1 parent 5c10e50 commit 0360ac6
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 232 deletions.
80 changes: 80 additions & 0 deletions pkg/networkservice/chains/nsmgr/nsmgr_single_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 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 nsmgr_test

import (
"context"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/stretchr/testify/require"

"github.com/networkservicemesh/sdk/pkg/networkservice/connectioncontext/dnscontext"
"github.com/networkservicemesh/sdk/pkg/tools/sandbox"
)

func Test_DNSUsecase(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()

var cluster = sandbox.NewBuilder(t).SetNodesCount(1).SetNSMgrProxySupplier(nil).SetRegistryProxySupplier(nil).SetContext(ctx).Build()

_, err := cluster.Nodes[0].NewEndpoint(ctx, defaultRegistryEndpoint(), 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"},
},
))
require.NoError(t, err)

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\tforward . 8.8.4.4\n\tlog\n\treload\n}\nmy.domain1 {\n\tfanout . 8.8.8.8 8.8.4.4\n\tlog\n}"

client := cluster.Nodes[0].NewClient(ctx, sandbox.GenerateTestToken, dnscontext.NewClient(
dnscontext.WithCorefilePath(corefilePath),
dnscontext.WithResolveConfigPath(resolveConfigPath)),
)

resp, err := client.Request(ctx, defaultRequest())
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 = client.Close(ctx, resp)
require.NoError(t, err)
_, err = cluster.Nodes[0].EndpointRegistryClient.Unregister(ctx, defaultRegistryEndpoint())
require.NoError(t, err)
}
87 changes: 31 additions & 56 deletions pkg/networkservice/connectioncontext/dnscontext/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,31 @@ import (
"io/ioutil"
"os"

"github.com/edwarnicke/serialize"

"github.com/networkservicemesh/sdk/pkg/tools/log"

"github.com/golang/protobuf/ptypes/empty"
"github.com/networkservicemesh/api/pkg/api/networkservice"
"google.golang.org/grpc"

"github.com/edwarnicke/serialize"

"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/tools/dnscontext"
)

type dnsContextClient struct {
cancelMonitoring context.CancelFunc
chainContext context.Context
monitorContext context.Context
requestContext context.Context
coreFilePath string
resolveConfigPath string
defaultNameServerIP string
monitorCallOptions []grpc.CallOption
dnsConfigManager dnscontext.Manager
monitorClient networkservice.MonitorConnectionClient
executor serialize.Executor
updateCorefileQueue serialize.Executor
}

// NewClient creates a new DNS client chain component. Setups all DNS traffic to the localhost. Monitors DNS configs from connections.
func NewClient(monitorClient networkservice.MonitorConnectionClient, options ...DNSOption) networkservice.NetworkServiceClient {
func NewClient(options ...DNSOption) networkservice.NetworkServiceClient {
c := &dnsContextClient{
chainContext: context.Background(),
dnsConfigManager: dnscontext.NewManager(),
monitorClient: monitorClient,
defaultNameServerIP: "127.0.0.1",
resolveConfigPath: "/etc/resolv.conf",
coreFilePath: "/etc/coredns/Corefile",
Expand All @@ -61,18 +54,21 @@ func NewClient(monitorClient networkservice.MonitorConnectionClient, options ...
o.apply(c)
}

if r, err := dnscontext.OpenResolveConfig(c.resolveConfigPath); err != nil {
log.FromContext(c.chainContext).Errorf("DnsContextClient: can not load resolve config file. Path: %v. Error: %v", c.resolveConfigPath, err.Error())
} else {
if r, err := dnscontext.OpenResolveConfig(c.resolveConfigPath); err == nil {
c.dnsConfigManager.Store("", &networkservice.DNSConfig{
SearchDomains: r.Value(dnscontext.AnyDomain),
DnsServerIps: r.Value(dnscontext.NameserverProperty),
})
r.SetValue(dnscontext.NameserverProperty, c.defaultNameServerIP)
if err := r.Save(); err != nil {
log.FromContext(c.chainContext).Errorf("DnsContextClient: can not update resolve config file. Error: %v", err.Error())
if err = r.Save(); err != nil {
log.FromContext(c.chainContext).Fatalf("DnsContextClient: can not update resolve config file. Error: %v", err.Error())
}
} else {
log.FromContext(c.chainContext).Fatalf("DnsContextClient: can not load resolve config file. Path: %v. Error: %v", c.resolveConfigPath, err.Error())
}

c.updateCorefileQueue.AsyncExec(c.updateCorefile)

return c
}

Expand All @@ -81,53 +77,32 @@ func (c *dnsContextClient) Request(ctx context.Context, request *networkservice.
if err != nil {
return nil, err
}
c.requestContext = ctx
c.executor.AsyncExec(c.monitorConfigs)
var conifgs []*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)
}
return rv, err
}

func (c *dnsContextClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
r, err := next.Client(ctx).Close(ctx, conn, opts...)
func (c *dnsContextClient) updateCorefile() {
err := ioutil.WriteFile(c.coreFilePath, []byte(c.dnsConfigManager.String()), os.ModePerm)
if err != nil {
return nil, err
log.FromContext(c.chainContext).Errorf("An error during update corefile: %v", err.Error())
}
c.cancelMonitoring()
return r, err
}

func (c *dnsContextClient) monitorConfigs() {
c.monitorContext, c.cancelMonitoring = context.WithCancel(c.chainContext)
steam, err := c.monitorClient.MonitorConnections(c.monitorContext, &networkservice.MonitorScopeSelector{}, c.monitorCallOptions...)
if err != nil {
log.FromContext(c.requestContext).Errorf("DnsContextClient: Can not start monitor connections: %v", err)
c.executor.AsyncExec(c.monitorConfigs)
return
}
for {
if c.monitorContext.Err() != nil {
return
}
event, err := steam.Recv()
if err != nil {
c.executor.AsyncExec(c.monitorConfigs)
return
}
c.handleEvent(event)
v := c.dnsConfigManager.String()
log.FromContext(c.requestContext).Info(v)
_ = ioutil.WriteFile(c.coreFilePath, []byte(v), os.ModePerm)
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()
}
}

func (c *dnsContextClient) handleEvent(event *networkservice.ConnectionEvent) {
switch event.GetType() {
case networkservice.ConnectionEventType_INITIAL_STATE_TRANSFER, networkservice.ConnectionEventType_UPDATE:
for k, v := range event.Connections {
c.dnsConfigManager.Store(k, v.GetContext().GetDnsContext().GetConfigs()...)
}
case networkservice.ConnectionEventType_DELETE:
for k := range event.Connections {
c.dnsConfigManager.Remove(k)
}
if len(conifgs) > 0 {
c.dnsConfigManager.Remove(conn.GetId())
c.updateCorefileQueue.AsyncExec(c.updateCorefile)
}
return next.Client(ctx).Close(ctx, conn, opts...)
}
Loading

0 comments on commit 0360ac6

Please sign in to comment.