Bump RootlessKit v0.14.0-beta.0

https://github.com/rootless-containers/rootlesskit/releases/tag/v0.14.0-beta.0

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda
2021-03-02 17:01:25 +09:00
parent 8af66806c8
commit 2f0fc2911c
12 changed files with 239 additions and 45 deletions

View File

@@ -0,0 +1,36 @@
package api
import "net"
const (
// Version of the REST API, not implementation version.
// See openapi.yaml for the definition.
Version = "1.1.0"
)
// ErrorJSON is returned with "application/json" content type and non-2XX status code
type ErrorJSON struct {
Message string `json:"message"`
}
// Info is the structure returned by `GET /info`
type Info struct {
APIVersion string `json:"apiVersion"` // REST API version
Version string `json:"version"` // Implementation version
StateDir string `json:"stateDir"`
ChildPID int `json:"childPID"`
NetworkDriver *NetworkDriverInfo `json:"networkDriver,omitempty"`
PortDriver *PortDriverInfo `json:"portDriver,omitempty"`
}
// NetworkDriverInfo in Info
type NetworkDriverInfo struct {
Driver string `json:"driver"`
DNS []net.IP `json:"dns,omitempty"`
}
// PortDriverInfo in Info
type PortDriverInfo struct {
Driver string `json:"driver"`
Protos []string `json:"protos"`
}

View File

@@ -0,0 +1,161 @@
# When you made a change to this YAML, please validate with https://editor.swagger.io
openapi: 3.0.3
info:
version: 1.1.0
title: RootlessKit API
servers:
- url: 'http://rootlesskit/v1'
description: Local UNIX socket server. The host part of the URL is ignored.
paths:
# /info: API >= 1.1.0
/info:
get:
responses:
'200':
description: Info. Available since API 1.1.0.
content:
application/json:
schema:
$ref: '#/components/schemas/Info'
/ports:
get:
responses:
'200':
description: An array of PortStatus
content:
application/json:
schema:
$ref: '#/components/schemas/PortStatuses'
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PortSpec'
responses:
'201':
description: PortStatus with ID
content:
application/json:
schema:
$ref: '#/components/schemas/PortStatus'
'/ports/{id}':
delete:
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: Null response
components:
schemas:
Proto:
type: string
description: "protocol for listening. Corresponds to Go's net.Listen. The strings with \"4\" and \"6\" suffixes were introduced in API 1.1.0."
enum:
- tcp
- tcp4
- tcp6
- udp
- udp4
- udp6
- sctp
- sctp4
- sctp6
PortSpec:
required:
- proto
properties:
proto:
$ref: '#/components/schemas/Proto'
parentIP:
type: string
parentPort:
type: integer
format: int32
minimum: 1
maximum: 65535
childIP:
type: string
# future version may support requests with parentPort<=0 for automatic port assignment
childPort:
type: integer
format: int32
minimum: 1
maximum: 65535
PortStatus:
required:
- id
properties:
id:
type: integer
format: int64
spec:
$ref: '#/components/schemas/PortSpec'
PortStatuses:
type: array
items:
$ref: '#/components/schemas/PortStatus'
# Info: API >= 1.1.0
Info:
required:
- apiVersion
- version
- stateDir
- childPID
properties:
apiVersion:
type: string
description: "API version, without \"v\" prefix"
example: "1.1.0"
version:
type: string
description: "Implementation version, without \"v\" prefix"
example: "0.42.0-beta.1+dev"
stateDir:
type: string
description: "state dir"
example: "/run/user/1000/rootlesskit"
childPID:
type: integer
description: "child PID"
example: 10042
networkDriver:
$ref: '#/components/schemas/NetworkDriverInfo'
portDriver:
$ref: '#/components/schemas/PortDriverInfo'
NetworkDriverInfo:
required:
- driver
properties:
driver:
type: string
description: "network driver. Empty when --net=host."
example: "slirp4netns"
# TODO: return TAP info
dns:
type: array
description: "DNS addresses"
items:
type: string
example: ["10.0.2.3"]
PortDriverInfo:
required:
- driver
- supportedProtos
properties:
driver:
type: string
description: "port driver"
example: "builtin"
protos:
type: array
description: "The supported protocol strings for listening ports"
example: ["tcp","udp"]
items:
$ref: '#/components/schemas/Proto'

View File

