Lint on pkg/* packages
- pkg/useragent - pkg/units - pkg/ulimit - pkg/truncindex - pkg/timeoutconn - pkg/term - pkg/tarsum - pkg/tailfile - pkg/systemd - pkg/stringutils - pkg/stringid - pkg/streamformatter - pkg/sockets - pkg/signal - pkg/proxy - pkg/progressreader - pkg/pools - pkg/plugins - pkg/pidfile - pkg/parsers - pkg/parsers/filters - pkg/parsers/kernel - pkg/parsers/operatingsystem Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
a922d62168
commit
9bcb3cba83
56 changed files with 455 additions and 195 deletions
|
@ -1,3 +1,5 @@
|
|||
// Package filters provides helper function to parse and handle command line
|
||||
// filter, used for example in docker ps or docker images commands.
|
||||
package filters
|
||||
|
||||
import (
|
||||
|
@ -7,16 +9,22 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Args stores filter arguments as map key:{array of values}.
|
||||
// It contains a aggregation of the list of arguments (which are in the form
|
||||
// of -f 'key=value') based on the key, and store values for the same key
|
||||
// in an slice.
|
||||
// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu'
|
||||
// the args will be {'label': {'label1=1','label2=2'}, 'image.name', {'ubuntu'}}
|
||||
type Args map[string][]string
|
||||
|
||||
// Parse the argument to the filter flag. Like
|
||||
// ParseFlag parses the argument to the filter flag. Like
|
||||
//
|
||||
// `docker ps -f 'created=today' -f 'image.name=ubuntu*'`
|
||||
//
|
||||
// If prev map is provided, then it is appended to, and returned. By default a new
|
||||
// map is created.
|
||||
func ParseFlag(arg string, prev Args) (Args, error) {
|
||||
var filters Args = prev
|
||||
filters := prev
|
||||
if prev == nil {
|
||||
filters = Args{}
|
||||
}
|
||||
|
@ -25,7 +33,7 @@ func ParseFlag(arg string, prev Args) (Args, error) {
|
|||
}
|
||||
|
||||
if !strings.Contains(arg, "=") {
|
||||
return filters, ErrorBadFormat
|
||||
return filters, ErrBadFormat
|
||||
}
|
||||
|
||||
f := strings.SplitN(arg, "=", 2)
|
||||
|
@ -36,9 +44,10 @@ func ParseFlag(arg string, prev Args) (Args, error) {
|
|||
return filters, nil
|
||||
}
|
||||
|
||||
var ErrorBadFormat = errors.New("bad format of filter (expected name=value)")
|
||||
// ErrBadFormat is an error returned in case of bad format for a filter.
|
||||
var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
|
||||
|
||||
// packs the Args into an string for easy transport from client to server
|
||||
// ToParam packs the Args into an string for easy transport from client to server.
|
||||
func ToParam(a Args) (string, error) {
|
||||
// this way we don't URL encode {}, just empty space
|
||||
if len(a) == 0 {
|
||||
|
@ -52,7 +61,7 @@ func ToParam(a Args) (string, error) {
|
|||
return string(buf), nil
|
||||
}
|
||||
|
||||
// unpacks the filter Args
|
||||
// FromParam unpacks the filter Args.
|
||||
func FromParam(p string) (Args, error) {
|
||||
args := Args{}
|
||||
if len(p) == 0 {
|
||||
|
@ -64,6 +73,11 @@ func FromParam(p string) (Args, error) {
|
|||
return args, nil
|
||||
}
|
||||
|
||||
// MatchKVList returns true if the values for the specified field maches the ones
|
||||
// from the sources.
|
||||
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
|
||||
// field is 'label' and sources are {'label':{'label1=1','label2=2','label3=3'}}
|
||||
// it returns true.
|
||||
func (filters Args) MatchKVList(field string, sources map[string]string) bool {
|
||||
fieldValues := filters[field]
|
||||
|
||||
|
@ -96,6 +110,10 @@ outer:
|
|||
return true
|
||||
}
|
||||
|
||||
// Match returns true if the values for the specified field matches the source string
|
||||
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
|
||||
// field is 'image.name' and source is 'ubuntu'
|
||||
// it returns true.
|
||||
func (filters Args) Match(field, source string) bool {
|
||||
fieldValues := filters[field]
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ func TestParseArgsEdgeCase(t *testing.T) {
|
|||
if args == nil || len(args) != 0 {
|
||||
t.Fatalf("Expected an empty Args (map), got %v", args)
|
||||
}
|
||||
if args, err = ParseFlag("anything", args); err == nil || err != ErrorBadFormat {
|
||||
t.Fatalf("Expected ErrorBadFormat, got %v", err)
|
||||
if args, err = ParseFlag("anything", args); err == nil || err != ErrBadFormat {
|
||||
t.Fatalf("Expected ErrBadFormat, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// +build !windows
|
||||
|
||||
// Package kernel provides helper function to get, parse and compare kernel
|
||||
// versions for different platforms.
|
||||
package kernel
|
||||
|
||||
import (
|
||||
|
@ -8,20 +10,21 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
type KernelVersionInfo struct {
|
||||
Kernel int
|
||||
Major int
|
||||
Minor int
|
||||
Flavor string
|
||||
// VersionInfo holds information about the kernel.
|
||||
type VersionInfo struct {
|
||||
Kernel int // Version of the kernel (e.g. 4.1.2-generic -> 4)
|
||||
Major int // Major part of the kernel version (e.g. 4.1.2-generic -> 1)
|
||||
Minor int // Minor part of the kernel version (e.g. 4.1.2-generic -> 2)
|
||||
Flavor string // Flavor of the kernel version (e.g. 4.1.2-generic -> generic)
|
||||
}
|
||||
|
||||
func (k *KernelVersionInfo) String() string {
|
||||
func (k *VersionInfo) String() string {
|
||||
return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, k.Flavor)
|
||||
}
|
||||
|
||||
// Compare two KernelVersionInfo struct.
|
||||
// CompareKernelVersion compares two kernel.VersionInfo structs.
|
||||
// Returns -1 if a < b, 0 if a == b, 1 it a > b
|
||||
func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
||||
func CompareKernelVersion(a, b VersionInfo) int {
|
||||
if a.Kernel < b.Kernel {
|
||||
return -1
|
||||
} else if a.Kernel > b.Kernel {
|
||||
|
@ -43,7 +46,8 @@ func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func GetKernelVersion() (*KernelVersionInfo, error) {
|
||||
// GetKernelVersion gets the current kernel version.
|
||||
func GetKernelVersion() (*VersionInfo, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
@ -67,7 +71,8 @@ func GetKernelVersion() (*KernelVersionInfo, error) {
|
|||
return ParseRelease(string(release))
|
||||
}
|
||||
|
||||
func ParseRelease(release string) (*KernelVersionInfo, error) {
|
||||
// ParseRelease parses a string and creates a VersionInfo based on it.
|
||||
func ParseRelease(release string) (*VersionInfo, error) {
|
||||
var (
|
||||
kernel, major, minor, parsed int
|
||||
flavor, partial string
|
||||
|
@ -86,7 +91,7 @@ func ParseRelease(release string) (*KernelVersionInfo, error) {
|
|||
flavor = partial
|
||||
}
|
||||
|
||||
return &KernelVersionInfo{
|
||||
return &VersionInfo{
|
||||
Kernel: kernel,
|
||||
Major: major,
|
||||
Minor: minor,
|
||||
|
|
|
@ -5,13 +5,13 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, result int) {
|
||||
func assertParseRelease(t *testing.T, release string, b *VersionInfo, result int) {
|
||||
var (
|
||||
a *KernelVersionInfo
|
||||
a *VersionInfo
|
||||
)
|
||||
a, _ = ParseRelease(release)
|
||||
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
if r := CompareKernelVersion(*a, *b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result for (%v,%v). Found %d, expected %d", release, b, r, result)
|
||||
}
|
||||
if a.Flavor != b.Flavor {
|
||||
|
@ -20,13 +20,13 @@ func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, resu
|
|||
}
|
||||
|
||||
func TestParseRelease(t *testing.T) {
|
||||
assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
||||
assertParseRelease(t, "3.12.8tag", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
||||
assertParseRelease(t, "3.12-1-amd64", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
||||
assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 4, Major: 8, Minor: 0}, -1)
|
||||
assertParseRelease(t, "3.8.0", &VersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &VersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &VersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.8.0-19-generic", &VersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
||||
assertParseRelease(t, "3.12.8tag", &VersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
||||
assertParseRelease(t, "3.12-1-amd64", &VersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
||||
assertParseRelease(t, "3.8.0", &VersionInfo{Kernel: 4, Major: 8, Minor: 0}, -1)
|
||||
// Errors
|
||||
invalids := []string{
|
||||
"3",
|
||||
|
@ -42,7 +42,7 @@ func TestParseRelease(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
||||
func assertKernelVersion(t *testing.T, a, b VersionInfo, result int) {
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
|
@ -50,43 +50,43 @@ func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
|||
|
||||
func TestCompareKernelVersion(t *testing.T) {
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 7, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 7, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 7, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 7, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
-1)
|
||||
}
|
||||
|
|
|
@ -6,18 +6,20 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
type KernelVersionInfo struct {
|
||||
kvi string
|
||||
major int
|
||||
minor int
|
||||
build int
|
||||
// VersionInfo holds information about the kernel.
|
||||
type VersionInfo struct {
|
||||
kvi string // Version of the kernel (e.g. 6.1.7601.17592 -> 6)
|
||||
major int // Major part of the kernel version (e.g. 6.1.7601.17592 -> 1)
|
||||
minor int // Minor part of the kernel version (e.g. 6.1.7601.17592 -> 7601)
|
||||
build int // Build number of the kernel version (e.g. 6.1.7601.17592 -> 17592)
|
||||
}
|
||||
|
||||
func (k *KernelVersionInfo) String() string {
|
||||
func (k *VersionInfo) String() string {
|
||||
return fmt.Sprintf("%d.%d %d (%s)", k.major, k.minor, k.build, k.kvi)
|
||||
}
|
||||
|
||||
func GetKernelVersion() (*KernelVersionInfo, error) {
|
||||
// GetKernelVersion gets the current kernel version.
|
||||
func GetKernelVersion() (*VersionInfo, error) {
|
||||
|
||||
var (
|
||||
h syscall.Handle
|
||||
|
@ -25,7 +27,7 @@ func GetKernelVersion() (*KernelVersionInfo, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
KVI := &KernelVersionInfo{"Unknown", 0, 0, 0}
|
||||
KVI := &VersionInfo{"Unknown", 0, 0, 0}
|
||||
|
||||
if err = syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE,
|
||||
syscall.StringToUTF16Ptr(`SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\`),
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// Utsname represents the system name structure.
|
||||
// It is passthgrouh for syscall.Utsname in order to make it portable with
|
||||
// other platforms where it is not available.
|
||||
type Utsname syscall.Utsname
|
||||
|
||||
func uname() (*syscall.Utsname, error) {
|
||||
|
|
|
@ -6,6 +6,9 @@ import (
|
|||
"errors"
|
||||
)
|
||||
|
||||
// Utsname represents the system name structure.
|
||||
// It is defined here to make it portable as it is available on linux but not
|
||||
// on windows.
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package operatingsystem provides helper function to get the operating system
|
||||
// name for different platforms.
|
||||
package operatingsystem
|
||||
|
||||
import (
|
||||
|
@ -14,6 +16,7 @@ var (
|
|||
etcOsRelease = "/etc/os-release"
|
||||
)
|
||||
|
||||
// GetOperatingSystem gets the name of the current operating system.
|
||||
func GetOperatingSystem() (string, error) {
|
||||
b, err := ioutil.ReadFile(etcOsRelease)
|
||||
if err != nil {
|
||||
|
@ -26,6 +29,7 @@ func GetOperatingSystem() (string, error) {
|
|||
return "", errors.New("PRETTY_NAME not found")
|
||||
}
|
||||
|
||||
// IsContainerized returns true if we are running inside a container.
|
||||
func IsContainerized() (bool, error) {
|
||||
b, err := ioutil.ReadFile(proc1Cgroup)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
// See https://code.google.com/p/go/source/browse/src/pkg/mime/type_windows.go?r=d14520ac25bf6940785aabb71f5be453a286f58c
|
||||
// for a similar sample
|
||||
|
||||
// GetOperatingSystem gets the name of the current operating system.
|
||||
func GetOperatingSystem() (string, error) {
|
||||
|
||||
var h syscall.Handle
|
||||
|
@ -41,7 +42,8 @@ func GetOperatingSystem() (string, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
// No-op on Windows
|
||||
// IsContainerized returns true if we are running inside a container.
|
||||
// No-op on Windows, always returns false.
|
||||
func IsContainerized() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Package parsers provides helper functions to parse and validate different type
|
||||
// of string. It can be hosts, unix addresses, tcp addresses, filters, kernel
|
||||
// operating system versions.
|
||||
package parsers
|
||||
|
||||
import (
|
||||
|
@ -9,6 +12,8 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// ParseHost parses the specified address and returns an address that will be used as the host.
|
||||
// Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr
|
||||
// FIXME: Change this not to receive default value as parameter
|
||||
func ParseHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) {
|
||||
addr = strings.TrimSpace(addr)
|
||||
|
@ -17,7 +22,7 @@ func ParseHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) {
|
|||
addr = fmt.Sprintf("unix://%s", defaultUnixAddr)
|
||||
} else {
|
||||
// Note - defaultTCPAddr already includes tcp:// prefix
|
||||
addr = fmt.Sprintf("%s", defaultTCPAddr)
|
||||
addr = defaultTCPAddr
|
||||
}
|
||||
}
|
||||
addrParts := strings.Split(addr, "://")
|
||||
|
@ -37,6 +42,10 @@ func ParseHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// ParseUnixAddr parses and validates that the specified address is a valid UNIX
|
||||
// socket address. It returns a formatted UNIX socket address, either using the
|
||||
// address parsed from addr, or the contents of defaultAddr if addr is a blank
|
||||
// string.
|
||||
func ParseUnixAddr(addr string, defaultAddr string) (string, error) {
|
||||
addr = strings.TrimPrefix(addr, "unix://")
|
||||
if strings.Contains(addr, "://") {
|
||||
|
@ -48,6 +57,9 @@ func ParseUnixAddr(addr string, defaultAddr string) (string, error) {
|
|||
return fmt.Sprintf("unix://%s", addr), nil
|
||||
}
|
||||
|
||||
// ParseTCPAddr parses and validates that the specified address is a valid TCP
|
||||
// address. It returns a formatted TCP address, either using the address parsed
|
||||
// from addr, or the contents of defaultAddr if addr is a blank string.
|
||||
func ParseTCPAddr(addr string, defaultAddr string) (string, error) {
|
||||
addr = strings.TrimPrefix(addr, "tcp://")
|
||||
if strings.Contains(addr, "://") || addr == "" {
|
||||
|
@ -74,7 +86,7 @@ func ParseTCPAddr(addr string, defaultAddr string) (string, error) {
|
|||
return fmt.Sprintf("tcp://%s:%d%s", host, p, u.Path), nil
|
||||
}
|
||||
|
||||
// Get a repos name and returns the right reposName + tag|digest
|
||||
// ParseRepositoryTag gets a repos name and returns the right reposName + tag|digest
|
||||
// The tag can be confusing because of a port in a repository name.
|
||||
// Ex: localhost.localdomain:5000/samalba/hipache:latest
|
||||
// Digest ex: localhost:5000/foo/bar@sha256:bc8813ea7b3603864987522f02a76101c17ad122e1c46d790efc0fca78ca7bfb
|
||||
|
@ -94,6 +106,8 @@ func ParseRepositoryTag(repos string) (string, string) {
|
|||
return repos, ""
|
||||
}
|
||||
|
||||
// PartParser parses and validates the specified string (data) using the specified template
|
||||
// e.g. ip:public:private -> 192.168.0.1:80:8000
|
||||
func PartParser(template, data string) (map[string]string, error) {
|
||||
// ip:public:private
|
||||
var (
|
||||
|
@ -115,6 +129,7 @@ func PartParser(template, data string) (map[string]string, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value)
|
||||
func ParseKeyValueOpt(opt string) (string, string, error) {
|
||||
parts := strings.SplitN(opt, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
|
@ -123,6 +138,7 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
|
|||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
||||
}
|
||||
|
||||
// ParsePortRange parses and validates the specified string as a port-range (8000-9000)
|
||||
func ParsePortRange(ports string) (uint64, uint64, error) {
|
||||
if ports == "" {
|
||||
return 0, 0, fmt.Errorf("Empty string specified for ports.")
|
||||
|
@ -148,6 +164,7 @@ func ParsePortRange(ports string) (uint64, uint64, error) {
|
|||
return start, end, nil
|
||||
}
|
||||
|
||||
// ParseLink parses and validates the specified string as a link format (name:alias)
|
||||
func ParseLink(val string) (string, string, error) {
|
||||
if val == "" {
|
||||
return "", "", fmt.Errorf("empty string specified for links")
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
func TestParseHost(t *testing.T) {
|
||||
var (
|
||||
defaultHttpHost = "127.0.0.1"
|
||||
defaultHTTPHost = "127.0.0.1"
|
||||
defaultUnix = "/var/run/docker.sock"
|
||||
)
|
||||
invalids := map[string]string{
|
||||
|
@ -32,12 +32,12 @@ func TestParseHost(t *testing.T) {
|
|||
"fd://something": "fd://something",
|
||||
}
|
||||
for invalidAddr, expectedError := range invalids {
|
||||
if addr, err := ParseHost(defaultHttpHost, defaultUnix, invalidAddr); err == nil || err.Error() != expectedError {
|
||||
if addr, err := ParseHost(defaultHTTPHost, defaultUnix, invalidAddr); err == nil || err.Error() != expectedError {
|
||||
t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
|
||||
}
|
||||
}
|
||||
for validAddr, expectedAddr := range valids {
|
||||
if addr, err := ParseHost(defaultHttpHost, defaultUnix, validAddr); err != nil || addr != expectedAddr {
|
||||
if addr, err := ParseHost(defaultHTTPHost, defaultUnix, validAddr); err != nil || addr != expectedAddr {
|
||||
t.Errorf("%v -> expected %v, got %v", validAddr, expectedAddr, addr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Package pidfile provides structure and helper functions to create and remove
|
||||
// PID file. A PID file is usually a file used to store the process ID of a
|
||||
// running process.
|
||||
package pidfile
|
||||
|
||||
import (
|
||||
|
@ -8,11 +11,12 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
type PidFile struct {
|
||||
// PIDFile is a file used to store the process ID of a running process.
|
||||
type PIDFile struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func checkPidFileAlreadyExists(path string) error {
|
||||
func checkPIDFileAlreadyExists(path string) error {
|
||||
if pidString, err := ioutil.ReadFile(path); err == nil {
|
||||
if pid, err := strconv.Atoi(string(pidString)); err == nil {
|
||||
if _, err := os.Stat(filepath.Join("/proc", string(pid))); err == nil {
|
||||
|
@ -23,18 +27,20 @@ func checkPidFileAlreadyExists(path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func New(path string) (*PidFile, error) {
|
||||
if err := checkPidFileAlreadyExists(path); err != nil {
|
||||
// New creates a PIDfile using the specified path.
|
||||
func New(path string) (*PIDFile, error) {
|
||||
if err := checkPIDFileAlreadyExists(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PidFile{path: path}, nil
|
||||
return &PIDFile{path: path}, nil
|
||||
}
|
||||
|
||||
func (file PidFile) Remove() error {
|
||||
// Remove removes the PIDFile.
|
||||
func (file PIDFile) Remove() error {
|
||||
if err := os.Remove(file.path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestNewAndRemove(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRemoveInvalidPath(t *testing.T) {
|
||||
file := PidFile{path: filepath.Join("foo", "bar")}
|
||||
file := PIDFile{path: filepath.Join("foo", "bar")}
|
||||
|
||||
if err := file.Remove(); err == nil {
|
||||
t.Fatal("Non-existing file doesn't give an error on delete")
|
||||
|
|
|
@ -19,6 +19,7 @@ const (
|
|||
defaultTimeOut = 30
|
||||
)
|
||||
|
||||
// NewClient creates a new plugin client (http).
|
||||
func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
|
||||
tr := &http.Transport{}
|
||||
|
||||
|
@ -33,11 +34,14 @@ func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
|
|||
return &Client{&http.Client{Transport: tr}, protoAndAddr[1]}, nil
|
||||
}
|
||||
|
||||
// Client represents a plugin client.
|
||||
type Client struct {
|
||||
http *http.Client
|
||||
addr string
|
||||
http *http.Client // http client to use
|
||||
addr string // http address of the plugin
|
||||
}
|
||||
|
||||
// Call calls the specified method with the specified arguments for the plugin.
|
||||
// It will retry for 30 seconds if a failure occurs when calling.
|
||||
func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error {
|
||||
return c.callWithRetry(serviceMethod, args, ret, true)
|
||||
}
|
||||
|
|
|
@ -12,22 +12,28 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound plugin not found
|
||||
ErrNotFound = errors.New("Plugin not found")
|
||||
socketsPath = "/run/docker/plugins"
|
||||
specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"}
|
||||
)
|
||||
|
||||
// Registry defines behavior of a registry of plugins.
|
||||
type Registry interface {
|
||||
// Plugins lists all plugins.
|
||||
Plugins() ([]*Plugin, error)
|
||||
// Plugin returns the plugin registered with the given name (or returns an error).
|
||||
Plugin(name string) (*Plugin, error)
|
||||
}
|
||||
|
||||
// LocalRegistry defines a registry that is local (using unix socket).
|
||||
type LocalRegistry struct{}
|
||||
|
||||
func newLocalRegistry() LocalRegistry {
|
||||
return LocalRegistry{}
|
||||
}
|
||||
|
||||
// Plugin returns the plugin registered with the given name (or returns an error).
|
||||
func (l *LocalRegistry) Plugin(name string) (*Plugin, error) {
|
||||
socketpaths := pluginPaths(socketsPath, name, ".sock")
|
||||
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
// Package plugins provides structures and helper functions to manage Docker
|
||||
// plugins.
|
||||
//
|
||||
// Docker discovers plugins by looking for them in the plugin directory whenever
|
||||
// a user or container tries to use one by name. UNIX domain socket files must
|
||||
// be located under /run/docker/plugins, whereas spec files can be located
|
||||
// either under /etc/docker/plugins or /usr/lib/docker/plugins. This is handled
|
||||
// by the Registry interface, which lets you list all plugins or get a plugin by
|
||||
// its name if it exists.
|
||||
//
|
||||
// The plugins need to implement an HTTP server and bind this to the UNIX socket
|
||||
// or the address specified in the spec files.
|
||||
// A handshake is send at /Plugin.Activate, and plugins are expected to return
|
||||
// a Manifest with a list of of Docker subsystems which this plugin implements.
|
||||
//
|
||||
// In order to use a plugins, you can use the ``Get`` with the name of the
|
||||
// plugin and the subsystem it implements.
|
||||
//
|
||||
// plugin, err := plugins.Get("example", "VolumeDriver")
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("Error looking up volume plugin example: %v", err)
|
||||
// }
|
||||
package plugins
|
||||
|
||||
import (
|
||||
|
@ -9,6 +31,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// ErrNotImplements is returned if the plugin does not implement the requested driver.
|
||||
ErrNotImplements = errors.New("Plugin does not implement the requested driver")
|
||||
)
|
||||
|
||||
|
@ -22,15 +45,23 @@ var (
|
|||
extpointHandlers = make(map[string]func(string, *Client))
|
||||
)
|
||||
|
||||
// Manifest lists what a plugin implements.
|
||||
type Manifest struct {
|
||||
// List of subsystem the plugin implements.
|
||||
Implements []string
|
||||
}
|
||||
|
||||
// Plugin is the definition of a docker plugin.
|
||||
type Plugin struct {
|
||||
// Name of the plugin
|
||||
Name string `json:"-"`
|
||||
// Address of the plugin
|
||||
Addr string
|
||||
// TLS configuration of the plugin
|
||||
TLSConfig tlsconfig.Options
|
||||
// Client attached to the plugin
|
||||
Client *Client `json:"-"`
|
||||
// Manifest of the plugin (see above)
|
||||
Manifest *Manifest `json:"-"`
|
||||
}
|
||||
|
||||
|
@ -96,6 +127,7 @@ func get(name string) (*Plugin, error) {
|
|||
return pl, nil
|
||||
}
|
||||
|
||||
// Get returns the plugin given the specified name and requested implementation.
|
||||
func Get(name, imp string) (*Plugin, error) {
|
||||
pl, err := get(name)
|
||||
if err != nil {
|
||||
|
@ -110,6 +142,7 @@ func Get(name, imp string) (*Plugin, error) {
|
|||
return nil, ErrNotImplements
|
||||
}
|
||||
|
||||
// Handle adds the specified function to the extpointHandlers.
|
||||
func Handle(iface string, fn func(string, *Client)) {
|
||||
extpointHandlers[iface] = fn
|
||||
}
|
||||
|
|
|
@ -18,14 +18,15 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// Pool which returns bufio.Reader with a 32K buffer
|
||||
// BufioReader32KPool is a pool which returns bufio.Reader with a 32K buffer.
|
||||
BufioReader32KPool *BufioReaderPool
|
||||
// Pool which returns bufio.Writer with a 32K buffer
|
||||
// BufioWriter32KPool is a pool which returns bufio.Writer with a 32K buffer.
|
||||
BufioWriter32KPool *BufioWriterPool
|
||||
)
|
||||
|
||||
const buffer32K = 32 * 1024
|
||||
|
||||
// BufioReaderPool is a bufio reader that uses sync.Pool.
|
||||
type BufioReaderPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ func (bufPool *BufioReaderPool) Put(b *bufio.Reader) {
|
|||
bufPool.pool.Put(b)
|
||||
}
|
||||
|
||||
// Copy is a convenience wrapper which uses a buffer to avoid allocation in io.Copy
|
||||
// Copy is a convenience wrapper which uses a buffer to avoid allocation in io.Copy.
|
||||
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||
buf := BufioReader32KPool.Get(src)
|
||||
written, err = io.Copy(dst, buf)
|
||||
|
@ -77,6 +78,7 @@ func (bufPool *BufioReaderPool) NewReadCloserWrapper(buf *bufio.Reader, r io.Rea
|
|||
})
|
||||
}
|
||||
|
||||
// BufioWriterPool is a bufio writer that uses sync.Pool.
|
||||
type BufioWriterPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package progressreader provides a Reader with a progress bar that can be
|
||||
// printed out using the streamformatter package.
|
||||
package progressreader
|
||||
|
||||
import (
|
||||
|
@ -7,7 +9,7 @@ import (
|
|||
"github.com/docker/docker/pkg/streamformatter"
|
||||
)
|
||||
|
||||
// Reader with progress bar
|
||||
// Config contains the configuration for a Reader with progress bar.
|
||||
type Config struct {
|
||||
In io.ReadCloser // Stream to read from
|
||||
Out io.Writer // Where to send progress bar to
|
||||
|
@ -20,6 +22,7 @@ type Config struct {
|
|||
Action string
|
||||
}
|
||||
|
||||
// New creates a new Config.
|
||||
func New(newReader Config) *Config {
|
||||
return &newReader
|
||||
}
|
||||
|
@ -48,6 +51,7 @@ func (config *Config) Read(p []byte) (n int, err error) {
|
|||
return read, err
|
||||
}
|
||||
|
||||
// Close closes the reader (Config).
|
||||
func (config *Config) Close() error {
|
||||
if config.Current < config.Size {
|
||||
//print a full progress bar when closing prematurely
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package proxy provides a network Proxy interface and implementations for TCP
|
||||
// and UDP.
|
||||
package proxy
|
||||
|
||||
import (
|
||||
|
@ -5,18 +7,24 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
// Proxy defines the behavior of a proxy. It forwards traffic back and forth
|
||||
// between two endpoints : the frontend and the backend.
|
||||
// It can be used to do software port-mapping between two addresses.
|
||||
// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
|
||||
// to the backend (container) at 172.17.42.108:4000.
|
||||
type Proxy interface {
|
||||
// Start forwarding traffic back and forth the front and back-end
|
||||
// addresses.
|
||||
// Run starts forwarding traffic back and forth between the front
|
||||
// and back-end addresses.
|
||||
Run()
|
||||
// Stop forwarding traffic and close both ends of the Proxy.
|
||||
// Close stops forwarding traffic and close both ends of the Proxy.
|
||||
Close()
|
||||
// Return the address on which the proxy is listening.
|
||||
// FrontendAddr returns the address on which the proxy is listening.
|
||||
FrontendAddr() net.Addr
|
||||
// Return the proxied address.
|
||||
// BackendAddr returns the proxied address.
|
||||
BackendAddr() net.Addr
|
||||
}
|
||||
|
||||
// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
|
||||
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||
switch frontendAddr.(type) {
|
||||
case *net.UDPAddr:
|
||||
|
|
|
@ -4,16 +4,25 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
// StubProxy is a proxy that is a stub (does nothing).
|
||||
type StubProxy struct {
|
||||
frontendAddr net.Addr
|
||||
backendAddr net.Addr
|
||||
}
|
||||
|
||||
// Run does nothing.
|
||||
func (p *StubProxy) Run() {}
|
||||
|
||||
// Close does nothing.
|
||||
func (p *StubProxy) Close() {}
|
||||
|
||||
// FrontendAddr returns the frontend address.
|
||||
func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
|
||||
|
||||
// BackendAddr returns the backend address.
|
||||
func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
|
||||
|
||||
// NewStubProxy creates a new StubProxy
|
||||
func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||
return &StubProxy{
|
||||
frontendAddr: frontendAddr,
|
||||
|
|
|
@ -8,12 +8,15 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
|
||||
// handle TCP traffic forwarding between the frontend and backend addresses.
|
||||
type TCPProxy struct {
|
||||
listener *net.TCPListener
|
||||
frontendAddr *net.TCPAddr
|
||||
backendAddr *net.TCPAddr
|
||||
}
|
||||
|
||||
// NewTCPProxy creates a new TCPProxy.
|
||||
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
|
||||
listener, err := net.ListenTCP("tcp", frontendAddr)
|
||||
if err != nil {
|
||||
|
@ -53,7 +56,7 @@ func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
|
|||
go broker(client, backend)
|
||||
go broker(backend, client)
|
||||
|
||||
var transferred int64 = 0
|
||||
var transferred int64
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case written := <-event:
|
||||
|
@ -72,6 +75,7 @@ func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
|
|||
backend.Close()
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using TCP.
|
||||
func (proxy *TCPProxy) Run() {
|
||||
quit := make(chan bool)
|
||||
defer close(quit)
|
||||
|
@ -85,6 +89,11 @@ func (proxy *TCPProxy) Run() {
|
|||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
|
||||
|
||||
// FrontendAddr returns the TCP address on which the proxy is listening.
|
||||
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
|
||||
// BackendAddr returns the TCP proxied address.
|
||||
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
|
|
|
@ -12,7 +12,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// UDPConnTrackTimeout is the timeout used for UDP connection tracking
|
||||
UDPConnTrackTimeout = 90 * time.Second
|
||||
// UDPBufSize is the buffer size for the UDP proxy
|
||||
UDPBufSize = 65507
|
||||
)
|
||||
|
||||
|
@ -41,6 +43,9 @@ func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
|
|||
|
||||
type connTrackMap map[connTrackKey]*net.UDPConn
|
||||
|
||||
// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
|
||||
// interface to handle UDP traffic forwarding between the frontend and backend
|
||||
// addresses.
|
||||
type UDPProxy struct {
|
||||
listener *net.UDPConn
|
||||
frontendAddr *net.UDPAddr
|
||||
|
@ -49,6 +54,7 @@ type UDPProxy struct {
|
|||
connTrackLock sync.Mutex
|
||||
}
|
||||
|
||||
// NewUDPProxy creates a new UDPProxy.
|
||||
func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
|
||||
listener, err := net.ListenUDP("udp", frontendAddr)
|
||||
if err != nil {
|
||||
|
@ -96,6 +102,7 @@ func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr
|
|||
}
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using UDP.
|
||||
func (proxy *UDPProxy) Run() {
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
|
@ -135,6 +142,7 @@ func (proxy *UDPProxy) Run() {
|
|||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *UDPProxy) Close() {
|
||||
proxy.listener.Close()
|
||||
proxy.connTrackLock.Lock()
|
||||
|
@ -144,7 +152,10 @@ func (proxy *UDPProxy) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
// FrontendAddr returns the UDP address on which the proxy is listening.
|
||||
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
|
||||
// BackendAddr returns the proxied UDP address.
|
||||
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
|
||||
func isClosedError(err error) bool {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package signal provides helper functions for dealing with signals across
|
||||
// various operating systems.
|
||||
package signal
|
||||
|
||||
import (
|
||||
|
@ -5,6 +7,7 @@ import (
|
|||
"os/signal"
|
||||
)
|
||||
|
||||
// CatchAll catches all signals and relays them to the specified channel.
|
||||
func CatchAll(sigc chan os.Signal) {
|
||||
handledSigs := []os.Signal{}
|
||||
for _, s := range SignalMap {
|
||||
|
@ -13,6 +16,7 @@ func CatchAll(sigc chan os.Signal) {
|
|||
signal.Notify(sigc, handledSigs...)
|
||||
}
|
||||
|
||||
// StopCatch stops catching the signals and closes the specified channel.
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of Darwin signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of FreeBSD signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
|
|
|
@ -8,5 +8,9 @@ import (
|
|||
|
||||
// Signals used in api/client (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
|
||||
// SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
|
||||
const SIGCHLD = syscall.SIGCHLD
|
||||
|
||||
// SIGWINCH is a signal sent to a process when its controlling terminal changes its size
|
||||
const SIGWINCH = syscall.SIGWINCH
|
||||
|
|
|
@ -6,4 +6,5 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is an empty map of signals for unsupported platform.
|
||||
var SignalMap = map[string]syscall.Signal{}
|
||||
|
|
|
@ -8,5 +8,7 @@ import (
|
|||
|
||||
// Signals used in api/client (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
const SIGCHLD = syscall.Signal(0xff)
|
||||
const SIGWINCH = syscall.Signal(0xff)
|
||||
const (
|
||||
SIGCHLD = syscall.Signal(0xff)
|
||||
SIGWINCH = syscall.Signal(0xff)
|
||||
)
|
||||
|
|
|
@ -55,6 +55,7 @@ func Trap(cleanup func()) {
|
|||
}()
|
||||
}
|
||||
|
||||
// DumpStacks dumps the runtime stack.
|
||||
func DumpStacks() {
|
||||
buf := make([]byte, 16384)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package sockets provides helper functions to create and configure Unix or TCP
|
||||
// sockets.
|
||||
package sockets
|
||||
|
||||
import (
|
||||
|
@ -9,7 +11,12 @@ import (
|
|||
"github.com/docker/docker/pkg/listenbuffer"
|
||||
)
|
||||
|
||||
func NewTcpSocket(addr string, tlsConfig *tls.Config, activate <-chan struct{}) (net.Listener, error) {
|
||||
// NewTCPSocket creates a TCP socket listener with the specified address and
|
||||
// and the specified tls configuration. If TLSConfig is set, will encapsulate the
|
||||
// TCP listener inside a TLS one.
|
||||
// The channel passed is used to activate the listenbuffer when the caller is ready
|
||||
// to accept connections.
|
||||
func NewTCPSocket(addr string, tlsConfig *tls.Config, activate <-chan struct{}) (net.Listener, error) {
|
||||
l, err := listenbuffer.NewListenBuffer("tcp", addr, activate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -21,6 +28,10 @@ func NewTcpSocket(addr string, tlsConfig *tls.Config, activate <-chan struct{})
|
|||
return l, nil
|
||||
}
|
||||
|
||||
// ConfigureTCPTransport configures the specified Transport according to the
|
||||
// specified proto and addr.
|
||||
// If the proto is unix (using a unix socket to communicate) the compression
|
||||
// is disabled.
|
||||
func ConfigureTCPTransport(tr *http.Transport, proto, addr string) {
|
||||
// Why 32? See https://github.com/docker/docker/pull/8035.
|
||||
timeout := 32 * time.Second
|
||||
|
|
|
@ -14,6 +14,9 @@ import (
|
|||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
)
|
||||
|
||||
// NewUnixSocket creates a unix socket with the specified path and group.
|
||||
// The channel passed is used to activate the listenbuffer when the caller is ready
|
||||
// to accept connections.
|
||||
func NewUnixSocket(path, group string, activate <-chan struct{}) (net.Listener, error) {
|
||||
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package streamformatter provides helper functions to format a stream.
|
||||
package streamformatter
|
||||
|
||||
import (
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
)
|
||||
|
||||
// StreamFormatter formats a stream, optionally using JSON.
|
||||
type StreamFormatter struct {
|
||||
json bool
|
||||
}
|
||||
|
@ -26,6 +28,7 @@ const streamNewline = "\r\n"
|
|||
|
||||
var streamNewlineBytes = []byte(streamNewline)
|
||||
|
||||
// FormatStream formats the specified stream.
|
||||
func (sf *StreamFormatter) FormatStream(str string) []byte {
|
||||
if sf.json {
|
||||
b, err := json.Marshal(&jsonmessage.JSONMessage{Stream: str})
|
||||
|
@ -37,6 +40,7 @@ func (sf *StreamFormatter) FormatStream(str string) []byte {
|
|||
return []byte(str + "\r")
|
||||
}
|
||||
|
||||
// FormatStatus formats the specified objects according to the specified format (and id).
|
||||
func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []byte {
|
||||
str := fmt.Sprintf(format, a...)
|
||||
if sf.json {
|
||||
|
@ -49,6 +53,7 @@ func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []b
|
|||
return []byte(str + streamNewline)
|
||||
}
|
||||
|
||||
// FormatError formats the specifed error.
|
||||
func (sf *StreamFormatter) FormatError(err error) []byte {
|
||||
if sf.json {
|
||||
jsonError, ok := err.(*jsonmessage.JSONError)
|
||||
|
@ -63,6 +68,7 @@ func (sf *StreamFormatter) FormatError(err error) []byte {
|
|||
return []byte("Error: " + err.Error() + streamNewline)
|
||||
}
|
||||
|
||||
// FormatProgress formats the progress information for a specified action.
|
||||
func (sf *StreamFormatter) FormatProgress(id, action string, progress *jsonmessage.JSONProgress) []byte {
|
||||
if progress == nil {
|
||||
progress = &jsonmessage.JSONProgress{}
|
||||
|
@ -86,12 +92,13 @@ func (sf *StreamFormatter) FormatProgress(id, action string, progress *jsonmessa
|
|||
return []byte(action + " " + progress.String() + endl)
|
||||
}
|
||||
|
||||
type StdoutFormater struct {
|
||||
// StdoutFormatter is a streamFormatter that writes to the standard output.
|
||||
type StdoutFormatter struct {
|
||||
io.Writer
|
||||
*StreamFormatter
|
||||
}
|
||||
|
||||
func (sf *StdoutFormater) Write(buf []byte) (int, error) {
|
||||
func (sf *StdoutFormatter) Write(buf []byte) (int, error) {
|
||||
formattedBuf := sf.StreamFormatter.FormatStream(string(buf))
|
||||
n, err := sf.Writer.Write(formattedBuf)
|
||||
if n != len(formattedBuf) {
|
||||
|
@ -100,12 +107,13 @@ func (sf *StdoutFormater) Write(buf []byte) (int, error) {
|
|||
return len(buf), err
|
||||
}
|
||||
|
||||
type StderrFormater struct {
|
||||
// StderrFormatter is a streamFormatter that writes to the standard error.
|
||||
type StderrFormatter struct {
|
||||
io.Writer
|
||||
*StreamFormatter
|
||||
}
|
||||
|
||||
func (sf *StderrFormater) Write(buf []byte) (int, error) {
|
||||
func (sf *StderrFormatter) Write(buf []byte) (int, error) {
|
||||
formattedBuf := sf.StreamFormatter.FormatStream("\033[91m" + string(buf) + "\033[0m")
|
||||
n, err := sf.Writer.Write(formattedBuf)
|
||||
if n != len(formattedBuf) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package stringid provides helper functions for dealing with string identifiers
|
||||
package stringid
|
||||
|
||||
import (
|
||||
|
@ -12,7 +13,7 @@ const shortLen = 12
|
|||
|
||||
var validShortID = regexp.MustCompile("^[a-z0-9]{12}$")
|
||||
|
||||
// Determine if an arbitrary string *looks like* a short ID.
|
||||
// IsShortID determines if an arbitrary string *looks like* a short ID.
|
||||
func IsShortID(id string) bool {
|
||||
return validShortID.MatchString(id)
|
||||
}
|
||||
|
@ -29,7 +30,7 @@ func TruncateID(id string) string {
|
|||
return id[:trimTo]
|
||||
}
|
||||
|
||||
// GenerateRandomID returns an unique id
|
||||
// GenerateRandomID returns an unique id.
|
||||
func GenerateRandomID() string {
|
||||
for {
|
||||
id := make([]byte, 32)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package stringutils provides helper functions for dealing with strings.
|
||||
package stringutils
|
||||
|
||||
import (
|
||||
|
@ -8,7 +9,7 @@ import (
|
|||
"github.com/docker/docker/pkg/random"
|
||||
)
|
||||
|
||||
// Generate alpha only random stirng with length n
|
||||
// GenerateRandomAlphaOnlyString generates an alphabetical random string with length n.
|
||||
func GenerateRandomAlphaOnlyString(n int) string {
|
||||
// make a really long string
|
||||
letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
@ -20,8 +21,8 @@ func GenerateRandomAlphaOnlyString(n int) string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
// Generate Ascii random stirng with length n
|
||||
func GenerateRandomAsciiString(n int) string {
|
||||
// GenerateRandomASCIIString generates an ASCII random stirng with length n.
|
||||
func GenerateRandomASCIIString(n int) string {
|
||||
chars := "abcdefghijklmnopqrstuvwxyz" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"~!@#$%^&*()-_+={}[]\\|<,>.?/\"';:` "
|
||||
|
@ -32,7 +33,7 @@ func GenerateRandomAsciiString(n int) string {
|
|||
return string(res)
|
||||
}
|
||||
|
||||
// Truncate a string to maxlen
|
||||
// Truncate truncates a string to maxlen.
|
||||
func Truncate(s string, maxlen int) string {
|
||||
if len(s) <= maxlen {
|
||||
return s
|
||||
|
@ -40,7 +41,7 @@ func Truncate(s string, maxlen int) string {
|
|||
return s[:maxlen]
|
||||
}
|
||||
|
||||
// Test wheather a string is contained in a slice of strings or not.
|
||||
// InSlice tests whether a string is contained in a slice of strings or not.
|
||||
// Comparison is case insensitive
|
||||
func InSlice(slice []string, s string) bool {
|
||||
for _, ss := range slice {
|
||||
|
@ -73,8 +74,8 @@ func quote(word string, buf *bytes.Buffer) {
|
|||
buf.WriteString("'")
|
||||
}
|
||||
|
||||
// Take a list of strings and escape them so they will be handled right
|
||||
// when passed as arguments to an program via a shell
|
||||
// ShellQuoteArguments takes a list of strings and escapes them so they will be
|
||||
// handled right when passed as arguments to an program via a shell
|
||||
func ShellQuoteArguments(args []string) string {
|
||||
var buf bytes.Buffer
|
||||
for i, arg := range args {
|
||||
|
|
|
@ -43,15 +43,15 @@ func TestGenerateRandomAlphaOnlyStringUniqueness(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringLength(t *testing.T) {
|
||||
testLengthHelper(GenerateRandomAsciiString, t)
|
||||
testLengthHelper(GenerateRandomASCIIString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringUniqueness(t *testing.T) {
|
||||
testUniquenessHelper(GenerateRandomAsciiString, t)
|
||||
testUniquenessHelper(GenerateRandomASCIIString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringIsAscii(t *testing.T) {
|
||||
str := GenerateRandomAsciiString(64)
|
||||
str := GenerateRandomASCIIString(64)
|
||||
if !isASCII(str) {
|
||||
t.Fatalf("%s contained non-ascii characters", str)
|
||||
}
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
var SdNotifyNoSocket = errors.New("No socket")
|
||||
// ErrSdNotifyNoSocket is an error returned if no socket was specified.
|
||||
var ErrSdNotifyNoSocket = errors.New("No socket")
|
||||
|
||||
// Send a message to the init daemon. It is common to ignore the error.
|
||||
// SdNotify sends a message to the init daemon. It is common to ignore the return value.
|
||||
func SdNotify(state string) error {
|
||||
socketAddr := &net.UnixAddr{
|
||||
Name: os.Getenv("NOTIFY_SOCKET"),
|
||||
|
@ -16,7 +17,7 @@ func SdNotify(state string) error {
|
|||
}
|
||||
|
||||
if socketAddr.Name == "" {
|
||||
return SdNotifyNoSocket
|
||||
return ErrSdNotifyNoSocket
|
||||
}
|
||||
|
||||
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package tailfile provides helper functinos to read the nth lines of any
|
||||
// ReadSeeker.
|
||||
package tailfile
|
||||
|
||||
import (
|
||||
|
@ -10,9 +12,11 @@ import (
|
|||
const blockSize = 1024
|
||||
|
||||
var eol = []byte("\n")
|
||||
var ErrNonPositiveLinesNumber = errors.New("Lines number must be positive")
|
||||
|
||||
//TailFile returns last n lines of file f
|
||||
// ErrNonPositiveLinesNumber is an error returned if the lines number was negative.
|
||||
var ErrNonPositiveLinesNumber = errors.New("The number of lines to extract from the file must be positive")
|
||||
|
||||
//TailFile returns last n lines of reader f (could be a fil).
|
||||
func TailFile(f io.ReadSeeker, n int) ([][]byte, error) {
|
||||
if n <= 0 {
|
||||
return nil, ErrNonPositiveLinesNumber
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package tarsum
|
||||
|
||||
// This interface extends TarSum by adding the Remove method. In general
|
||||
// there was concern about adding this method to TarSum itself so instead
|
||||
// it is being added just to "BuilderContext" which will then only be used
|
||||
// during the .dockerignore file processing - see builder/evaluator.go
|
||||
// BuilderContext is an interface extending TarSum by adding the Remove method.
|
||||
// In general there was concern about adding this method to TarSum itself
|
||||
// so instead it is being added just to "BuilderContext" which will then
|
||||
// only be used during the .dockerignore file processing
|
||||
// - see builder/evaluator.go
|
||||
type BuilderContext interface {
|
||||
TarSum
|
||||
Remove(string)
|
||||
|
|
|
@ -2,7 +2,9 @@ package tarsum
|
|||
|
||||
import "sort"
|
||||
|
||||
// This info will be accessed through interface so the actual name and sum cannot be medled with
|
||||
// FileInfoSumInterface provides an interface for accessing file checksum
|
||||
// information within a tar file. This info is accessed through interface
|
||||
// so the actual name and sum cannot be medled with.
|
||||
type FileInfoSumInterface interface {
|
||||
// File name
|
||||
Name() string
|
||||
|
@ -28,9 +30,10 @@ func (fis fileInfoSum) Pos() int64 {
|
|||
return fis.pos
|
||||
}
|
||||
|
||||
// FileInfoSums provides a list of FileInfoSumInterfaces.
|
||||
type FileInfoSums []FileInfoSumInterface
|
||||
|
||||
// GetFile returns the first FileInfoSumInterface with a matching name
|
||||
// GetFile returns the first FileInfoSumInterface with a matching name.
|
||||
func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface {
|
||||
for i := range fis {
|
||||
if fis[i].Name() == name {
|
||||
|
@ -40,7 +43,7 @@ func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetAllFile returns a FileInfoSums with all matching names
|
||||
// GetAllFile returns a FileInfoSums with all matching names.
|
||||
func (fis FileInfoSums) GetAllFile(name string) FileInfoSums {
|
||||
f := FileInfoSums{}
|
||||
for i := range fis {
|
||||
|
@ -51,6 +54,7 @@ func (fis FileInfoSums) GetAllFile(name string) FileInfoSums {
|
|||
return f
|
||||
}
|
||||
|
||||
// GetDuplicatePaths returns a FileInfoSums with all duplicated paths.
|
||||
func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) {
|
||||
seen := make(map[string]int, len(fis)) // allocate earl. no need to grow this map.
|
||||
for i := range fis {
|
||||
|
@ -64,17 +68,23 @@ func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) {
|
|||
return dups
|
||||
}
|
||||
|
||||
// Len returns the size of the FileInfoSums.
|
||||
func (fis FileInfoSums) Len() int { return len(fis) }
|
||||
|
||||
// Swap swaps two FileInfoSum values if a FileInfoSums list.
|
||||
func (fis FileInfoSums) Swap(i, j int) { fis[i], fis[j] = fis[j], fis[i] }
|
||||
|
||||
// SortByPos sorts FileInfoSums content by position.
|
||||
func (fis FileInfoSums) SortByPos() {
|
||||
sort.Sort(byPos{fis})
|
||||
}
|
||||
|
||||
// SortByNames sorts FileInfoSums content by name.
|
||||
func (fis FileInfoSums) SortByNames() {
|
||||
sort.Sort(byName{fis})
|
||||
}
|
||||
|
||||
// SortBySums sorts FileInfoSums content by sums.
|
||||
func (fis FileInfoSums) SortBySums() {
|
||||
dups := fis.GetDuplicatePaths()
|
||||
if len(dups) > 0 {
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
// Package tarsum provides algorithms to perform checksum calculation on
|
||||
// filesystem layers.
|
||||
//
|
||||
// The transportation of filesystems, regarding Docker, is done with tar(1)
|
||||
// archives. There are a variety of tar serialization formats [2], and a key
|
||||
// concern here is ensuring a repeatable checksum given a set of inputs from a
|
||||
// generic tar archive. Types of transportation include distribution to and from a
|
||||
// registry endpoint, saving and loading through commands or Docker daemon APIs,
|
||||
// transferring the build context from client to Docker daemon, and committing the
|
||||
// filesystem of a container to become an image.
|
||||
//
|
||||
// As tar archives are used for transit, but not preserved in many situations, the
|
||||
// focus of the algorithm is to ensure the integrity of the preserved filesystem,
|
||||
// while maintaining a deterministic accountability. This includes neither
|
||||
// constraining the ordering or manipulation of the files during the creation or
|
||||
// unpacking of the archive, nor include additional metadata state about the file
|
||||
// system attributes.
|
||||
package tarsum
|
||||
|
||||
import (
|
||||
|
@ -30,7 +47,8 @@ func NewTarSum(r io.Reader, dc bool, v Version) (TarSum, error) {
|
|||
return NewTarSumHash(r, dc, v, DefaultTHash)
|
||||
}
|
||||
|
||||
// Create a new TarSum, providing a THash to use rather than the DefaultTHash
|
||||
// NewTarSumHash creates a new TarSum, providing a THash to use rather than
|
||||
// the DefaultTHash.
|
||||
func NewTarSumHash(r io.Reader, dc bool, v Version, tHash THash) (TarSum, error) {
|
||||
headerSelector, err := getTarHeaderSelector(v)
|
||||
if err != nil {
|
||||
|
@ -41,7 +59,7 @@ func NewTarSumHash(r io.Reader, dc bool, v Version, tHash THash) (TarSum, error)
|
|||
return ts, err
|
||||
}
|
||||
|
||||
// Create a new TarSum using the provided TarSum version+hash label.
|
||||
// NewTarSumForLabel creates a new TarSum using the provided TarSum version+hash label.
|
||||
func NewTarSumForLabel(r io.Reader, disableCompression bool, label string) (TarSum, error) {
|
||||
parts := strings.SplitN(label, "+", 2)
|
||||
if len(parts) != 2 {
|
||||
|
@ -66,7 +84,7 @@ func NewTarSumForLabel(r io.Reader, disableCompression bool, label string) (TarS
|
|||
}
|
||||
|
||||
// TarSum is the generic interface for calculating fixed time
|
||||
// checksums of a tar archive
|
||||
// checksums of a tar archive.
|
||||
type TarSum interface {
|
||||
io.Reader
|
||||
GetSums() FileInfoSums
|
||||
|
@ -75,7 +93,7 @@ type TarSum interface {
|
|||
Hash() THash
|
||||
}
|
||||
|
||||
// tarSum struct is the structure for a Version0 checksum calculation
|
||||
// tarSum struct is the structure for a Version0 checksum calculation.
|
||||
type tarSum struct {
|
||||
io.Reader
|
||||
tarR *tar.Reader
|
||||
|
@ -104,13 +122,13 @@ func (ts tarSum) Version() Version {
|
|||
return ts.tarSumVersion
|
||||
}
|
||||
|
||||
// A hash.Hash type generator and its name
|
||||
// THash provides a hash.Hash type generator and its name.
|
||||
type THash interface {
|
||||
Hash() hash.Hash
|
||||
Name() string
|
||||
}
|
||||
|
||||
// Convenience method for creating a THash
|
||||
// NewTHash is a convenience method for creating a THash.
|
||||
func NewTHash(name string, h func() hash.Hash) THash {
|
||||
return simpleTHash{n: name, h: h}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// versioning of the TarSum algorithm
|
||||
// Version is used for versioning of the TarSum algorithm
|
||||
// based on the prefix of the hash used
|
||||
// i.e. "tarsum+sha256:e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b"
|
||||
type Version int
|
||||
|
@ -17,7 +17,7 @@ type Version int
|
|||
const (
|
||||
Version0 Version = iota
|
||||
Version1
|
||||
// NOTE: this variable will be either the latest or an unsettled next-version of the TarSum calculation
|
||||
// VersionDev this constant will be either the latest or an unsettled next-version of the TarSum calculation
|
||||
VersionDev
|
||||
)
|
||||
|
||||
|
@ -33,7 +33,7 @@ func VersionLabelForChecksum(checksum string) string {
|
|||
return checksum[:sepIndex]
|
||||
}
|
||||
|
||||
// Get a list of all known tarsum Version
|
||||
// GetVersions gets a list of all known tarsum versions.
|
||||
func GetVersions() []Version {
|
||||
v := []Version{}
|
||||
for k := range tarSumVersions {
|
||||
|
@ -59,7 +59,7 @@ func (tsv Version) String() string {
|
|||
return tarSumVersions[tsv]
|
||||
}
|
||||
|
||||
// GetVersionFromTarsum returns the Version from the provided string
|
||||
// GetVersionFromTarsum returns the Version from the provided string.
|
||||
func GetVersionFromTarsum(tarsum string) (Version, error) {
|
||||
tsv := tarsum
|
||||
if strings.Contains(tarsum, "+") {
|
||||
|
|
|
@ -10,6 +10,9 @@ import (
|
|||
// #include <termios.h>
|
||||
import "C"
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
// It is passthgrouh for syscall.Termios in order to make it portable with
|
||||
// other platforms where it is not available or handled differently.
|
||||
type Termios syscall.Termios
|
||||
|
||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
|
|
18
term/term.go
18
term/term.go
|
@ -1,5 +1,7 @@
|
|||
// +build !windows
|
||||
|
||||
// Package term provides provides structures and helper functions to work with
|
||||
// terminal (state, sizes).
|
||||
package term
|
||||
|
||||
import (
|
||||
|
@ -12,13 +14,16 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidState is returned if the state of the terminal is invalid.
|
||||
ErrInvalidState = errors.New("Invalid terminal state")
|
||||
)
|
||||
|
||||
// State represents the state of the terminal.
|
||||
type State struct {
|
||||
termios Termios
|
||||
}
|
||||
|
||||
// Winsize represents the size of the terminal window.
|
||||
type Winsize struct {
|
||||
Height uint16
|
||||
Width uint16
|
||||
|
@ -26,10 +31,12 @@ type Winsize struct {
|
|||
y uint16
|
||||
}
|
||||
|
||||
// StdStreams returns the standard streams (stdin, stdout, stedrr).
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
}
|
||||
|
||||
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
var inFd uintptr
|
||||
var isTerminalIn bool
|
||||
|
@ -40,6 +47,7 @@ func GetFdInfo(in interface{}) (uintptr, bool) {
|
|||
return inFd, isTerminalIn
|
||||
}
|
||||
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
ws := &Winsize{}
|
||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws)))
|
||||
|
@ -50,6 +58,7 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
|
|||
return ws, err
|
||||
}
|
||||
|
||||
// SetWinsize tries to set the specified window size for the specified file descriptor.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
|
||||
// Skipp errno = 0
|
||||
|
@ -65,8 +74,8 @@ func IsTerminal(fd uintptr) bool {
|
|||
return tcget(fd, &termios) == 0
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor
|
||||
// to a previous state.
|
||||
func RestoreTerminal(fd uintptr, state *State) error {
|
||||
if state == nil {
|
||||
return ErrInvalidState
|
||||
|
@ -77,6 +86,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SaveState saves the state of the terminal connected to the given file descriptor.
|
||||
func SaveState(fd uintptr) (*State, error) {
|
||||
var oldState State
|
||||
if err := tcget(fd, &oldState.termios); err != 0 {
|
||||
|
@ -86,6 +96,8 @@ func SaveState(fd uintptr) (*State, error) {
|
|||
return &oldState, nil
|
||||
}
|
||||
|
||||
// DisableEcho applies the specified state to the terminal connected to the file
|
||||
// descriptor, with echo disabled.
|
||||
func DisableEcho(fd uintptr, state *State) error {
|
||||
newState := state.termios
|
||||
newState.Lflag &^= syscall.ECHO
|
||||
|
@ -97,6 +109,8 @@ func DisableEcho(fd uintptr, state *State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetRawTerminal puts the terminal connected to the given file descriptor into
|
||||
// raw mode and returns the previous state.
|
||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||
oldState, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ type Winsize struct {
|
|||
y uint16
|
||||
}
|
||||
|
||||
// StdStreams returns the standard streams (stdin, stdout, stedrr).
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
switch {
|
||||
case os.Getenv("ConEmuANSI") == "ON":
|
||||
|
@ -36,12 +37,12 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal.
|
||||
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
return winconsole.GetHandleInfo(in)
|
||||
}
|
||||
|
||||
// GetWinsize retrieves the window size of the terminal connected to the passed file descriptor.
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
info, err := winconsole.GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
|
@ -56,7 +57,7 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
|
|||
y: 0}, nil
|
||||
}
|
||||
|
||||
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
|
||||
// SetWinsize tries to set the specified window size for the specified file descriptor.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
// TODO(azlinux): Implement SetWinsize
|
||||
logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked")
|
||||
|
@ -68,8 +69,8 @@ func IsTerminal(fd uintptr) bool {
|
|||
return winconsole.IsConsole(fd)
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor
|
||||
// to a previous state.
|
||||
func RestoreTerminal(fd uintptr, state *State) error {
|
||||
return winconsole.SetConsoleMode(fd, state.mode)
|
||||
}
|
||||
|
@ -94,8 +95,7 @@ func DisableEcho(fd uintptr, state *State) error {
|
|||
}
|
||||
|
||||
// SetRawTerminal puts the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
// mode and returns the previous state.
|
||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||
state, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,7 +8,10 @@ import (
|
|||
const (
|
||||
getTermios = syscall.TIOCGETA
|
||||
setTermios = syscall.TIOCSETA
|
||||
)
|
||||
|
||||
// Termios magic numbers, passthrough to the ones defined in syscall.
|
||||
const (
|
||||
IGNBRK = syscall.IGNBRK
|
||||
PARMRK = syscall.PARMRK
|
||||
INLCR = syscall.INLCR
|
||||
|
@ -29,6 +32,7 @@ const (
|
|||
IEXTEN = syscall.IEXTEN
|
||||
)
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
type Termios struct {
|
||||
Iflag uint64
|
||||
Oflag uint64
|
||||
|
|
|
@ -8,7 +8,10 @@ import (
|
|||
const (
|
||||
getTermios = syscall.TIOCGETA
|
||||
setTermios = syscall.TIOCSETA
|
||||
)
|
||||
|
||||
// Termios magic numbers, passthrough to the ones defined in syscall.
|
||||
const (
|
||||
IGNBRK = syscall.IGNBRK
|
||||
PARMRK = syscall.PARMRK
|
||||
INLCR = syscall.INLCR
|
||||
|
@ -29,6 +32,7 @@ const (
|
|||
IEXTEN = syscall.IEXTEN
|
||||
)
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
|
|
|
@ -12,6 +12,7 @@ const (
|
|||
setTermios = syscall.TCSETS
|
||||
)
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package timeoutconn provides overridden net.Conn that supports deadline (timeout).
|
||||
package timeoutconn
|
||||
|
||||
import (
|
||||
|
@ -5,11 +6,13 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// New creates a net.Conn with a timeout for every Read operation.
|
||||
func New(netConn net.Conn, timeout time.Duration) net.Conn {
|
||||
return &conn{netConn, timeout}
|
||||
}
|
||||
|
||||
// A net.Conn that sets a deadline for every Read or Write operation
|
||||
// A net.Conn that sets a deadline for every Read operation.
|
||||
// FIXME was documented the deadline was on Write operation too but not implement
|
||||
type conn struct {
|
||||
net.Conn
|
||||
timeout time.Duration
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Package timeutils provides helper functions to parse and print time (time.Time).
|
||||
package timeutils
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Package truncindex package provides a general 'index tree', used by Docker
|
||||
// in order to be able to reference containers by only a few unambiguous
|
||||
// characters of their id.
|
||||
package truncindex
|
||||
|
||||
import (
|
||||
|
@ -10,7 +13,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// ErrEmptyPrefix is an error returned if the prefix was empty.
|
||||
ErrEmptyPrefix = errors.New("Prefix can't be empty")
|
||||
// ErrAmbiguousPrefix is an error returned if the prefix was ambiguous (multiple ids for the prefix).
|
||||
ErrAmbiguousPrefix = errors.New("Multiple IDs found with provided prefix")
|
||||
)
|
||||
|
||||
|
@ -22,7 +27,7 @@ type TruncIndex struct {
|
|||
ids map[string]struct{}
|
||||
}
|
||||
|
||||
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs
|
||||
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs.
|
||||
func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
||||
idx = &TruncIndex{
|
||||
ids: make(map[string]struct{}),
|
||||
|
@ -54,7 +59,7 @@ func (idx *TruncIndex) addID(id string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Add adds a new ID to the TruncIndex
|
||||
// Add adds a new ID to the TruncIndex.
|
||||
func (idx *TruncIndex) Add(id string) error {
|
||||
idx.Lock()
|
||||
defer idx.Unlock()
|
||||
|
@ -109,7 +114,7 @@ func (idx *TruncIndex) Get(s string) (string, error) {
|
|||
return "", fmt.Errorf("no such id: %s", s)
|
||||
}
|
||||
|
||||
// Iterates over all stored IDs, and passes each of them to the given handler
|
||||
// Iterate iterates over all stored IDs, and passes each of them to the given handler.
|
||||
func (idx *TruncIndex) Iterate(handler func(id string)) {
|
||||
idx.RLock()
|
||||
defer idx.RUnlock()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package ulimit provides structure and helper function to parse and represent
|
||||
// resource limits (Rlimit and Ulimit, its human friendly version).
|
||||
package ulimit
|
||||
|
||||
import (
|
||||
|
@ -6,13 +8,14 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Human friendly version of Rlimit
|
||||
// Ulimit is a human friendly version of Rlimit.
|
||||
type Ulimit struct {
|
||||
Name string
|
||||
Hard int64
|
||||
Soft int64
|
||||
}
|
||||
|
||||
// Rlimit specifies the resource limits, such as max open files.
|
||||
type Rlimit struct {
|
||||
Type int `json:"type,omitempty"`
|
||||
Hard uint64 `json:"hard,omitempty"`
|
||||
|
@ -24,43 +27,44 @@ const (
|
|||
// some of these are defined in the syscall package, but not all.
|
||||
// Also since Windows client doesn't get access to the syscall package, need to
|
||||
// define these here
|
||||
RLIMIT_AS = 9
|
||||
RLIMIT_CORE = 4
|
||||
RLIMIT_CPU = 0
|
||||
RLIMIT_DATA = 2
|
||||
RLIMIT_FSIZE = 1
|
||||
RLIMIT_LOCKS = 10
|
||||
RLIMIT_MEMLOCK = 8
|
||||
RLIMIT_MSGQUEUE = 12
|
||||
RLIMIT_NICE = 13
|
||||
RLIMIT_NOFILE = 7
|
||||
RLIMIT_NPROC = 6
|
||||
RLIMIT_RSS = 5
|
||||
RLIMIT_RTPRIO = 14
|
||||
RLIMIT_RTTIME = 15
|
||||
RLIMIT_SIGPENDING = 11
|
||||
RLIMIT_STACK = 3
|
||||
rlimitAs = 9
|
||||
rlimitCore = 4
|
||||
rlimitCPU = 0
|
||||
rlimitData = 2
|
||||
rlimitFsize = 1
|
||||
rlimitLocks = 10
|
||||
rlimitMemlock = 8
|
||||
rlimitMsgqueue = 12
|
||||
rlimitNice = 13
|
||||
rlimitNofile = 7
|
||||
rlimitNproc = 6
|
||||
rlimitRss = 5
|
||||
rlimitRtprio = 14
|
||||
rlimitRttime = 15
|
||||
rlimitSigpending = 11
|
||||
rlimitStack = 3
|
||||
)
|
||||
|
||||
var ulimitNameMapping = map[string]int{
|
||||
//"as": RLIMIT_AS, // Disbaled since this doesn't seem usable with the way Docker inits a container.
|
||||
"core": RLIMIT_CORE,
|
||||
"cpu": RLIMIT_CPU,
|
||||
"data": RLIMIT_DATA,
|
||||
"fsize": RLIMIT_FSIZE,
|
||||
"locks": RLIMIT_LOCKS,
|
||||
"memlock": RLIMIT_MEMLOCK,
|
||||
"msgqueue": RLIMIT_MSGQUEUE,
|
||||
"nice": RLIMIT_NICE,
|
||||
"nofile": RLIMIT_NOFILE,
|
||||
"nproc": RLIMIT_NPROC,
|
||||
"rss": RLIMIT_RSS,
|
||||
"rtprio": RLIMIT_RTPRIO,
|
||||
"rttime": RLIMIT_RTTIME,
|
||||
"sigpending": RLIMIT_SIGPENDING,
|
||||
"stack": RLIMIT_STACK,
|
||||
//"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container.
|
||||
"core": rlimitCore,
|
||||
"cpu": rlimitCPU,
|
||||
"data": rlimitData,
|
||||
"fsize": rlimitFsize,
|
||||
"locks": rlimitLocks,
|
||||
"memlock": rlimitMemlock,
|
||||
"msgqueue": rlimitMsgqueue,
|
||||
"nice": rlimitNice,
|
||||
"nofile": rlimitNofile,
|
||||
"nproc": rlimitNproc,
|
||||
"rss": rlimitRss,
|
||||
"rtprio": rlimitRtprio,
|
||||
"rttime": rlimitRttime,
|
||||
"sigpending": rlimitSigpending,
|
||||
"stack": rlimitStack,
|
||||
}
|
||||
|
||||
// Parse parses and returns a Ulimit from the specified string.
|
||||
func Parse(val string) (*Ulimit, error) {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
|
@ -92,6 +96,7 @@ func Parse(val string) (*Ulimit, error) {
|
|||
return &Ulimit{Name: parts[0], Soft: soft, Hard: hard}, nil
|
||||
}
|
||||
|
||||
// GetRlimit returns the RLimit corresponding to Ulimit.
|
||||
func (u *Ulimit) GetRlimit() (*Rlimit, error) {
|
||||
t, exists := ulimitNameMapping[u.Name]
|
||||
if !exists {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package units provides helper function to parse and print size and time units
|
||||
// in human-readable format.
|
||||
package units
|
||||
|
||||
import (
|
||||
|
@ -6,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// HumanDuration returns a human-readable approximation of a duration
|
||||
// (eg. "About a minute", "4 hours ago", etc.)
|
||||
// (eg. "About a minute", "4 hours ago", etc.).
|
||||
func HumanDuration(d time.Duration) string {
|
||||
if seconds := int(d.Seconds()); seconds < 1 {
|
||||
return "Less than a second"
|
||||
|
|
|
@ -38,7 +38,7 @@ var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
|||
var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||
|
||||
// CustomSize returns a human-readable approximation of a size
|
||||
// using custom format
|
||||
// using custom format.
|
||||
func CustomSize(format string, size float64, base float64, _map []string) string {
|
||||
i := 0
|
||||
for size >= base {
|
||||
|
@ -49,17 +49,19 @@ func CustomSize(format string, size float64, base float64, _map []string) string
|
|||
}
|
||||
|
||||
// HumanSize returns a human-readable approximation of a size
|
||||
// using SI standard (eg. "44kB", "17MB")
|
||||
// using SI standard (eg. "44kB", "17MB").
|
||||
func HumanSize(size float64) string {
|
||||
return CustomSize("%.4g %s", size, 1000.0, decimapAbbrs)
|
||||
}
|
||||
|
||||
// BytesSize returns a human-readable size in bytes, kibibytes,
|
||||
// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB").
|
||||
func BytesSize(size float64) string {
|
||||
return CustomSize("%.4g %s", size, 1024.0, binaryAbbrs)
|
||||
}
|
||||
|
||||
// FromHumanSize returns an integer from a human-readable specification of a
|
||||
// size using SI standard (eg. "44kB", "17MB")
|
||||
// size using SI standard (eg. "44kB", "17MB").
|
||||
func FromHumanSize(size string) (int64, error) {
|
||||
return parseSize(size, decimalMap)
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ func RAMInBytes(size string) (int64, error) {
|
|||
return parseSize(size, binaryMap)
|
||||
}
|
||||
|
||||
// Parses the human-readable size string into the amount it represents
|
||||
// Parses the human-readable size string into the amount it represents.
|
||||
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
|
||||
matches := sizeRegex.FindStringSubmatch(sizeStr)
|
||||
if len(matches) != 3 {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Package urlutil provides helper function to check urls kind.
|
||||
// It supports http urls, git urls and transport url (tcp://, …)
|
||||
package urlutil
|
||||
|
||||
import (
|
||||
|
|
|
@ -3,14 +3,9 @@
|
|||
package useragent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNilRequest = errors.New("request cannot be nil")
|
||||
)
|
||||
|
||||
// VersionInfo is used to model UserAgent versions.
|
||||
type VersionInfo struct {
|
||||
Name string
|
||||
|
@ -30,7 +25,7 @@ func (vi *VersionInfo) isValid() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Convert versions to a string and append the string to the string base.
|
||||
// AppendVersions converts versions to a string and appends the string to the string base.
|
||||
//
|
||||
// Each VersionInfo will be converted to a string in the format of
|
||||
// "product/version", where the "product" is get from the name field, while
|
||||
|
|
Loading…
Reference in a new issue