<commit_before>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 main

import (
	"context"
	"fmt"
	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/connectioncontext"
	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/local/connection"
	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/local/networkservice"
	"github.com/ligato/networkservicemesh/controlplane/pkg/nsmd"
	"github.com/ligato/networkservicemesh/pkg/tools"
	"github.com/sirupsen/logrus"
	"os"
	"sync"
	"time"
)

const (
	nsEnv        = "NETWORK_SERVICES"
	nscLabelsEnv = "NSC_LABELS"
	attemptsMax  = 10
)

func newNetworkServiceRequest(networkServiceName string, nsLabels map[string]string, intf string, netns string) *networkservice.NetworkServiceRequest {
	return &networkservice.NetworkServiceRequest{
		Connection: &connection.Connection{
			NetworkService: networkServiceName,
			Context: &connectioncontext.ConnectionContext{
				SrcIpRequired: true,
				DstIpRequired: true,
			},
			Labels: nsLabels,
		},
		MechanismPreferences: []*connection.Mechanism{
			{
				Type: connection.MechanismType_KERNEL_INTERFACE,
				Parameters: map[string]string{
					connection.NetNsInodeKey:    netns,
					connection.InterfaceNameKey: intf,
				},
			},
		},
	}
}

func main() {
	// For NSC to program container's dataplane, container's linux namespace must be sent to NSM
	netns, err := tools.GetCurrentNS()
	if err != nil {
		logrus.Fatalf("nsc: failed to get a linux namespace with error: %+v, exiting...", err)
		os.Exit(101)
	}
	logrus.Infof("Starting NSC, linux namespace: %s...", netns)

	networkServices, ok := os.LookupEnv(nsEnv)
	if !ok {
		logrus.Infof("nsc: no services to connect, exiting...")
		os.Exit(0)
	}

	nscLabels, ok := os.LookupEnv(nscLabelsEnv)
	if !ok {
		logrus.Infof("nsc: no services to connect, exiting...")
	}

	// Init related activities start here
	logrus.Info("Connecting to nsm server on socket")
	nsmConnectionClient, conn, err := nsmd.NewNetworkServiceClient()
	if err != nil {
		logrus.Fatalf("nsc: failed to connect with NSMD: %+v, exiting...", err)
		os.Exit(101)
	}
	defer conn.Close()

	nsConfig := tools.ParseKVStringToMap(networkServices, ",", ":")
	nsLabels := tools.ParseKVStringToMap(nscLabels, ",", "=")

	var requests []*networkservice.NetworkServiceRequest

	for intf, ns := range nsConfig {
		requests = append(requests, newNetworkServiceRequest(ns, nsLabels, intf, netns))
	}

	errorCh := make(chan error)
	waitCh := make(chan struct{})

	go func() {
		var wg sync.WaitGroup

		for _, r := range requests {
			wg.Add(1)
			go func(r *networkservice.NetworkServiceRequest, errorCh chan<- error) {
				logrus.Infof("start goroutine for requesting connection with %v", r.Connection.NetworkService)
				defer wg.Done()
				attempt := 0
				for attempt < attemptsMax {
					<-time.Tick(time.Second)

					attempt++
					logrus.Infof("Sending request %v", r)
					reply, err := nsmConnectionClient.Request(context.Background(), r)
					if err != nil {
						logrus.Errorf("failure to request connection with error: %+v", err)
						continue
					}
					logrus.Infof("Received reply: %v", reply)
					return
				}
				errorCh <- fmt.Errorf("unable to setup connection with %v after %v attempts",
					r.Connection.NetworkService, attempt)
			}(r, errorCh)
		}

		wg.Wait()
		close(waitCh)
	}()

	select {
	case err := <-errorCh:
		logrus.Error(err)
		os.Exit(1)
	case <-waitCh:
		logrus.Info("nsm client: initialization is completed successfully")
	}
}<commit_msg>adding timeout, fixes #652 (#653)<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 main

