<commit_before>package allocrunner

import (
	"context"
	"fmt"
	"os"
	"path/filepath"

	"github.com/containernetworking/cni/libcni"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/plugins/drivers"
)

const (
	// envCNIPath is the environment variable name to use to derive the CNI path
	// when it is not explicitly set by the client
	envCNIPath = "CNI_PATH"

	// defaultCNIPath is the CNI path to use when it is not set by the client
	// and is not set by environment variable
	defaultCNIPath = "/opt/cni/bin"

	// defaultNomadBridgeName is the name of the bridge to use when not set by
	// the client
	defaultNomadBridgeName = "nomad"

	// bridgeNetworkAllocIfName is the name that is set for the interface created
	// inside of the alloc network which is connected to the bridge
	bridgeNetworkContainerIfName = "eth0"

	// defaultNomadAllocSubnet is the subnet to use for host local ip address
	// allocation when not specified by the client
	defaultNomadAllocSubnet = "172.26.66.0/23"
)

// bridgeNetworkConfigurator is a NetworkConfigurator which adds the alloc to a
// shared bridge, configures masquerading for egress traffic and port mapping
// for ingress
type bridgeNetworkConfigurator struct {
	ctx         context.Context
	cniConfig   *libcni.CNIConfig
	allocSubnet string
	bridgeName  string
}

func newBridgeNetworkConfigurator(ctx context.Context, bridgeName, ipRange, cniPath string) *bridgeNetworkConfigurator {
	b := &bridgeNetworkConfigurator{
		ctx:         ctx,
		bridgeName:  bridgeName,
		allocSubnet: ipRange,
	}
	if cniPath == "" {
		if cniPath = os.Getenv(envCNIPath); cniPath == "" {
			cniPath = defaultCNIPath
		}
	}
	b.cniConfig = libcni.NewCNIConfig(filepath.SplitList(cniPath), nil)

	if b.bridgeName == "" {
		b.bridgeName = defaultNomadBridgeName
	}

	if b.allocSubnet == "" {
		b.allocSubnet = defaultNomadAllocSubnet
	}

	return b
}

// Setup calls the CNI plugins with the add action
func (b *bridgeNetworkConfigurator) Setup(alloc *structs.Allocation, spec *drivers.NetworkIsolationSpec) error {
	netconf, err := b.buildNomadNetConfig()
	if err != nil {
		return err
	}

	result, err := b.cniConfig.AddNetworkList(b.ctx, netconf, b.runtimeConf(alloc, spec))
	if result != nil {
		result.Print()
	}

	return err

}

// Teardown calls the CNI plugins with the delete action
func (b *bridgeNetworkConfigurator) Teardown(alloc *structs.Allocation, spec *drivers.NetworkIsolationSpec) error {
	netconf, err := b.buildNomadNetConfig()
	if err != nil {
		return err
	}

	err = b.cniConfig.DelNetworkList(b.ctx, netconf, b.runtimeConf(alloc, spec))
	return err

}

// getPortMapping builds a list of portMapping structs that are used as the
// portmapping capability arguments for the portmap CNI plugin
func getPortMapping(alloc *structs.Allocation) []*portMapping {
	ports := []*portMapping{}
	for _, network := range alloc.AllocatedResources.Shared.Networks {
		for _, port := range append(network.DynamicPorts, network.ReservedPorts...) {
			for _, proto := range []string{"tcp", "udp"} {
				ports = append(ports, &portMapping{
					Host:      port.Value,
					Container: port.To,
					Proto:     proto,
				})
			}
		}
	}
	return ports
}

