<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/juju/utils/clock"
)

// Bridger creates network bridges to support addressable containers.
type Bridger interface {
	// Turns existing devices into bridged devices.
	Bridge(deviceNames []string) error
}

type etcNetworkInterfacesBridger struct {
	BridgePrefix string
	Clock        clock.Clock
	DryRun       bool
	Environ      []string
	Filename     string
	Timeout      time.Duration
}

var _ Bridger = (*etcNetworkInterfacesBridger)(nil)

// bestPythonVersion returns a string to the best python interpreter
// found.
//
// For ubuntu series < xenial we prefer python2 over python3 as we
// don't want to invalidate lots of testing against known cloud-image
// contents. A summary of Ubuntu releases and python inclusion in the
// default install of Ubuntu Server is as follows:
//
// 12.04 precise:  python 2 (2.7.3)
// 14.04 trusty:   python 2 (2.7.5) and python3 (3.4.0)
// 14.10 utopic:   python 2 (2.7.8) and python3 (3.4.2)
// 15.04 vivid:    python 2 (2.7.9) and python3 (3.4.3)
// 15.10 wily:     python 2 (2.7.9) and python3 (3.4.3)
// 16.04 xenial:   python 3 only (3.5.1)
//
// going forward:  python 3 only
func bestPythonVersion() string {
	for _, version := range []string{
		"/usr/bin/python2",
		"/usr/bin/python3",
		"/usr/bin/python",
	} {
		if _, err := os.Stat(version); err == nil {
			return version
		}
	}
	return ""
}

func (b *etcNetworkInterfacesBridger) Bridge(deviceNames []string) error {
	cmd := bridgeCmd(deviceNames, b.BridgePrefix, b.Filename, BridgeScriptPythonContent, b.DryRun)
	debugCmd := bridgeCmd(deviceNames, b.BridgePrefix, b.Filename, "<script-redacted>", b.DryRun)
	logger.Debugf("bridgescript command=%s", debugCmd)
	result, err := runCommand(cmd, b.Environ, b.Clock, b.Timeout)
	if err != nil {
		return errors.Errorf("script invocation error: %s", err)
	}
	logger.Infof("bridgescript result=%v, timeout=%v", result.Code, result.TimedOut)
	if result.TimedOut {
		return errors.Errorf("bridgescript timed out after %v", b.Timeout)
	}
	if result.Code != 0 {
		logger.Errorf("bridgescript stdout\n%s\n", result.Stdout)
		logger.Errorf("bridgescript stderr\n%s\n", result.Stderr)
		return errors.Errorf("bridgescript failed: %s", string(result.Stderr))
	}
	logger.Debugf("bridgescript stdout\n%s\n", result.Stdout)
	logger.Debugf("bridgescript stderr\n%s\n", result.Stderr)
	return nil
}

func bridgeCmd(deviceNames []string, bridgePrefix, filename, pythonScript string, dryRun bool) string {
	dryRunOption := ""

	if bridgePrefix != "" {
		bridgePrefix = fmt.Sprintf("--bridge-prefix=%s", bridgePrefix)
	}

	if dryRun {
		dryRunOption = "--dry-run"
	}

	return fmt.Sprintf(`
%s - --interfaces-to-bridge=%q --activate %s %s %s <<'EOF'
%s
EOF
`[1:],
		bestPythonVersion(),
		strings.Join(deviceNames, " "),
		bridgePrefix,
		dryRunOption,
		filename,
		pythonScript)
}

// NewEtcNetworkInterfacesBridger returns a Bridger that can parse<commit_msg>And back to logging at trace level<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/juju/utils/clock"
)

// Bridger creates network bridges to support addressable containers.
type Bridger interface {
	// Turns existing devices into bridged devices.
	Bridge(deviceNames []string) error
}

type etcNetworkInterfacesBridger struct {
	BridgePrefix string
	Clock        clock.Clock
	DryRun       bool
	Environ      []string
	Filename     string
	Timeout      time.Duration
}

var _ Bridger = (*etcNetworkInterfacesBridger)(nil)

// bestPythonVersion returns a string to the best python interpreter
// found.
//
// For ubuntu series < xenial we prefer python2 over python3 as we
// don't want to invalidate lots of testing against known cloud-image
// contents. A summary of Ubuntu releases and python inclusion in the
// default install of Ubuntu Server is as follows:
//
// 12.04 precise:  python 2 (2.7.3)
// 14.04 trusty:   python 2 (2.7.5) and python3 (3.4.0)
// 14.10 utopic:   python 2 (2.7.8) and python3 (3.4.2)
// 15.04 vivid:    python 2 (2.7.9) and python3 (3.4.3)
// 15.10 wily:     python 2 (2.7.9) and python3 (3.4.3)
// 16.04 xenial:   python 3 only (3.5.1)
//
// going forward:  python 3 only
func bestPythonVersion() string {
	for _, version := range []string{
		"/usr/bin/python2",
		"/usr/bin/python3",
		"/usr/bin/python",
	} {
		if _, err := os.Stat(version); err == nil {
			return version
		}
	}
	return ""
}

func (b *etcNetworkInterfacesBridger) Bridge(deviceNames []string) error {
	cmd := bridgeCmd(deviceNames, b.BridgePrefix, b.Filename, BridgeScriptPythonContent, b.DryRun)
	debugCmd := bridgeCmd(deviceNames, b.BridgePrefix, b.Filename, "<script-redacted>", b.DryRun)
	logger.Infof("bridgescript command=%s", debugCmd)
	result, err := runCommand(cmd, b.Environ, b.Clock, b.Timeout)
	if err != nil {
		return errors.Errorf("script invocation error: %s", err)
	}
	logger.Infof("bridgescript result=%v, timeout=%v", result.Code, result.TimedOut)
	if result.TimedOut {
		return errors.Errorf("bridgescript timed out after %v", b.Timeout)
	}
	if result.Code != 0 {
		logger.Errorf("bridgescript stdout\n%s\n", result.Stdout)
		logger.Errorf("bridgescript stderr\n%s\n", result.Stderr)
		return errors.Errorf("bridgescript failed: %s", string(result.Stderr))
	}
	logger.Tracef("bridgescript stdout\n%s\n", result.Stdout)
	logger.Tracef("bridgescript stderr\n%s\n", result.Stderr)
	return nil
}

func bridgeCmd(deviceNames []string, bridgePrefix, filename, pythonScript string, dryRun bool) string {
	dryRunOption := ""

	if bridgePrefix != "" {
		bridgePrefix = fmt.Sprintf("--bridge-prefix=%s", bridgePrefix)
	}

	if dryRun {
		dryRunOption = "--dry-run"
	}

	return fmt.Sprintf(`
%s - --interfaces-to-bridge=%q --activate %s %s %s <<'EOF'
%s
EOF
`[1:],
		bestPythonVersion(),
		strings.Join(deviceNames, " "),
		bridgePrefix,
		dryRunOption,
		filename,
		pythonScript)
}

// NewEtcNetworkInterfacesBridger returns a Bridger that can parse
{'fraction_non_alphanumeric': 0.13517862890247828, 'fraction_numerical': 0.024460894753781784, 'mean_word_length': 3.8140975987606507, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5128755', 'n_tokens_mistral': 2301, 'n_tokens_neox': 2116, 'n_words': 593}