import (
	"context"
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/connectioncontext"
	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/local/connection"
	"github.com/ligato/networkservicemesh/controlplane/pkg/apis/local/networkservice"
	"github.com/ligato/networkservicemesh/controlplane/pkg/nsmd"
	"github.com/ligato/networkservicemesh/pkg/tools"
	"github.com/sirupsen/logrus"
)

const (
	nsEnv        = "NETWORK_SERVICES"
	nscLabelsEnv = "NSC_LABELS"
	attemptsMax  = 10
)

func newNetworkServiceRequest(networkServiceName string, nsLabels map[string]string, intf string, netns string) *networkservice.NetworkServiceRequest {
	return &networkservice.NetworkServiceRequest{
		Connection: &connection.Connection{
			NetworkService: networkServiceName,
			Context: &connectioncontext.ConnectionContext{
				SrcIpRequired: true,
				DstIpRequired: true,
			},
			Labels: nsLabels,
		},
		MechanismPreferences: []*connection.Mechanism{
			{
				Type: connection.MechanismType_KERNEL_INTERFACE,
				Parameters: map[string]string{
					connection.NetNsInodeKey:    netns,
					connection.InterfaceNameKey: intf,
				},
			},
		},
	}
}

func main() {
	// For NSC to program container's dataplane, container's linux namespace must be sent to NSM
	netns, err := tools.GetCurrentNS()
	if err != nil {
		logrus.Fatalf("nsc: failed to get a linux namespace with error: %+v, exiting...", err)
		os.Exit(101)
	}
	logrus.Infof("Starting NSC, linux namespace: %s...", netns)

	networkServices, ok := os.LookupEnv(nsEnv)
	if !ok {
		logrus.Infof("nsc: no services to connect, exiting...")
		os.Exit(0)
	}

	nscLabels, ok := os.LookupEnv(nscLabelsEnv)
	if !ok {
		logrus.Infof("nsc: no services to connect, exiting...")
	}

	// Init related activities start here
	logrus.Info("Connecting to nsm server on socket")
	nsmConnectionClient, conn, err := nsmd.NewNetworkServiceClient()
	if err != nil {
		logrus.Fatalf("nsc: failed to connect with NSMD: %+v, exiting...", err)
		os.Exit(101)
	}
	defer conn.Close()

	nsConfig := tools.ParseKVStringToMap(networkServices, ",", ":")
	nsLabels := tools.ParseKVStringToMap(nscLabels, ",", "=")

	var requests []*networkservice.NetworkServiceRequest

	for intf, ns := range nsConfig {
		requests = append(requests, newNetworkServiceRequest(ns, nsLabels, intf, netns))
	}

	errorCh := make(chan error)
	waitCh := make(chan struct{})

	go func() {
		var wg sync.WaitGroup

		for _, r := range requests {
			wg.Add(1)
			go func(r *networkservice.NetworkServiceRequest, errorCh chan<- error) {
				logrus.Infof("start goroutine for requesting connection with %v", r.Connection.NetworkService)
				defer wg.Done()
				attempt := 0
				for attempt < attemptsMax {
					<-time.Tick(time.Second)

					attempt++
					logrus.Infof("Sending request %v", r)
					ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
					defer cancel()
					reply, err := nsmConnectionClient.Request(ctx, r)
					if err != nil {
						logrus.Errorf("failure to request connection with error: %+v", err)
						continue
					}
					logrus.Infof("Received reply: %v", reply)
					return
				}
				errorCh <- fmt.Errorf("unable to setup connection with %v after %v attempts",
					r.Connection.NetworkService, attempt)
			}(r, errorCh)
		}

		wg.Wait()
		close(waitCh)
	}()

	select {
	case err := <-errorCh:
		logrus.Error(err)
		os.Exit(1)
	case <-waitCh:
		logrus.Info("nsm client: initialization is completed successfully")
	}
}
{'fraction_non_alphanumeric': 0.12334587835376958, 'fraction_numerical': 0.005705960908097609, 'mean_word_length': 3.9123434704830053, 'pattern_counts': {'":': 2, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2190664', 'n_tokens_mistral': 2995, 'n_tokens_neox': 2656, 'n_words': 704}