// portMapping is the json representation of the portmapping capability arguments
// for the portmap CNI plugin
type portMapping struct {
	Host      int    `json:"hostPort"`
	Container int    `json:"containerPort"`
	Proto     string `json:"protocol"`<commit_msg>ar: fix bridge networking port mapping when port.To is unset (#6190)<commit_after>package allocrunner

import (
	"context"
	"fmt"
	"os"
	"path/filepath"

	"github.com/containernetworking/cni/libcni"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/plugins/drivers"
)

const (
	// envCNIPath is the environment variable name to use to derive the CNI path
	// when it is not explicitly set by the client
	envCNIPath = "CNI_PATH"

	// defaultCNIPath is the CNI path to use when it is not set by the client
	// and is not set by environment variable
	defaultCNIPath = "/opt/cni/bin"

	// defaultNomadBridgeName is the name of the bridge to use when not set by
	// the client
	defaultNomadBridgeName = "nomad"

	// bridgeNetworkAllocIfName is the name that is set for the interface created
	// inside of the alloc network which is connected to the bridge
	bridgeNetworkContainerIfName = "eth0"

	// defaultNomadAllocSubnet is the subnet to use for host local ip address
	// allocation when not specified by the client
	defaultNomadAllocSubnet = "172.26.66.0/23"
)

// bridgeNetworkConfigurator is a NetworkConfigurator which adds the alloc to a
// shared bridge, configures masquerading for egress traffic and port mapping
// for ingress
type bridgeNetworkConfigurator struct {
	ctx         context.Context
	cniConfig   *libcni.CNIConfig
	allocSubnet string
	bridgeName  string
}

func newBridgeNetworkConfigurator(ctx context.Context, bridgeName, ipRange, cniPath string) *bridgeNetworkConfigurator {
	b := &bridgeNetworkConfigurator{
		ctx:         ctx,
		bridgeName:  bridgeName,
		allocSubnet: ipRange,
	}
	if cniPath == "" {
		if cniPath = os.Getenv(envCNIPath); cniPath == "" {
			cniPath = defaultCNIPath
		}
	}
	b.cniConfig = libcni.NewCNIConfig(filepath.SplitList(cniPath), nil)

	if b.bridgeName == "" {
		b.bridgeName = defaultNomadBridgeName
	}

	if b.allocSubnet == "" {
		b.allocSubnet = defaultNomadAllocSubnet
	}

	return b
}

// Setup calls the CNI plugins with the add action
func (b *bridgeNetworkConfigurator) Setup(alloc *structs.Allocation, spec *drivers.NetworkIsolationSpec) error {
	netconf, err := b.buildNomadNetConfig()
	if err != nil {
		return err
	}

	result, err := b.cniConfig.AddNetworkList(b.ctx, netconf, b.runtimeConf(alloc, spec))
	if result != nil {
		result.Print()
	}

	return err

}

// Teardown calls the CNI plugins with the delete action
func (b *bridgeNetworkConfigurator) Teardown(alloc *structs.Allocation, spec *drivers.NetworkIsolationSpec) error {
	netconf, err := b.buildNomadNetConfig()
	if err != nil {
		return err
	}

	err = b.cniConfig.DelNetworkList(b.ctx, netconf, b.runtimeConf(alloc, spec))
	return err

}

// getPortMapping builds a list of portMapping structs that are used as the
// portmapping capability arguments for the portmap CNI plugin
func getPortMapping(alloc *structs.Allocation) []*portMapping {
	ports := []*portMapping{}
	for _, network := range alloc.AllocatedResources.Shared.Networks {
		for _, port := range append(network.DynamicPorts, network.ReservedPorts...) {
			if port.To < 1 {
				continue
			}
			for _, proto := range []string{"tcp", "udp"} {
				ports = append(ports, &portMapping{
					Host:      port.Value,
					Container: port.To,
					Proto:     proto,
				})
			}
		}
	}
	return ports
}

// portMapping is the json representation of the portmapping capability arguments
// for the portmap CNI plugin
type portMapping struct {
	Host      int    `json:"hostPort"`
	Container int    `json:"containerPort"`
	Proto     string `json:"protocol"`
{'fraction_non_alphanumeric': 0.09419980048453755, 'fraction_numerical': 0.003847798204360838, 'mean_word_length': 3.914565826330532, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, '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': '6029285', 'n_tokens_mistral': 2383, 'n_tokens_neox': 2235, 'n_words': 687}