File: run.go

package info (click to toggle)
golang-github-containers-common 0.50.1%2Bds1-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,440 kB
  • sloc: makefile: 118; sh: 46
file content (142 lines) | stat: -rw-r--r-- 4,074 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//go:build linux || freebsd
// +build linux freebsd

package netavark

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/containers/common/libnetwork/internal/util"
	"github.com/containers/common/libnetwork/types"
	"github.com/sirupsen/logrus"
)

type netavarkOptions struct {
	types.NetworkOptions
	Networks map[string]*types.Network `json:"network_info"`
}

// Setup will setup the container network namespace. It returns
// a map of StatusBlocks, the key is the network name.
func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions) (map[string]types.StatusBlock, error) {
	n.lock.Lock()
	defer n.lock.Unlock()
	err := n.loadNetworks()
	if err != nil {
		return nil, err
	}

	err = util.ValidateSetupOptions(n, namespacePath, options)
	if err != nil {
		return nil, err
	}

	// allocate IPs in the IPAM db
	err = n.allocIPs(&options.NetworkOptions)
	if err != nil {
		return nil, err
	}

	netavarkOpts, err := n.convertNetOpts(options.NetworkOptions)
	if err != nil {
		return nil, fmt.Errorf("failed to convert net opts: %w", err)
	}

	// Warn users if one or more networks have dns enabled
	// but aardvark-dns binary is not configured
	for _, network := range netavarkOpts.Networks {
		if network != nil && network.DNSEnabled && n.aardvarkBinary == "" {
			// this is not a fatal error we can still use container without dns
			logrus.Warnf("aardvark-dns binary not found, container dns will not be enabled")
			break
		}
	}

	// trace output to get the json
	if logrus.IsLevelEnabled(logrus.TraceLevel) {
		b, err := json.Marshal(&netavarkOpts)
		if err != nil {
			return nil, err
		}
		// show the full netavark command so we can easily reproduce errors from the cli
		logrus.Tracef("netavark command: printf '%s' | %s setup %s", string(b), n.netavarkBinary, namespacePath)
	}

	result := map[string]types.StatusBlock{}
	err = n.execNetavark([]string{"setup", namespacePath}, netavarkOpts, &result)
	if err != nil {
		// lets dealloc ips to prevent leaking
		if err := n.deallocIPs(&options.NetworkOptions); err != nil {
			logrus.Error(err)
		}
		return nil, err
	}

	// make sure that the result makes sense
	if len(result) != len(options.Networks) {
		logrus.Errorf("unexpected netavark result: %v", result)
		return nil, fmt.Errorf("unexpected netavark result length, want (%d), got (%d) networks", len(options.Networks), len(result))
	}

	return result, err
}

// Teardown will teardown the container network namespace.
func (n *netavarkNetwork) Teardown(namespacePath string, options types.TeardownOptions) error {
	n.lock.Lock()
	defer n.lock.Unlock()
	err := n.loadNetworks()
	if err != nil {
		return err
	}

	// get IPs from the IPAM db
	err = n.getAssignedIPs(&options.NetworkOptions)
	if err != nil {
		// when there is an error getting the ips we should still continue
		// to call teardown for netavark to prevent leaking network interfaces
		logrus.Error(err)
	}

	netavarkOpts, err := n.convertNetOpts(options.NetworkOptions)
	if err != nil {
		return fmt.Errorf("failed to convert net opts: %w", err)
	}

	retErr := n.execNetavark([]string{"teardown", namespacePath}, netavarkOpts, nil)

	// when netavark returned an error we still free the used ips
	// otherwise we could end up in a state where block the ips forever
	err = n.deallocIPs(&netavarkOpts.NetworkOptions)
	if err != nil {
		if retErr != nil {
			logrus.Error(err)
		} else {
			retErr = err
		}
	}

	return retErr
}

func (n *netavarkNetwork) getCommonNetavarkOptions() []string {
	return []string{"--config", n.networkRunDir, "--rootless=" + strconv.FormatBool(n.networkRootless), "--aardvark-binary=" + n.aardvarkBinary}
}

func (n *netavarkNetwork) convertNetOpts(opts types.NetworkOptions) (*netavarkOptions, error) {
	netavarkOptions := netavarkOptions{
		NetworkOptions: opts,
		Networks:       make(map[string]*types.Network, len(opts.Networks)),
	}

	for network := range opts.Networks {
		net, err := n.getNetwork(network)
		if err != nil {
			return nil, err
		}
		netavarkOptions.Networks[network] = net
	}
	return &netavarkOptions, nil
}