@@ -1,10 +1,11 @@
package child
import (
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
@@ -101,10 +102,16 @@ func (d *childDriver) handleConnectInit(c *net.UnixConn, req *msg.Request) error
func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) error {
switch req.Proto {
case "tcp":
case "tcp4":
case "tcp6":
case "udp":
case "udp4":
case "udp6":
default:
return errors.Errorf("unknown proto: %q", req.Proto)
}
// dialProto does not need "4", "6" suffix
dialProto := strings.TrimSuffix(strings.TrimSuffix(req.Proto, "6"), "4")
var dialer net.Dialer
ip := req.IP
if ip == "" {
@@ -114,13 +121,9 @@ func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) er
if p == nil {
return errors.Errorf("invalid IP: %q", ip)
}
p = p.To4()
if p == nil {
return errors.Errorf("unsupported IP (v6?): %s", ip)
}
ip = p.String()
}
targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("%s:%d", ip, req.Port))
targetConn, err := dialer.Dial(dialProto, net.JoinHostPort(ip, strconv.Itoa(req.Port)))
if err != nil {
return err
}

View File

@@ -19,7 +19,7 @@ const (
// Request and Response are encoded as JSON with uint32le length header.
type Request struct {
Type string // "init" or "connect"
Proto string // "tcp" or "udp"
Proto string // "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6"
IP string
Port int
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/pkg/errors"
"github.com/rootless-containers/rootlesskit/pkg/api"
"github.com/rootless-containers/rootlesskit/pkg/port"
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque"
@@ -56,6 +57,14 @@ type driver struct {
nextID int
}
func (d *driver) Info(ctx context.Context) (*api.PortDriverInfo, error) {
info := &api.PortDriverInfo{
Driver: "builtin",
Protos: []string{"tcp", "tcp4", "tcp6", "udp", "udp4", "udp6"},
}
return info, nil
}
func (d *driver) OpaqueForChild() map[string]string {
return map[string]string{
opaque.SocketPath: d.socketPath,
@@ -134,9 +143,9 @@ func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, err
return nil // FIXME
}
switch spec.Proto {
case "tcp":
case "tcp", "tcp4", "tcp6":
err = tcp.Run(d.socketPath, spec, routineStopCh, d.logWriter)
case "udp":
case "udp", "udp4", "udp6":
err = udp.Run(d.socketPath, spec, routineStopCh, d.logWriter)
default:
// NOTREACHED

View File

@@ -13,7 +13,7 @@ import (
)
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
ln, err := net.Listen("tcp", net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
ln, err := net.Listen(spec.Proto, net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
if err != nil {
fmt.Fprintf(logWriter, "listen: %v\n", err)
return err

View File

@@ -14,11 +14,11 @@ import (
)
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
addr, err := net.ResolveUDPAddr(spec.Proto, net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
if err != nil {
return err
}
c, err := net.ListenUDP("udp", addr)
c, err := net.ListenUDP(spec.Proto, addr)
if err != nil {
return err
}

View File

@@ -3,17 +3,20 @@ package port
import (
"context"
"net"
"github.com/rootless-containers/rootlesskit/pkg/api"
)
type Spec struct {
Proto string `json:"proto,omitempty"` // either "tcp" or "udp". in future "sctp" will be supported as well.
ParentIP string `json:"parentIP,omitempty"` // IPv4 address. can be empty (0.0.0.0).
// Proto is one of ["tcp", "tcp4", "tcp6", "udp", "udp4", "udp6"].
// "tcp" may cause listening on both IPv4 and IPv6. (Corresponds to Go's net.Listen .)
Proto string `json:"proto,omitempty"`
ParentIP string `json:"parentIP,omitempty"` // IPv4 or IPv6 address. can be empty (0.0.0.0).
ParentPort int `json:"parentPort,omitempty"`
ChildPort int `json:"childPort,omitempty"`
// ChildIP is an IPv4 address.
// ChildIP is an IPv4 or IPv6 address.
// Default values:
// - builtin driver: 127.0.0.1
// - socat driver: 127.0.0.1
// - slirp4netns driver: slirp4netns's child IP, e.g., 10.0.2.100
ChildIP string `json:"childIP,omitempty"`
}
@@ -41,6 +44,7 @@ type ChildContext struct {
// ParentDriver is a driver for the parent process.
type ParentDriver interface {
Manager
Info(ctx context.Context) (*api.PortDriverInfo, error)
// OpaqueForChild typically consists of socket path
// for controlling child from parent
OpaqueForChild() map[string]string

View File

@@ -152,7 +152,10 @@ func ValidatePortSpec(spec port.Spec, existingPorts map[int]*port.Status) error
func validateProto(proto string) error {
switch proto {
case "tcp", "udp", "sctp":
case
"tcp", "tcp4", "tcp6",
"udp", "udp4", "udp6",
"sctp", "sctp4", "sctp6":
return nil
default:
return errors.Errorf("unknown proto: %q", proto)