podman

Форк
0
/
networking_machine.go 
134 строки · 3.8 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"bytes"
7
	"context"
8
	"errors"
9
	"fmt"
10
	"io"
11
	"net"
12
	"net/http"
13
	"strconv"
14
	"strings"
15
	"time"
16

17
	"github.com/containers/common/libnetwork/types"
18
	"github.com/containers/common/pkg/machine"
19
	"github.com/sirupsen/logrus"
20
)
21

22
const machineGvproxyEndpoint = "gateway.containers.internal"
23

24
// machineExpose is the struct for the gvproxy port forwarding api send via json
25
type machineExpose struct {
26
	// Local is the local address on the vm host, format is ip:port
27
	Local string `json:"local"`
28
	// Remote is used to specify the vm ip:port
29
	Remote string `json:"remote,omitempty"`
30
	// Protocol to forward, tcp or udp
31
	Protocol string `json:"protocol"`
32
}
33

34
func requestMachinePorts(expose bool, ports []types.PortMapping) error {
35
	url := "http://" + machineGvproxyEndpoint + "/services/forwarder/"
36
	if expose {
37
		url += "expose"
38
	} else {
39
		url += "unexpose"
40
	}
41
	ctx := context.Background()
42
	client := &http.Client{
43
		Transport: &http.Transport{
44
			// make sure to not set a proxy here so explicitly ignore the proxy
45
			// since we want to talk directly to gvproxy
46
			// https://github.com/containers/podman/issues/13628
47
			Proxy:                 nil,
48
			MaxIdleConns:          50,
49
			IdleConnTimeout:       30 * time.Second,
50
			TLSHandshakeTimeout:   10 * time.Second,
51
			ExpectContinueTimeout: 1 * time.Second,
52
		},
53
	}
54
	buf := new(bytes.Buffer)
55
	for num, port := range ports {
56
		protocols := strings.Split(port.Protocol, ",")
57
		for _, protocol := range protocols {
58
			for i := uint16(0); i < port.Range; i++ {
59
				machinePort := machineExpose{
60
					Local:    net.JoinHostPort(port.HostIP, strconv.FormatInt(int64(port.HostPort+i), 10)),
61
					Protocol: protocol,
62
				}
63
				if expose {
64
					// only set the remote port the ip will be automatically be set by gvproxy
65
					machinePort.Remote = ":" + strconv.FormatInt(int64(port.HostPort+i), 10)
66
				}
67

68
				// post request
69
				if err := json.NewEncoder(buf).Encode(machinePort); err != nil {
70
					if expose {
71
						// in case of an error make sure to unexpose the other ports
72
						if cerr := requestMachinePorts(false, ports[:num]); cerr != nil {
73
							logrus.Errorf("failed to free gvproxy machine ports: %v", cerr)
74
						}
75
					}
76
					return err
77
				}
78
				if err := makeMachineRequest(ctx, client, url, buf); err != nil {
79
					if expose {
80
						// in case of an error make sure to unexpose the other ports
81
						if cerr := requestMachinePorts(false, ports[:num]); cerr != nil {
82
							logrus.Errorf("failed to free gvproxy machine ports: %v", cerr)
83
						}
84
					}
85
					return err
86
				}
87
				buf.Reset()
88
			}
89
		}
90
	}
91
	return nil
92
}
93

94
func makeMachineRequest(ctx context.Context, client *http.Client, url string, buf io.Reader) error {
95
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, buf)
96
	if err != nil {
97
		return err
98
	}
99
	req.Header.Add("Accept", "application/json")
100
	req.Header.Add("Content-Type", "application/json")
101
	resp, err := client.Do(req)
102
	if err != nil {
103
		return err
104
	}
105
	defer resp.Body.Close()
106
	if resp.StatusCode != http.StatusOK {
107
		return annotateGvproxyResponseError(resp.Body)
108
	}
109
	return nil
110
}
111

112
func annotateGvproxyResponseError(r io.Reader) error {
113
	b, err := io.ReadAll(r)
114
	if err == nil && len(b) > 0 {
115
		return fmt.Errorf("something went wrong with the request: %q", string(b))
116
	}
117
	return errors.New("something went wrong with the request, could not read response")
118
}
119

120
// exposeMachinePorts exposes the ports for podman machine via gvproxy
121
func (r *Runtime) exposeMachinePorts(ports []types.PortMapping) error {
122
	if !machine.IsGvProxyBased() {
123
		return nil
124
	}
125
	return requestMachinePorts(true, ports)
126
}
127

128
// unexposeMachinePorts closes the ports for podman machine via gvproxy
129
func (r *Runtime) unexposeMachinePorts(ports []types.PortMapping) error {
130
	if !machine.IsGvProxyBased() {
131
		return nil
132
	}
133
	return requestMachinePorts(false, ports)
134
}
135

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.