mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	Bump moby/buildkit
Signed-off-by: ulyssessouza <ulyssessouza@gmail.com>
This commit is contained in:
		
							
								
								
									
										18
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,6 +16,7 @@ import ( | ||||
| //sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort | ||||
| //sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus | ||||
| //sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes | ||||
| //sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult | ||||
|  | ||||
| type atomicBool int32 | ||||
|  | ||||
| @@ -79,6 +80,7 @@ type win32File struct { | ||||
| 	wg            sync.WaitGroup | ||||
| 	wgLock        sync.RWMutex | ||||
| 	closing       atomicBool | ||||
| 	socket        bool | ||||
| 	readDeadline  deadlineHandler | ||||
| 	writeDeadline deadlineHandler | ||||
| } | ||||
| @@ -109,7 +111,13 @@ func makeWin32File(h syscall.Handle) (*win32File, error) { | ||||
| } | ||||
|  | ||||
| func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { | ||||
| 	return makeWin32File(h) | ||||
| 	// If we return the result of makeWin32File directly, it can result in an | ||||
| 	// interface-wrapped nil, rather than a nil interface value. | ||||
| 	f, err := makeWin32File(h) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return f, nil | ||||
| } | ||||
|  | ||||
| // closeHandle closes the resources associated with a Win32 handle | ||||
| @@ -190,6 +198,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er | ||||
| 			if f.closing.isSet() { | ||||
| 				err = ErrFileClosed | ||||
| 			} | ||||
| 		} else if err != nil && f.socket { | ||||
| 			// err is from Win32. Query the overlapped structure to get the winsock error. | ||||
| 			var bytes, flags uint32 | ||||
| 			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags) | ||||
| 		} | ||||
| 	case <-timeout: | ||||
| 		cancelIoEx(f.handle, &c.o) | ||||
| @@ -265,6 +277,10 @@ func (f *win32File) Flush() error { | ||||
| 	return syscall.FlushFileBuffers(f.handle) | ||||
| } | ||||
|  | ||||
| func (f *win32File) Fd() uintptr { | ||||
| 	return uintptr(f.handle) | ||||
| } | ||||
|  | ||||
| func (d *deadlineHandler) set(deadline time.Time) error { | ||||
| 	d.setLock.Lock() | ||||
| 	defer d.setLock.Unlock() | ||||
|   | ||||
							
								
								
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| module github.com/Microsoft/go-winio | ||||
|  | ||||
| go 1.12 | ||||
|  | ||||
| require ( | ||||
| 	github.com/pkg/errors v0.8.1 | ||||
| 	github.com/sirupsen/logrus v1.4.1 | ||||
| 	golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b | ||||
| ) | ||||
							
								
								
									
										16
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | ||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= | ||||
| github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= | ||||
| golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
							
								
								
									
										305
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | ||||
| package winio | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/Microsoft/go-winio/pkg/guid" | ||||
| ) | ||||
|  | ||||
| //sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind | ||||
|  | ||||
| const ( | ||||
| 	afHvSock = 34 // AF_HYPERV | ||||
|  | ||||
| 	socketError = ^uintptr(0) | ||||
| ) | ||||
|  | ||||
| // An HvsockAddr is an address for a AF_HYPERV socket. | ||||
| type HvsockAddr struct { | ||||
| 	VMID      guid.GUID | ||||
| 	ServiceID guid.GUID | ||||
| } | ||||
|  | ||||
| type rawHvsockAddr struct { | ||||
| 	Family    uint16 | ||||
| 	_         uint16 | ||||
| 	VMID      guid.GUID | ||||
| 	ServiceID guid.GUID | ||||
| } | ||||
|  | ||||
| // Network returns the address's network name, "hvsock". | ||||
| func (addr *HvsockAddr) Network() string { | ||||
| 	return "hvsock" | ||||
| } | ||||
|  | ||||
| func (addr *HvsockAddr) String() string { | ||||
| 	return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID) | ||||
| } | ||||
|  | ||||
| // VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port. | ||||
| func VsockServiceID(port uint32) guid.GUID { | ||||
| 	g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3") | ||||
| 	g.Data1 = port | ||||
| 	return g | ||||
| } | ||||
|  | ||||
| func (addr *HvsockAddr) raw() rawHvsockAddr { | ||||
| 	return rawHvsockAddr{ | ||||
| 		Family:    afHvSock, | ||||
| 		VMID:      addr.VMID, | ||||
| 		ServiceID: addr.ServiceID, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) { | ||||
| 	addr.VMID = raw.VMID | ||||
| 	addr.ServiceID = raw.ServiceID | ||||
| } | ||||
|  | ||||
| // HvsockListener is a socket listener for the AF_HYPERV address family. | ||||
| type HvsockListener struct { | ||||
| 	sock *win32File | ||||
| 	addr HvsockAddr | ||||
| } | ||||
|  | ||||
| // HvsockConn is a connected socket of the AF_HYPERV address family. | ||||
| type HvsockConn struct { | ||||
| 	sock          *win32File | ||||
| 	local, remote HvsockAddr | ||||
| } | ||||
|  | ||||
| func newHvSocket() (*win32File, error) { | ||||
| 	fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1) | ||||
| 	if err != nil { | ||||
| 		return nil, os.NewSyscallError("socket", err) | ||||
| 	} | ||||
| 	f, err := makeWin32File(fd) | ||||
| 	if err != nil { | ||||
| 		syscall.Close(fd) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	f.socket = true | ||||
| 	return f, nil | ||||
| } | ||||
|  | ||||
| // ListenHvsock listens for connections on the specified hvsock address. | ||||
| func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { | ||||
| 	l := &HvsockListener{addr: *addr} | ||||
| 	sock, err := newHvSocket() | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("listen", err) | ||||
| 	} | ||||
| 	sa := addr.raw() | ||||
| 	err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa))) | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("listen", os.NewSyscallError("socket", err)) | ||||
| 	} | ||||
| 	err = syscall.Listen(sock.handle, 16) | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("listen", os.NewSyscallError("listen", err)) | ||||
| 	} | ||||
| 	return &HvsockListener{sock: sock, addr: *addr}, nil | ||||
| } | ||||
|  | ||||
| func (l *HvsockListener) opErr(op string, err error) error { | ||||
| 	return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err} | ||||
| } | ||||
|  | ||||
| // Addr returns the listener's network address. | ||||
| func (l *HvsockListener) Addr() net.Addr { | ||||
| 	return &l.addr | ||||
| } | ||||
|  | ||||
| // Accept waits for the next connection and returns it. | ||||
| func (l *HvsockListener) Accept() (_ net.Conn, err error) { | ||||
| 	sock, err := newHvSocket() | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("accept", err) | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		if sock != nil { | ||||
| 			sock.Close() | ||||
| 		} | ||||
| 	}() | ||||
| 	c, err := l.sock.prepareIo() | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("accept", err) | ||||
| 	} | ||||
| 	defer l.sock.wg.Done() | ||||
|  | ||||
| 	// AcceptEx, per documentation, requires an extra 16 bytes per address. | ||||
| 	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{})) | ||||
| 	var addrbuf [addrlen * 2]byte | ||||
|  | ||||
| 	var bytes uint32 | ||||
| 	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o) | ||||
| 	_, err = l.sock.asyncIo(c, nil, bytes, err) | ||||
| 	if err != nil { | ||||
| 		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) | ||||
| 	} | ||||
| 	conn := &HvsockConn{ | ||||
| 		sock: sock, | ||||
| 	} | ||||
| 	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0]))) | ||||
| 	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen]))) | ||||
| 	sock = nil | ||||
| 	return conn, nil | ||||
| } | ||||
|  | ||||
| // Close closes the listener, causing any pending Accept calls to fail. | ||||
| func (l *HvsockListener) Close() error { | ||||
| 	return l.sock.Close() | ||||
| } | ||||
|  | ||||
| /* Need to finish ConnectEx handling | ||||
| func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) { | ||||
| 	sock, err := newHvSocket() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		if sock != nil { | ||||
| 			sock.Close() | ||||
| 		} | ||||
| 	}() | ||||
| 	c, err := sock.prepareIo() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer sock.wg.Done() | ||||
| 	var bytes uint32 | ||||
| 	err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o) | ||||
| 	_, err = sock.asyncIo(ctx, c, nil, bytes, err) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	conn := &HvsockConn{ | ||||
| 		sock:   sock, | ||||
| 		remote: *addr, | ||||
| 	} | ||||
| 	sock = nil | ||||
| 	return conn, nil | ||||
| } | ||||
| */ | ||||
|  | ||||
| func (conn *HvsockConn) opErr(op string, err error) error { | ||||
| 	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err} | ||||
| } | ||||
|  | ||||
| func (conn *HvsockConn) Read(b []byte) (int, error) { | ||||
| 	c, err := conn.sock.prepareIo() | ||||
| 	if err != nil { | ||||
| 		return 0, conn.opErr("read", err) | ||||
| 	} | ||||
| 	defer conn.sock.wg.Done() | ||||
| 	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} | ||||
| 	var flags, bytes uint32 | ||||
| 	err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil) | ||||
| 	n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err) | ||||
| 	if err != nil { | ||||
| 		if _, ok := err.(syscall.Errno); ok { | ||||
| 			err = os.NewSyscallError("wsarecv", err) | ||||
| 		} | ||||
| 		return 0, conn.opErr("read", err) | ||||
| 	} else if n == 0 { | ||||
| 		err = io.EOF | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (conn *HvsockConn) Write(b []byte) (int, error) { | ||||
| 	t := 0 | ||||
| 	for len(b) != 0 { | ||||
| 		n, err := conn.write(b) | ||||
| 		if err != nil { | ||||
| 			return t + n, err | ||||
| 		} | ||||
| 		t += n | ||||
| 		b = b[n:] | ||||
| 	} | ||||
| 	return t, nil | ||||
| } | ||||
|  | ||||
| func (conn *HvsockConn) write(b []byte) (int, error) { | ||||
| 	c, err := conn.sock.prepareIo() | ||||
| 	if err != nil { | ||||
| 		return 0, conn.opErr("write", err) | ||||
| 	} | ||||
| 	defer conn.sock.wg.Done() | ||||
| 	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} | ||||
| 	var bytes uint32 | ||||
| 	err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil) | ||||
| 	n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err) | ||||
| 	if err != nil { | ||||
| 		if _, ok := err.(syscall.Errno); ok { | ||||
| 			err = os.NewSyscallError("wsasend", err) | ||||
| 		} | ||||
| 		return 0, conn.opErr("write", err) | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| // Close closes the socket connection, failing any pending read or write calls. | ||||
| func (conn *HvsockConn) Close() error { | ||||
| 	return conn.sock.Close() | ||||
| } | ||||
|  | ||||
| func (conn *HvsockConn) shutdown(how int) error { | ||||
| 	err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD) | ||||
| 	if err != nil { | ||||
| 		return os.NewSyscallError("shutdown", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CloseRead shuts down the read end of the socket. | ||||
| func (conn *HvsockConn) CloseRead() error { | ||||
| 	err := conn.shutdown(syscall.SHUT_RD) | ||||
| 	if err != nil { | ||||
| 		return conn.opErr("close", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CloseWrite shuts down the write end of the socket, notifying the other endpoint that | ||||
| // no more data will be written. | ||||
| func (conn *HvsockConn) CloseWrite() error { | ||||
| 	err := conn.shutdown(syscall.SHUT_WR) | ||||
| 	if err != nil { | ||||
| 		return conn.opErr("close", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // LocalAddr returns the local address of the connection. | ||||
| func (conn *HvsockConn) LocalAddr() net.Addr { | ||||
| 	return &conn.local | ||||
| } | ||||
|  | ||||
| // RemoteAddr returns the remote address of the connection. | ||||
| func (conn *HvsockConn) RemoteAddr() net.Addr { | ||||
| 	return &conn.remote | ||||
| } | ||||
|  | ||||
| // SetDeadline implements the net.Conn SetDeadline method. | ||||
| func (conn *HvsockConn) SetDeadline(t time.Time) error { | ||||
| 	conn.SetReadDeadline(t) | ||||
| 	conn.SetWriteDeadline(t) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SetReadDeadline implements the net.Conn SetReadDeadline method. | ||||
| func (conn *HvsockConn) SetReadDeadline(t time.Time) error { | ||||
| 	return conn.sock.SetReadDeadline(t) | ||||
| } | ||||
|  | ||||
| // SetWriteDeadline implements the net.Conn SetWriteDeadline method. | ||||
| func (conn *HvsockConn) SetWriteDeadline(t time.Time) error { | ||||
| 	return conn.sock.SetWriteDeadline(t) | ||||
| } | ||||
							
								
								
									
										235
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| // Package guid provides a GUID type. The backing structure for a GUID is | ||||
| // identical to that used by the golang.org/x/sys/windows GUID type. | ||||
| // There are two main binary encodings used for a GUID, the big-endian encoding, | ||||
| // and the Windows (mixed-endian) encoding. See here for details: | ||||
| // https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding | ||||
| package guid | ||||
|  | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"golang.org/x/sys/windows" | ||||
| ) | ||||
|  | ||||
| // Variant specifies which GUID variant (or "type") of the GUID. It determines | ||||
| // how the entirety of the rest of the GUID is interpreted. | ||||
| type Variant uint8 | ||||
|  | ||||
| // The variants specified by RFC 4122. | ||||
| const ( | ||||
| 	// VariantUnknown specifies a GUID variant which does not conform to one of | ||||
| 	// the variant encodings specified in RFC 4122. | ||||
| 	VariantUnknown Variant = iota | ||||
| 	VariantNCS | ||||
| 	VariantRFC4122 | ||||
| 	VariantMicrosoft | ||||
| 	VariantFuture | ||||
| ) | ||||
|  | ||||
| // Version specifies how the bits in the GUID were generated. For instance, a | ||||
| // version 4 GUID is randomly generated, and a version 5 is generated from the | ||||
| // hash of an input string. | ||||
| type Version uint8 | ||||
|  | ||||
| var _ = (encoding.TextMarshaler)(GUID{}) | ||||
| var _ = (encoding.TextUnmarshaler)(&GUID{}) | ||||
|  | ||||
| // GUID represents a GUID/UUID. It has the same structure as | ||||
| // golang.org/x/sys/windows.GUID so that it can be used with functions expecting | ||||
| // that type. It is defined as its own type so that stringification and | ||||
| // marshaling can be supported. The representation matches that used by native | ||||
| // Windows code. | ||||
| type GUID windows.GUID | ||||
|  | ||||
| // NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122. | ||||
| func NewV4() (GUID, error) { | ||||
| 	var b [16]byte | ||||
| 	if _, err := rand.Read(b[:]); err != nil { | ||||
| 		return GUID{}, err | ||||
| 	} | ||||
|  | ||||
| 	g := FromArray(b) | ||||
| 	g.setVersion(4) // Version 4 means randomly generated. | ||||
| 	g.setVariant(VariantRFC4122) | ||||
|  | ||||
| 	return g, nil | ||||
| } | ||||
|  | ||||
| // NewV5 returns a new version 5 (generated from a string via SHA-1 hashing) | ||||
| // GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name, | ||||
| // and the sample code treats it as a series of bytes, so we do the same here. | ||||
| // | ||||
| // Some implementations, such as those found on Windows, treat the name as a | ||||
| // big-endian UTF16 stream of bytes. If that is desired, the string can be | ||||
| // encoded as such before being passed to this function. | ||||
| func NewV5(namespace GUID, name []byte) (GUID, error) { | ||||
| 	b := sha1.New() | ||||
| 	namespaceBytes := namespace.ToArray() | ||||
| 	b.Write(namespaceBytes[:]) | ||||
| 	b.Write(name) | ||||
|  | ||||
| 	a := [16]byte{} | ||||
| 	copy(a[:], b.Sum(nil)) | ||||
|  | ||||
| 	g := FromArray(a) | ||||
| 	g.setVersion(5) // Version 5 means generated from a string. | ||||
| 	g.setVariant(VariantRFC4122) | ||||
|  | ||||
| 	return g, nil | ||||
| } | ||||
|  | ||||
| func fromArray(b [16]byte, order binary.ByteOrder) GUID { | ||||
| 	var g GUID | ||||
| 	g.Data1 = order.Uint32(b[0:4]) | ||||
| 	g.Data2 = order.Uint16(b[4:6]) | ||||
| 	g.Data3 = order.Uint16(b[6:8]) | ||||
| 	copy(g.Data4[:], b[8:16]) | ||||
| 	return g | ||||
| } | ||||
|  | ||||
| func (g GUID) toArray(order binary.ByteOrder) [16]byte { | ||||
| 	b := [16]byte{} | ||||
| 	order.PutUint32(b[0:4], g.Data1) | ||||
| 	order.PutUint16(b[4:6], g.Data2) | ||||
| 	order.PutUint16(b[6:8], g.Data3) | ||||
| 	copy(b[8:16], g.Data4[:]) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // FromArray constructs a GUID from a big-endian encoding array of 16 bytes. | ||||
| func FromArray(b [16]byte) GUID { | ||||
| 	return fromArray(b, binary.BigEndian) | ||||
| } | ||||
|  | ||||
| // ToArray returns an array of 16 bytes representing the GUID in big-endian | ||||
| // encoding. | ||||
| func (g GUID) ToArray() [16]byte { | ||||
| 	return g.toArray(binary.BigEndian) | ||||
| } | ||||
|  | ||||
| // FromWindowsArray constructs a GUID from a Windows encoding array of bytes. | ||||
| func FromWindowsArray(b [16]byte) GUID { | ||||
| 	return fromArray(b, binary.LittleEndian) | ||||
| } | ||||
|  | ||||
| // ToWindowsArray returns an array of 16 bytes representing the GUID in Windows | ||||
| // encoding. | ||||
| func (g GUID) ToWindowsArray() [16]byte { | ||||
| 	return g.toArray(binary.LittleEndian) | ||||
| } | ||||
|  | ||||
| func (g GUID) String() string { | ||||
| 	return fmt.Sprintf( | ||||
| 		"%08x-%04x-%04x-%04x-%012x", | ||||
| 		g.Data1, | ||||
| 		g.Data2, | ||||
| 		g.Data3, | ||||
| 		g.Data4[:2], | ||||
| 		g.Data4[2:]) | ||||
| } | ||||
|  | ||||
| // FromString parses a string containing a GUID and returns the GUID. The only | ||||
| // format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` | ||||
| // format. | ||||
| func FromString(s string) (GUID, error) { | ||||
| 	if len(s) != 36 { | ||||
| 		return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 	} | ||||
| 	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { | ||||
| 		return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 	} | ||||
|  | ||||
| 	var g GUID | ||||
|  | ||||
| 	data1, err := strconv.ParseUint(s[0:8], 16, 32) | ||||
| 	if err != nil { | ||||
| 		return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 	} | ||||
| 	g.Data1 = uint32(data1) | ||||
|  | ||||
| 	data2, err := strconv.ParseUint(s[9:13], 16, 16) | ||||
| 	if err != nil { | ||||
| 		return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 	} | ||||
| 	g.Data2 = uint16(data2) | ||||
|  | ||||
| 	data3, err := strconv.ParseUint(s[14:18], 16, 16) | ||||
| 	if err != nil { | ||||
| 		return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 	} | ||||
| 	g.Data3 = uint16(data3) | ||||
|  | ||||
| 	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} { | ||||
| 		v, err := strconv.ParseUint(s[x:x+2], 16, 8) | ||||
| 		if err != nil { | ||||
| 			return GUID{}, fmt.Errorf("invalid GUID %q", s) | ||||
| 		} | ||||
| 		g.Data4[i] = uint8(v) | ||||
| 	} | ||||
|  | ||||
| 	return g, nil | ||||
| } | ||||
|  | ||||
| func (g *GUID) setVariant(v Variant) { | ||||
| 	d := g.Data4[0] | ||||
| 	switch v { | ||||
| 	case VariantNCS: | ||||
| 		d = (d & 0x7f) | ||||
| 	case VariantRFC4122: | ||||
| 		d = (d & 0x3f) | 0x80 | ||||
| 	case VariantMicrosoft: | ||||
| 		d = (d & 0x1f) | 0xc0 | ||||
| 	case VariantFuture: | ||||
| 		d = (d & 0x0f) | 0xe0 | ||||
| 	case VariantUnknown: | ||||
| 		fallthrough | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("invalid variant: %d", v)) | ||||
| 	} | ||||
| 	g.Data4[0] = d | ||||
| } | ||||
|  | ||||
| // Variant returns the GUID variant, as defined in RFC 4122. | ||||
| func (g GUID) Variant() Variant { | ||||
| 	b := g.Data4[0] | ||||
| 	if b&0x80 == 0 { | ||||
| 		return VariantNCS | ||||
| 	} else if b&0xc0 == 0x80 { | ||||
| 		return VariantRFC4122 | ||||
| 	} else if b&0xe0 == 0xc0 { | ||||
| 		return VariantMicrosoft | ||||
| 	} else if b&0xe0 == 0xe0 { | ||||
| 		return VariantFuture | ||||
| 	} | ||||
| 	return VariantUnknown | ||||
| } | ||||
|  | ||||
| func (g *GUID) setVersion(v Version) { | ||||
| 	g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12) | ||||
| } | ||||
|  | ||||
| // Version returns the GUID version, as defined in RFC 4122. | ||||
| func (g GUID) Version() Version { | ||||
| 	return Version((g.Data3 & 0xF000) >> 12) | ||||
| } | ||||
|  | ||||
| // MarshalText returns the textual representation of the GUID. | ||||
| func (g GUID) MarshalText() ([]byte, error) { | ||||
| 	return []byte(g.String()), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalText takes the textual representation of a GUID, and unmarhals it | ||||
| // into this GUID. | ||||
| func (g *GUID) UnmarshalText(text []byte) error { | ||||
| 	g2, err := FromString(string(text)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*g = g2 | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | ||||
| package winio | ||||
|  | ||||
| //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go | ||||
| //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go | ||||
|   | ||||
							
								
								
									
										33
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -38,6 +38,7 @@ func errnoErr(e syscall.Errno) error { | ||||
|  | ||||
| var ( | ||||
| 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll") | ||||
| 	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll") | ||||
| 	modntdll    = windows.NewLazySystemDLL("ntdll.dll") | ||||
| 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") | ||||
|  | ||||
| @@ -45,6 +46,7 @@ var ( | ||||
| 	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort") | ||||
| 	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus") | ||||
| 	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes") | ||||
| 	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult") | ||||
| 	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe") | ||||
| 	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW") | ||||
| 	procCreateFileW                                          = modkernel32.NewProc("CreateFileW") | ||||
| @@ -73,6 +75,7 @@ var ( | ||||
| 	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") | ||||
| 	procBackupRead                                           = modkernel32.NewProc("BackupRead") | ||||
| 	procBackupWrite                                          = modkernel32.NewProc("BackupWrite") | ||||
| 	procbind                                                 = modws2_32.NewProc("bind") | ||||
| ) | ||||
|  | ||||
| func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { | ||||
| @@ -124,6 +127,24 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { | ||||
| 	var _p0 uint32 | ||||
| 	if wait { | ||||
| 		_p0 = 1 | ||||
| 	} else { | ||||
| 		_p0 = 0 | ||||
| 	} | ||||
| 	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) | ||||
| 	if r1 == 0 { | ||||
| 		if e1 != 0 { | ||||
| 			err = errnoErr(e1) | ||||
| 		} else { | ||||
| 			err = syscall.EINVAL | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { | ||||
| 	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) | ||||
| 	if r1 == 0 { | ||||
| @@ -527,3 +548,15 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { | ||||
| 	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) | ||||
| 	if r1 == socketError { | ||||
| 		if e1 != 0 { | ||||
| 			err = errnoErr(e1) | ||||
| 		} else { | ||||
| 			err = syscall.EINVAL | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/containerd/containerd/.appveyor.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/containerd/containerd/.appveyor.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -12,7 +12,7 @@ environment: | ||||
|   GOPATH: C:\gopath | ||||
|   CGO_ENABLED: 1 | ||||
|   matrix: | ||||
|     - GO_VERSION: 1.12.1 | ||||
|     - GO_VERSION: 1.12.10 | ||||
|  | ||||
| before_build: | ||||
|   - choco install -y mingw --version 5.3.0 | ||||
| @@ -54,9 +54,9 @@ test_script: | ||||
|   # TODO: need an equivalent of TRAVIS_COMMIT_RANGE | ||||
|   # - GIT_CHECK_EXCLUDE="./vendor" TRAVIS_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE/.../..}" C:\MinGW\bin\mingw32-make.exe dco | ||||
|   - bash.exe -lc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe coverage root-coverage" | ||||
|   - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe integration" | ||||
|   # - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe integration" | ||||
|   # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 | ||||
|   - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH; TESTFLAGS_PARALLEL=1 mingw32-make.exe integration" | ||||
|   # - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH; TESTFLAGS_PARALLEL=1 mingw32-make.exe integration" | ||||
|  | ||||
| on_success: | ||||
|   codecov --flag windows -f coverage.txt | ||||
|   | ||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/containerd/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/containerd/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| linters: | ||||
|   enable: | ||||
|     - structcheck | ||||
|     - varcheck | ||||
|     - staticcheck | ||||
|     - unconvert | ||||
|     - gofmt | ||||
|     - goimports | ||||
|     - golint | ||||
|     - ineffassign | ||||
|     - vet | ||||
|     - unused | ||||
|     - misspell | ||||
|   disable: | ||||
|     - errcheck | ||||
|  | ||||
| run: | ||||
|   deadline: 2m | ||||
|   skip-dirs: | ||||
|     - api | ||||
|     - design | ||||
|     - docs | ||||
|     - docs/man | ||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/containerd/.gometalinter.json
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/containerd/.gometalinter.json
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,23 +0,0 @@ | ||||
| { | ||||
|   "Vendor": true, | ||||
|   "Deadline": "2m", | ||||
|   "Sort": ["linter", "severity", "path", "line"], | ||||
|   "Exclude": [ | ||||
|     ".*\\.pb\\.go", | ||||
|     "fetch\\.go:.*::error: unrecognized printf verb 'r'" | ||||
|   ], | ||||
|   "EnableGC": true, | ||||
|  | ||||
|   "Enable": [ | ||||
|     "structcheck", | ||||
|     "varcheck", | ||||
|     "staticcheck", | ||||
|     "unconvert", | ||||
|  | ||||
|     "gofmt", | ||||
|     "goimports", | ||||
|     "golint", | ||||
|     "ineffassign", | ||||
|     "vet" | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										77
									
								
								vendor/github.com/containerd/containerd/.mailmap
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/containerd/containerd/.mailmap
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +1,49 @@ | ||||
| Abhinandan Prativadi <abhi@docker.com> Abhinandan Prativadi <aprativadi@gmail.com> | ||||
| Abhinandan Prativadi <abhi@docker.com> abhi <abhi@docker.com> | ||||
| Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> Akihiro Suda <suda.kyoto@gmail.com> | ||||
| Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> Akihiro Suda <suda.akihiro@lab.ntt.co.jp> | ||||
| Andrei Vagin <avagin@virtuozzo.com> Andrei Vagin <avagin@openvz.org> | ||||
| Brent Baude <bbaude@redhat.com> baude <bbaude@redhat.com> | ||||
| Frank Yang <yyb196@gmail.com> frank yang <yyb196@gmail.com> | ||||
| Georgia Panoutsakopoulou <gpanoutsak@gmail.com> gpanouts <gpanoutsak@gmail.com> | ||||
| Jie Zhang <iamkadisi@163.com> kadisi <iamkadisi@163.com> | ||||
| John Howard <john.howard@microsoft.com> John Howard <jhoward@microsoft.com> | ||||
| Justin Terry <juterry@microsoft.com> Justin Terry (VM) <juterry@microsoft.com> | ||||
| Justin Terry <juterry@microsoft.com> Justin <jterry75@users.noreply.github.com> | ||||
| Kenfe-Mickaël Laventure <mickael.laventure@gmail.com> Kenfe-Mickael Laventure <mickael.laventure@gmail.com> | ||||
| Kevin Xu <cming.xu@gmail.com> kevin.xu <cming.xu@gmail.com> | ||||
| Lu Jingxiao <lujingxiao@huawei.com> l00397676 <lujingxiao@huawei.com> | ||||
| Lantao Liu <lantaol@google.com> Lantao Liu <taotaotheripper@gmail.com> | ||||
| Phil Estes <estesp@gmail.com> Phil Estes <estesp@linux.vnet.ibm.com> | ||||
| Stephen J Day <stevvooe@gmail.com> Stephen J Day <stephen.day@docker.com> | ||||
| Stephen J Day <stevvooe@gmail.com> Stephen Day <stevvooe@users.noreply.github.com> | ||||
| Stephen J Day <stevvooe@gmail.com> Stephen Day <stephen.day@getcruise.com> | ||||
| Sudeesh John <sudeesh@linux.vnet.ibm.com> sudeesh john <sudeesh@linux.vnet.ibm.com> | ||||
| Tõnis Tiigi <tonistiigi@gmail.com> Tonis Tiigi <tonistiigi@gmail.com> | ||||
| Lifubang <lifubang@aliyun.com> Lifubang <lifubang@acmcoder.com> | ||||
| Xiaodong Zhang <a4012017@sina.com> nashasha1 <a4012017@sina.com> | ||||
| Jian Liao <jliao@alauda.io> liaoj <jliao@alauda.io> | ||||
| Jian Liao <jliao@alauda.io> liaojian <liaojian@Dabllo.local> | ||||
| Rui Cao <ruicao@alauda.io> ruicao <ruicao@alauda.io> | ||||
| Xuean Yan <yan.xuean@zte.com.cn> yanxuean <yan.xuean@zte.com.cn> | ||||
| Abhinandan Prativadi <abhi@docker.com> | ||||
| Abhinandan Prativadi <abhi@docker.com> <aprativadi@gmail.com> | ||||
| Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.akihiro@lab.ntt.co.jp> | ||||
| Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.kyoto@gmail.com> | ||||
| Andrei Vagin <avagin@virtuozzo.com> <avagin@openvz.org> | ||||
| Andrey Kolomentsev <andrey.kolomentsev@gmail.com> | ||||
| Brent Baude <bbaude@redhat.com> | ||||
| Carlos Eduardo <me@carlosedp.com> <me@carlosedp.com> | ||||
| Eric Ren <renzhen.rz@alibaba-linux.com> <renzhen.rz@alibaba-inc.com> | ||||
| Frank Yang <yyb196@gmail.com> | ||||
| Georgia Panoutsakopoulou <gpanoutsak@gmail.com> | ||||
| Guangming Wang <guangming.wang@daocloud.io> | ||||
| Haiyan Meng <haiyanmeng@google.com> | ||||
| Jian Liao <jliao@alauda.io> | ||||
| Jian Liao <jliao@alauda.io> <liaojian@Dabllo.local> | ||||
| Ji'an Liu <anthonyliu@zju.edu.cn> | ||||
| Jie Zhang <iamkadisi@163.com> | ||||
| John Howard <john.howard@microsoft.com> <jhoward@microsoft.com> | ||||
| John Howard <john.howard@microsoft.com> <jhowardmsft@users.noreply.github.com> | ||||
| Julien Balestra <julien.balestra@datadoghq.com> | ||||
| Justin Cormack <justin.cormack@docker.com> <justin@specialbusservice.com> | ||||
| Justin Terry <juterry@microsoft.com> | ||||
| Justin Terry <juterry@microsoft.com> <jterry75@users.noreply.github.com> | ||||
| Kenfe-Mickaël Laventure <mickael.laventure@gmail.com> | ||||
| Kevin Xu <cming.xu@gmail.com> | ||||
| Lantao Liu <lantaol@google.com> <taotaotheripper@gmail.com> | ||||
| Lifubang <lifubang@aliyun.com> <lifubang@acmcoder.com> | ||||
| Lu Jingxiao <lujingxiao@huawei.com> | ||||
| Maksym Pavlenko <makpav@amazon.com> <pavlenko.maksym@gmail.com> | ||||
| Mark Gordon <msg555@gmail.com> | ||||
| Michael Katsoulis <michaelkatsoulis88@gmail.com> | ||||
| Mike Brown <brownwm@us.ibm.com> <mikebrow@users.noreply.github.com> | ||||
| Nishchay Kumar <mrawesomenix@gmail.com> | ||||
| Phil Estes <estesp@gmail.com> <estesp@linux.vnet.ibm.com> | ||||
| Rui Cao <ruicao@alauda.io> <ruicao@alauda.io> | ||||
| Stephen J Day <stevvooe@gmail.com> <stephen.day@getcruise.com> | ||||
| Stephen J Day <stevvooe@gmail.com> <stevvooe@users.noreply.github.com> | ||||
| Stephen J Day <stevvooe@gmail.com> <stephen.day@docker.com> | ||||
| Sudeesh John <sudeesh@linux.vnet.ibm.com> | ||||
| Su Fei  <fesu@ebay.com> <fesu@ebay.com> | ||||
| Tõnis Tiigi <tonistiigi@gmail.com> | ||||
| Wei Fu <fuweid89@gmail.com> <fhfuwei@163.com> | ||||
| Xiaodong Zhang <a4012017@sina.com> | ||||
| Xuean Yan <yan.xuean@zte.com.cn> | ||||
| Yuxing Liu <starnop@163.com> | ||||
| zhenguang zhu <zhengguang.zhu@daocloud.io> | ||||
| zhongming chang<zhongming.chang@daocloud.io> | ||||
| zhoulin xie <zhoulin.xie@daocloud.io> | ||||
| zhoulin xie <zhoulin.xie@daocloud.io> <42261994+JoeWrightss@users.noreply.github.com> | ||||
|   | ||||
							
								
								
									
										80
									
								
								vendor/github.com/containerd/containerd/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/containerd/containerd/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| dist: xenial | ||||
| dist: bionic | ||||
| sudo: required | ||||
| # setup travis so that we can run containers for integration tests | ||||
| services: | ||||
| @@ -6,8 +6,25 @@ services: | ||||
|  | ||||
| language: go | ||||
|  | ||||
| os: | ||||
| - linux | ||||
|  | ||||
| go: | ||||
|   - "1.11.x" | ||||
|   - "1.12.x" | ||||
|  | ||||
| env: | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v1 TRAVIS_CGO_ENABLED=1 TRAVIS_DISTRO=bionic | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v2 TRAVIS_CGO_ENABLED=1 TRAVIS_DISTRO=bionic TRAVIS_RELEASE=yes | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runtime.v1.linux TRAVIS_CGO_ENABLED=1 TRAVIS_DISTRO=bionic | ||||
|   - TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0 | ||||
|  | ||||
| matrix: | ||||
|   include: | ||||
|     # Skip testing previous LTS (Xenial / Ubuntu 16.04 LTS) on pull requests | ||||
|     - if: type != pull_request | ||||
|       os: linux | ||||
|       dist: xenial | ||||
|       env: TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v2 TRAVIS_CGO_ENABLED=1 TRAVIS_DISTRO=xenial | ||||
|  | ||||
| go_import_path: github.com/containerd/containerd | ||||
|  | ||||
| @@ -22,16 +39,9 @@ addons: | ||||
|       - python-minimal | ||||
|       - libcap-dev | ||||
|       - libaio-dev | ||||
|       - libprotobuf-c0-dev | ||||
|       - libprotobuf-c-dev | ||||
|       - libprotobuf-dev | ||||
|       - socat | ||||
|       - libseccomp-dev | ||||
|  | ||||
| env: | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v1 TRAVIS_CGO_ENABLED=1 | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v2 TRAVIS_CGO_ENABLED=1 | ||||
|   - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runtime.v1.linux TRAVIS_CGO_ENABLED=1 | ||||
|   - TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0 | ||||
|  | ||||
| before_install: | ||||
|   - uname -r | ||||
| @@ -45,12 +55,13 @@ install: | ||||
|   - go get -u github.com/vbatts/git-validation | ||||
|   - go get -u github.com/kunalkushwaha/ltag | ||||
|   - go get -u github.com/LK4D4/vndr | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-seccomp ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-runc ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-cni ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-critools ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then wget https://github.com/checkpoint-restore/criu/archive/v3.7.tar.gz -O /tmp/criu.tar.gz ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then wget https://github.com/checkpoint-restore/criu/archive/v3.12.tar.gz -O /tmp/criu.tar.gz ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then tar -C /tmp/ -zxf /tmp/criu.tar.gz ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then cd /tmp/criu-3.7 && sudo make install-criu ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then cd /tmp/criu-3.12 && sudo make install-criu ; fi | ||||
|   - cd $TRAVIS_BUILD_DIR | ||||
|  | ||||
| before_script: | ||||
| @@ -61,21 +72,22 @@ script: | ||||
|   - export CGO_ENABLED=$TRAVIS_CGO_ENABLED | ||||
|   - DCO_VERBOSITY=-q ../project/script/validate/dco | ||||
|   - ../project/script/validate/fileheader ../project/ | ||||
|   - ../project/script/validate/vendor | ||||
|   - travis_wait ../project/script/validate/vendor | ||||
|   - GOOS=linux script/setup/install-dev-tools | ||||
|   - go build -i . | ||||
|   - make check | ||||
|   - if [ "$GOOS" = "linux" ]; then make check-protos check-api-descriptors; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then make man ; fi | ||||
|   - make build | ||||
|   - make binaries | ||||
|   - if [ "$GOOS" = "linux" ]; then sudo make install ; fi | ||||
|   - if [ "$GOOS" = "linux" ]; then make coverage ; fi | ||||
|   - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make root-coverage ; fi | ||||
|   - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make integration ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo make install ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then make coverage ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make root-coverage ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make integration ; fi | ||||
|   # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 | ||||
|   - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH TESTFLAGS_PARALLEL=1 make integration ; fi | ||||
|   - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH TESTFLAGS_PARALLEL=1 make integration ; fi | ||||
|   - | | ||||
|     if [ "$GOOS" = "linux" ]; then | ||||
|     if [ "$TRAVIS_GOOS" = "linux" ]; then | ||||
|       sudo mkdir -p /etc/containerd | ||||
|       sudo bash -c "cat > /etc/containerd/config.toml <<EOF | ||||
|       [plugins.cri.containerd.default_runtime] | ||||
| @@ -95,15 +107,25 @@ after_success: | ||||
|   - bash <(curl -s https://codecov.io/bash) -F linux | ||||
|  | ||||
| before_deploy: | ||||
|   - make release | ||||
|   - if [ "$TRAVIS_RELEASE" = "yes" ]; then make release cri-release; fi | ||||
|  | ||||
| deploy: | ||||
|   provider: releases | ||||
|   api_key: | ||||
|     secure: HO+WSIVVUMMsbU74x+YyFsTP3ahqnR4xjwKAziedJ5lZXKJszQBhiYTFmcTeVBoouNjTISd07GQzpoLChuGC20U3+1NbT+CkK8xWR/x1ao2D3JY3Ds6AD9ubWRNWRLptt/xOn5Vq3F8xZyUYchwvDMl4zKCuTKxQGVdHKsINb2DehKcP5cVL6MMvqzEdfj2g99vqXAqs8uuo6dOmvxmHV43bfzDaAJSabjZZs6TKlWTqCQMet8uxyx2Dmjl2lxLwdqv12oJdrszacasn41NYuEyHI2bXyef1mhWGYN4n9bU/Y5winctZ8DOSOZvYg/2ziAaUN0+CTn1IESwVesrPz23P2Sy7wdLxu8dSIZ2yUHl7OsA5T5a5rDchAGguRVNBWvoGtuepEhdRacxTQUo1cMFZsEXjgRKKjdfc1emYQPVdN8mBv8GJwndty473ZXdvFt5R0kNVFtvWuYCa6UYJD2cKrsPSAfbZCDC/LiR3FOoTaUPMZUVkR2ACEO7Dn4+KlmBajqT40Osk/A7k1XA/TzVhMIpLtE0Vk2DfPmGsjCv8bC+MFd+R2Sc8SFdE92oEWRdoPQY5SxMYQtGxA+cbKVlT1kSw6y80yEbx5JZsBnT6+NTHwmDO3kVU9ztLdawOozTElKNAK8HoAyFmzIZ3wL64oThuDrv/TUuY8Iyn814= | ||||
|   file_glob: true | ||||
|   file: releases/*.tar.gz | ||||
|   skip_cleanup: true | ||||
|   on: | ||||
|     repo: containerd/containerd | ||||
|     tags: true | ||||
|   - provider: releases | ||||
|     api_key: | ||||
|       secure: HO+WSIVVUMMsbU74x+YyFsTP3ahqnR4xjwKAziedJ5lZXKJszQBhiYTFmcTeVBoouNjTISd07GQzpoLChuGC20U3+1NbT+CkK8xWR/x1ao2D3JY3Ds6AD9ubWRNWRLptt/xOn5Vq3F8xZyUYchwvDMl4zKCuTKxQGVdHKsINb2DehKcP5cVL6MMvqzEdfj2g99vqXAqs8uuo6dOmvxmHV43bfzDaAJSabjZZs6TKlWTqCQMet8uxyx2Dmjl2lxLwdqv12oJdrszacasn41NYuEyHI2bXyef1mhWGYN4n9bU/Y5winctZ8DOSOZvYg/2ziAaUN0+CTn1IESwVesrPz23P2Sy7wdLxu8dSIZ2yUHl7OsA5T5a5rDchAGguRVNBWvoGtuepEhdRacxTQUo1cMFZsEXjgRKKjdfc1emYQPVdN8mBv8GJwndty473ZXdvFt5R0kNVFtvWuYCa6UYJD2cKrsPSAfbZCDC/LiR3FOoTaUPMZUVkR2ACEO7Dn4+KlmBajqT40Osk/A7k1XA/TzVhMIpLtE0Vk2DfPmGsjCv8bC+MFd+R2Sc8SFdE92oEWRdoPQY5SxMYQtGxA+cbKVlT1kSw6y80yEbx5JZsBnT6+NTHwmDO3kVU9ztLdawOozTElKNAK8HoAyFmzIZ3wL64oThuDrv/TUuY8Iyn814= | ||||
|     file_glob: true | ||||
|     file: | ||||
|       - releases/*.tar.gz | ||||
|       - releases/*.tar.gz.sha256sum | ||||
|     skip_cleanup: true | ||||
|     on: | ||||
|       repo: containerd/containerd | ||||
|       tags: true | ||||
|       condition: $TRAVIS_GOOS = linux | ||||
|   - provider: script | ||||
|     script: bash script/release/deploy-cri | ||||
|     skip_cleanup: true | ||||
|     on: | ||||
|       repo: containerd/containerd | ||||
|       tags: true | ||||
|       condition: $TRAVIS_GOOS = linux | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/containerd/containerd/.zuul.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/containerd/containerd/.zuul.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| - project: | ||||
|     name: containerd/containerd | ||||
|     check: | ||||
|       jobs: | ||||
|         - containerd-build-arm64 | ||||
|  | ||||
| - job: | ||||
|     name: containerd-build-arm64 | ||||
|     parent: init-test | ||||
|     description: | | ||||
|       Containerd build in openlab cluster. | ||||
|     run: .zuul/playbooks/containerd-build/run.yaml | ||||
|     nodeset: ubuntu-xenial-arm64 | ||||
|     voting: false | ||||
							
								
								
									
										40
									
								
								vendor/github.com/containerd/containerd/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/containerd/containerd/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,7 +17,7 @@ | ||||
| ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) | ||||
|  | ||||
| # Base path used to install. | ||||
| DESTDIR=/usr/local | ||||
| DESTDIR ?= /usr/local | ||||
|  | ||||
| # Used to populate variables in version package. | ||||
| VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always) | ||||
| @@ -111,17 +111,17 @@ GO_GCFLAGS=$(shell				\ | ||||
| BINARIES=$(addprefix bin/,$(COMMANDS)) | ||||
|  | ||||
| # Flags passed to `go test` | ||||
| TESTFLAGS ?= -v $(TESTFLAGS_RACE) | ||||
| TESTFLAGS ?= $(TESTFLAGS_RACE) | ||||
| TESTFLAGS_PARALLEL ?= 8 | ||||
|  | ||||
| .PHONY: clean all AUTHORS build binaries test integration generate protos checkprotos coverage ci check help install uninstall vendor release mandir install-man | ||||
| .PHONY: clean all AUTHORS build binaries test integration generate protos checkprotos coverage ci check help install uninstall vendor release mandir install-man genman | ||||
| .DEFAULT: default | ||||
|  | ||||
| all: binaries | ||||
|  | ||||
| check: proto-fmt ## run all linters | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	gometalinter --config .gometalinter.json ./... | ||||
| 	GOGC=75 golangci-lint run | ||||
|  | ||||
| ci: check binaries checkprotos coverage coverage-integration ## to be used by the CI | ||||
|  | ||||
| @@ -194,10 +194,6 @@ bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and om | ||||
| 	@echo "$(WHALE) bin/containerd-shim-runc-v2" | ||||
| 	@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v2 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 | ||||
|  | ||||
| bin/containerd-shim-runhcs-v1: cmd/containerd-shim-runhcs-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 | ||||
| 	@echo "$(WHALE) bin/containerd-shim-runhcs-v1${BINARY_SUFFIX}" | ||||
| 	@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runhcs-v1${BINARY_SUFFIX} ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runhcs-v1 | ||||
|  | ||||
| binaries: $(BINARIES) ## build binaries | ||||
| 	@echo "$(WHALE) $@" | ||||
|  | ||||
| @@ -207,8 +203,19 @@ man: mandir $(addprefix man/,$(MANPAGES)) | ||||
| mandir: | ||||
| 	@mkdir -p man | ||||
|  | ||||
| # Kept for backwards compatability | ||||
| genman: man/containerd.1 man/ctr.1 | ||||
|  | ||||
| man/containerd.1: FORCE | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	go run cmd/gen-manpages/main.go containerd man/ | ||||
|  | ||||
| man/ctr.1: FORCE | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	go run cmd/gen-manpages/main.go ctr man/ | ||||
|  | ||||
| man/%: docs/man/%.md FORCE | ||||
| 	@echo "$(WHALE) $<" | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	go-md2man -in "$<" -out "$@" | ||||
|  | ||||
| define installmanpage | ||||
| @@ -220,12 +227,21 @@ install-man: | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	$(foreach manpage,$(addprefix man/,$(MANPAGES)), $(call installmanpage,$(manpage),$(subst .,,$(suffix $(manpage))),$(notdir $(manpage)))) | ||||
|  | ||||
| release: $(BINARIES) | ||||
| releases/$(RELEASE).tar.gz: $(BINARIES) | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	@rm -rf releases/$(RELEASE) releases/$(RELEASE).tar.gz | ||||
| 	@install -d releases/$(RELEASE)/bin | ||||
| 	@install $(BINARIES) releases/$(RELEASE)/bin | ||||
| 	@cd releases/$(RELEASE) && tar -czf ../$(RELEASE).tar.gz * | ||||
| 	@tar -czf releases/$(RELEASE).tar.gz -C releases/$(RELEASE) bin | ||||
| 	@rm -rf releases/$(RELEASE) | ||||
|  | ||||
| release: $(BINARIES) releases/$(RELEASE).tar.gz | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	@cd releases && sha256sum $(RELEASE).tar.gz >$(RELEASE).tar.gz.sha256sum | ||||
|  | ||||
| cri-release: $(BINARIES) releases/$(RELEASE).tar.gz | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	@VERSION=$(VERSION:v%=%) script/release/release-cri | ||||
|  | ||||
| clean: ## clean up binaries | ||||
| 	@echo "$(WHALE) $@" | ||||
| @@ -286,7 +302,7 @@ root-coverage: ## generate coverage profiles for unit tests that require root | ||||
|  | ||||
| vendor: | ||||
| 	@echo "$(WHALE) $@" | ||||
| 	@vndr | ||||
| 	@vndr -whitelist github.com/urfave/cli/autocomplete/ | ||||
|  | ||||
| help: ## this help | ||||
| 	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/containerd/containerd/Makefile.windows
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containerd/containerd/Makefile.windows
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,7 +16,6 @@ | ||||
| #Windows specific settings. | ||||
| WHALE = "+" | ||||
| ONI = "-" | ||||
| COMMANDS += containerd-shim-runhcs-v1 | ||||
|  | ||||
| BINARY_SUFFIX=".exe" | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/containerd/containerd/Protobuild.toml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/containerd/containerd/Protobuild.toml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -69,19 +69,3 @@ ignore_files = [ | ||||
| 	"google/protobuf/descriptor.proto", | ||||
| 	"gogoproto/gogo.proto" | ||||
| ] | ||||
|  | ||||
| [[descriptors]] | ||||
| prefix = "github.com/containerd/containerd/runtime/v2/runhcs/options" | ||||
| target = "runtime/v2/runhcs/options/next.pb.txt" | ||||
| ignore_files = [ | ||||
| 	"google/protobuf/descriptor.proto", | ||||
| 	"gogoproto/gogo.proto" | ||||
| ] | ||||
|  | ||||
| [[descriptors]] | ||||
| prefix = "github.com/containerd/containerd/windows/hcsshimtypes" | ||||
| target = "windows/hcsshimtypes/next.pb.txt" | ||||
| ignore_files = [ | ||||
| 	"google/protobuf/descriptor.proto", | ||||
| 	"gogoproto/gogo.proto" | ||||
| ] | ||||
|   | ||||
							
								
								
									
										30
									
								
								vendor/github.com/containerd/containerd/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/containerd/containerd/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -210,6 +210,34 @@ See [PLUGINS.md](PLUGINS.md) for how to create plugins | ||||
| Please see [RELEASES.md](RELEASES.md) for details on versioning and stability | ||||
| of containerd components. | ||||
|  | ||||
| Downloadable 64-bit Intel/AMD binaries of all official releases are available on | ||||
| our [releases page](https://github.com/containerd/containerd/releases), as well as | ||||
| auto-published to the [cri-containerd-release storage bucket](https://console.cloud.google.com/storage/browser/cri-containerd-release?pli=1). | ||||
|  | ||||
| For other architectures and distribution support, you will find that many | ||||
| Linux distributions package their own containerd and provide it across several | ||||
| architectures, such as [Canonical's Ubuntu packaging](https://launchpad.net/ubuntu/bionic/+package/containerd). | ||||
|  | ||||
| #### Enabling command auto-completion | ||||
|  | ||||
| Starting with containerd 1.4, the urfave client feature for auto-creation of bash | ||||
| autocompletion data is enabled. To use the autocomplete feature in your shell, source | ||||
| the autocomplete/bash_autocomplete file in your .bashrc file while setting the `PROG` | ||||
| variable to `ctr`: | ||||
|  | ||||
| ``` | ||||
| $ PROG=ctr source vendor/github.com/urfave/cli/autocomplete/bash_autocomplete | ||||
| ``` | ||||
|  | ||||
| #### Distribution of `ctr` autocomplete for bash | ||||
|  | ||||
| Copy `vendor/github.com/urfave/cli/autocomplete/bash_autocomplete` into | ||||
| `/etc/bash_completion.d/` and rename it to `ctr`. | ||||
|  | ||||
| Provide documentation to users to `source` this file into their shell if | ||||
| you don't place the autocomplete file in a location where it is automatically | ||||
| loaded for user's bash shell environment. | ||||
|  | ||||
| ### Communication | ||||
|  | ||||
| For async communication and long running discussions please use issues and pull requests on the github repo. | ||||
| @@ -218,7 +246,7 @@ This will be the best place to discuss design and implementation. | ||||
| For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development. | ||||
|  | ||||
| **Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com. | ||||
| [Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ) | ||||
| [Click here for an invite to docker community slack.](https://dockr.ly/slack) | ||||
|  | ||||
| ### Security audit | ||||
|  | ||||
|   | ||||
							
								
								
									
										35
									
								
								vendor/github.com/containerd/containerd/RELEASES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/containerd/containerd/RELEASES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -77,8 +77,8 @@ Support horizons will be defined corresponding to a release branch, identified | ||||
| by `<major>.<minor>`. Releases branches will be in one of several states: | ||||
|  | ||||
| - __*Next*__: The next planned release branch. | ||||
| - __*Active*__: The release is currently supported and accepting patches. | ||||
| - __*Extended*__: The release is only accepting security patches. | ||||
| - __*Active*__: The release branch is currently supported and accepting patches. | ||||
| - __*Extended*__: The release branch is only accepting security patches. | ||||
| - __*End of Life*__: The release branch is no longer supported and no new patches will be accepted. | ||||
|  | ||||
| Releases will be supported up to one year after a _minor_ release. This means that | ||||
| @@ -97,9 +97,10 @@ The current state is available in the following table: | ||||
| | [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - | | ||||
| | [0.2](https://github.com/containerd/containerd/tree/v0.2.x)         | End of Life | Apr 21, 2016      | December 5, 2017 | | ||||
| | [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.3) | End of Life | December 5, 2017  | December 5, 2018 | | ||||
| | [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.7) | Active   | April 23, 2018  | July 23, 2019 (Active), October 23, 2019 (Extended) | | ||||
| | [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.6) | Active   | October 24, 2018 | max(October 24, 2019, release of 1.3.0 + 6 months) | | ||||
| | [1.3](https://github.com/containerd/containerd/milestone/20)        | Next   | TBD  | max(TBD+1 year, release of 1.4.0 + 6 months) | | ||||
| | [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | Extended   | April 23, 2018  | October 23, 2019 | | ||||
| | [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.10) | Active   | October 24, 2018 | March 26, 2020 | | ||||
| | [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.0)  | Active   | September 26, 2019  | max(September 26, 2020, release of 1.4.0 + 6 months) | | ||||
| | [1.4](https://github.com/containerd/containerd/milestone/27)        | Next   | TBD  | max(TBD+1 year, release of 1.5.0 + 6 months) | | ||||
|  | ||||
| Note that branches and release from before 1.0 may not follow these rules. | ||||
|  | ||||
| @@ -173,6 +174,7 @@ containerd versions: | ||||
| | GRPC API         | Stable   | 1.0                | [api/](api) | | ||||
| | Metrics API      | Stable   | 1.0                | - | | ||||
| | Runtime Shim API | Stable   | 1.2                | - | | ||||
| | Daemon Config    | Stable   | 1.0			       | - | | ||||
| | Go client API    | Unstable | _future_           | [godoc](https://godoc.org/github.com/containerd/containerd) | | ||||
| | CRI GRPC API     | Unstable | v1alpha2 _current_ | [api/](https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet/apis/cri/runtime/v1alpha2) | | ||||
| | `ctr` tool       | Unstable | Out of scope       | - | | ||||
| @@ -198,6 +200,10 @@ enumerating the support services and messages. See [api/](api) for details. | ||||
| Note that new services may be added in _minor_ releases. New service methods | ||||
| and new fields on messages may be added if they are optional. | ||||
|  | ||||
| `*.pb.txt` files are generated at each API release. They prevent unintentional changes | ||||
| to the API by having a diff that the CI can run. These files are not intended to be | ||||
| consumed or used by clients. | ||||
|  | ||||
| ### Metrics API | ||||
|  | ||||
| The metrics API that outputs prometheus style metrics will be versioned independently, | ||||
| @@ -266,10 +272,23 @@ version of Kubernetes which supports that version of CRI. | ||||
| ### `ctr` tool | ||||
|  | ||||
| The `ctr` tool provides the ability to introspect and understand the containerd | ||||
| API. At this time, it is not considered a primary offering of the project. It | ||||
| may be completely refactored or have breaking changes in _minor_ releases. | ||||
| API. It is not considered a primary offering of the project and is unsupported in | ||||
| that sense. While we understand it's value as a debug tool, it may be completely | ||||
| refactored or have breaking changes in _minor_ releases. | ||||
|  | ||||
| We will try not break the tool in _patch_ releases. | ||||
| Targeting `ctr` for feature additions reflects a misunderstanding of the containerd | ||||
| architecture. Feature addition should focus on the client Go API and additions to | ||||
| `ctr` may or may not be accepted at the discretion of the maintainers. | ||||
|  | ||||
| We will do our best to not break compatibility in the tool in _patch_ releases. | ||||
|  | ||||
| ### Daemon Configuration | ||||
|  | ||||
| The daemon's configuration file, commonly located in `/etc/containerd/config.toml` | ||||
| is versioned and backwards compatible.  The `version` field in the config | ||||
| file specifies the config's version.  If no version number is specified inside | ||||
| the config file then it is assumed to be a version 1 config and parsed as such. | ||||
| Use `version = 2` to enable version 2 config. | ||||
|  | ||||
| ### Not Covered | ||||
|  | ||||
|   | ||||
							
								
								
									
										266
									
								
								vendor/github.com/containerd/containerd/api/services/diff/v1/diff.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										266
									
								
								vendor/github.com/containerd/containerd/api/services/diff/v1/diff.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,6 +9,7 @@ import ( | ||||
| 	types "github.com/containerd/containerd/api/types" | ||||
| 	proto "github.com/gogo/protobuf/proto" | ||||
| 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" | ||||
| 	types1 "github.com/gogo/protobuf/types" | ||||
| 	grpc "google.golang.org/grpc" | ||||
| 	io "io" | ||||
| 	math "math" | ||||
| @@ -29,11 +30,12 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package | ||||
|  | ||||
| type ApplyRequest struct { | ||||
| 	// Diff is the descriptor of the diff to be extracted | ||||
| 	Diff                 *types.Descriptor `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"` | ||||
| 	Mounts               []*types.Mount    `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{}          `json:"-"` | ||||
| 	XXX_unrecognized     []byte            `json:"-"` | ||||
| 	XXX_sizecache        int32             `json:"-"` | ||||
| 	Diff                 *types.Descriptor      `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"` | ||||
| 	Mounts               []*types.Mount         `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"` | ||||
| 	Payloads             map[string]*types1.Any `protobuf:"bytes,3,rep,name=payloads,proto3" json:"payloads,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` | ||||
| 	XXX_NoUnkeyedLiteral struct{}               `json:"-"` | ||||
| 	XXX_unrecognized     []byte                 `json:"-"` | ||||
| 	XXX_sizecache        int32                  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *ApplyRequest) Reset()      { *m = ApplyRequest{} } | ||||
| @@ -205,6 +207,7 @@ var xxx_messageInfo_DiffResponse proto.InternalMessageInfo | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*ApplyRequest)(nil), "containerd.services.diff.v1.ApplyRequest") | ||||
| 	proto.RegisterMapType((map[string]*types1.Any)(nil), "containerd.services.diff.v1.ApplyRequest.PayloadsEntry") | ||||
| 	proto.RegisterType((*ApplyResponse)(nil), "containerd.services.diff.v1.ApplyResponse") | ||||
| 	proto.RegisterType((*DiffRequest)(nil), "containerd.services.diff.v1.DiffRequest") | ||||
| 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.diff.v1.DiffRequest.LabelsEntry") | ||||
| @@ -216,36 +219,40 @@ func init() { | ||||
| } | ||||
|  | ||||
| var fileDescriptor_3b36a99e6faaa935 = []byte{ | ||||
| 	// 457 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4f, 0x6f, 0xd3, 0x30, | ||||
| 	0x14, 0xaf, 0xfb, 0x0f, 0xf5, 0x75, 0x48, 0xc8, 0x9a, 0x44, 0x14, 0x20, 0xaa, 0x7a, 0xea, 0x40, | ||||
| 	0x38, 0xac, 0xa0, 0x09, 0xb6, 0xcb, 0x40, 0x43, 0x5c, 0xc6, 0x25, 0xda, 0x01, 0x81, 0x04, 0x4a, | ||||
| 	0x9b, 0x97, 0xce, 0x22, 0x8d, 0xbd, 0xd8, 0xad, 0x94, 0x1b, 0xdf, 0x85, 0x8f, 0xc2, 0x65, 0x47, | ||||
| 	0x8e, 0x1c, 0x69, 0x3f, 0x09, 0xb2, 0x93, 0x40, 0x24, 0xa4, 0x12, 0x76, 0xca, 0xcb, 0xf3, 0xef, | ||||
| 	0x9f, 0xfd, 0x6c, 0x38, 0x5d, 0x70, 0x7d, 0xb9, 0x9a, 0xb1, 0xb9, 0x58, 0xfa, 0x73, 0x91, 0xea, | ||||
| 	0x90, 0xa7, 0x98, 0x45, 0xf5, 0x32, 0x94, 0xdc, 0x57, 0x98, 0xad, 0xf9, 0x1c, 0x95, 0x1f, 0xf1, | ||||
| 	0x38, 0xf6, 0xd7, 0x87, 0xf6, 0xcb, 0x64, 0x26, 0xb4, 0xa0, 0xf7, 0xfe, 0x60, 0x59, 0x85, 0x63, | ||||
| 	0x76, 0x7d, 0x7d, 0xe8, 0xee, 0x2f, 0xc4, 0x42, 0x58, 0x9c, 0x6f, 0xaa, 0x82, 0xe2, 0x1e, 0x35, | ||||
| 	0x32, 0xd5, 0xb9, 0x44, 0xe5, 0x2f, 0xc5, 0x2a, 0xd5, 0x25, 0xef, 0xe4, 0x3f, 0x78, 0x11, 0xaa, | ||||
| 	0x79, 0xc6, 0xa5, 0x16, 0x59, 0x41, 0x1e, 0x5f, 0xc1, 0xde, 0x4b, 0x29, 0x93, 0x3c, 0xc0, 0xab, | ||||
| 	0x15, 0x2a, 0x4d, 0x9f, 0x40, 0xd7, 0xa4, 0x74, 0xc8, 0x88, 0x4c, 0x86, 0xd3, 0xfb, 0xac, 0xb6, | ||||
| 	0x0d, 0xab, 0xc0, 0xce, 0x7e, 0x2b, 0x04, 0x16, 0x49, 0x7d, 0xe8, 0xdb, 0x34, 0xca, 0x69, 0x8f, | ||||
| 	0x3a, 0x93, 0xe1, 0xf4, 0xee, 0xdf, 0x9c, 0xb7, 0x66, 0x3d, 0x28, 0x61, 0xe3, 0x37, 0x70, 0xbb, | ||||
| 	0xb4, 0x54, 0x52, 0xa4, 0x0a, 0xe9, 0x11, 0xdc, 0x0a, 0xa5, 0x4c, 0x38, 0x46, 0x8d, 0x6c, 0x2b, | ||||
| 	0xf0, 0xf8, 0x6b, 0x1b, 0x86, 0x67, 0x3c, 0x8e, 0xab, 0xec, 0x8f, 0xa0, 0x9b, 0x60, 0xac, 0x1d, | ||||
| 	0xb2, 0x3b, 0x87, 0x05, 0xd1, 0xc7, 0xd0, 0xcb, 0xf8, 0xe2, 0x52, 0xff, 0x2b, 0x75, 0x81, 0xa2, | ||||
| 	0x0f, 0x00, 0x96, 0x18, 0xf1, 0xf0, 0x93, 0x59, 0x73, 0x3a, 0x23, 0x32, 0x19, 0x04, 0x03, 0xdb, | ||||
| 	0xb9, 0xc8, 0x25, 0xd2, 0x3b, 0xd0, 0xc9, 0x30, 0x76, 0xba, 0xb6, 0x6f, 0x4a, 0x7a, 0x0e, 0xfd, | ||||
| 	0x24, 0x9c, 0x61, 0xa2, 0x9c, 0x9e, 0x35, 0x78, 0xc6, 0x76, 0xdc, 0x08, 0x56, 0xdb, 0x06, 0x3b, | ||||
| 	0xb7, 0xb4, 0xd7, 0xa9, 0xce, 0xf2, 0xa0, 0xd4, 0x70, 0x5f, 0xc0, 0xb0, 0xd6, 0x36, 0x76, 0x9f, | ||||
| 	0x31, 0xb7, 0xa7, 0x35, 0x08, 0x4c, 0x49, 0xf7, 0xa1, 0xb7, 0x0e, 0x93, 0x15, 0x3a, 0x6d, 0xdb, | ||||
| 	0x2b, 0x7e, 0x8e, 0xdb, 0xcf, 0xc9, 0xf8, 0x14, 0xf6, 0x0a, 0xf5, 0xf2, 0xb4, 0xab, 0x09, 0x77, | ||||
| 	0x9a, 0x4e, 0x78, 0xfa, 0x8d, 0x40, 0xd7, 0x48, 0xd0, 0x8f, 0xd0, 0xb3, 0x93, 0xa3, 0x07, 0x3b, | ||||
| 	0x37, 0x53, 0xbf, 0x50, 0xee, 0xc3, 0x26, 0xd0, 0x32, 0xda, 0x87, 0xd2, 0x67, 0xd2, 0xf4, 0xac, | ||||
| 	0xdc, 0x83, 0x06, 0xc8, 0x42, 0xfc, 0xd5, 0xc5, 0xf5, 0xc6, 0x6b, 0xfd, 0xd8, 0x78, 0xad, 0x2f, | ||||
| 	0x5b, 0x8f, 0x5c, 0x6f, 0x3d, 0xf2, 0x7d, 0xeb, 0x91, 0x9f, 0x5b, 0x8f, 0xbc, 0x3f, 0xbe, 0xd1, | ||||
| 	0x6b, 0x3f, 0x31, 0xdf, 0x77, 0xad, 0x59, 0xdf, 0x3e, 0xa4, 0xa7, 0xbf, 0x02, 0x00, 0x00, 0xff, | ||||
| 	0xff, 0x61, 0xd1, 0x6e, 0x9e, 0x34, 0x04, 0x00, 0x00, | ||||
| 	// 526 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x4c, | ||||
| 	0x10, 0x8d, 0xed, 0x24, 0xdf, 0x97, 0x49, 0x2b, 0xa1, 0x55, 0x24, 0x8c, 0x01, 0xab, 0xca, 0x29, | ||||
| 	0x2d, 0x62, 0x4d, 0x03, 0x2a, 0xd0, 0x5e, 0x5a, 0x54, 0xc4, 0xa5, 0x48, 0x60, 0x7a, 0x40, 0x20, | ||||
| 	0x81, 0x9c, 0x78, 0xed, 0xae, 0x70, 0xbc, 0x8b, 0x77, 0x1d, 0xc9, 0x37, 0xfe, 0x06, 0x67, 0x7e, | ||||
| 	0x0a, 0x97, 0x1e, 0x39, 0x72, 0xa4, 0xf9, 0x25, 0xc8, 0xeb, 0x75, 0x31, 0x02, 0x05, 0xc3, 0xc9, | ||||
| 	0x9b, 0x9d, 0xf7, 0xde, 0xce, 0xbc, 0x37, 0x0a, 0x1c, 0xc6, 0x54, 0x9e, 0xe5, 0x33, 0x3c, 0x67, | ||||
| 	0x0b, 0x6f, 0xce, 0x52, 0x19, 0xd0, 0x94, 0x64, 0x61, 0xf3, 0x18, 0x70, 0xea, 0x09, 0x92, 0x2d, | ||||
| 	0xe9, 0x9c, 0x08, 0x2f, 0xa4, 0x51, 0xe4, 0x2d, 0x77, 0xd5, 0x17, 0xf3, 0x8c, 0x49, 0x86, 0xae, | ||||
| 	0xff, 0xc0, 0xe2, 0x1a, 0x87, 0x55, 0x7d, 0xb9, 0xeb, 0x8c, 0x62, 0x16, 0x33, 0x85, 0xf3, 0xca, | ||||
| 	0x53, 0x45, 0x71, 0xae, 0xc5, 0x8c, 0xc5, 0x09, 0xf1, 0xd4, 0xaf, 0x59, 0x1e, 0x79, 0x41, 0x5a, | ||||
| 	0xe8, 0xd2, 0x5e, 0xab, 0x7e, 0x64, 0xc1, 0x89, 0xf0, 0x16, 0x2c, 0x4f, 0xa5, 0xe6, 0x1d, 0xfc, | ||||
| 	0x05, 0x2f, 0x24, 0x62, 0x9e, 0x51, 0x2e, 0x59, 0x56, 0x91, 0xc7, 0x1f, 0x4d, 0xd8, 0x38, 0xe2, | ||||
| 	0x3c, 0x29, 0x7c, 0xf2, 0x3e, 0x27, 0x42, 0xa2, 0x3b, 0xd0, 0x2d, 0x27, 0xb0, 0x8d, 0x2d, 0x63, | ||||
| 	0x32, 0x9c, 0xde, 0xc0, 0x8d, 0x11, 0x95, 0x04, 0x3e, 0xbe, 0x94, 0xf0, 0x15, 0x12, 0x79, 0xd0, | ||||
| 	0x57, 0xed, 0x08, 0xdb, 0xdc, 0xb2, 0x26, 0xc3, 0xe9, 0xd5, 0x5f, 0x39, 0x4f, 0xcb, 0xba, 0xaf, | ||||
| 	0x61, 0xe8, 0x05, 0xfc, 0xcf, 0x83, 0x22, 0x61, 0x41, 0x28, 0x6c, 0x4b, 0x51, 0xee, 0xe3, 0x35, | ||||
| 	0x4e, 0xe2, 0x66, 0x7f, 0xf8, 0x99, 0x66, 0x3e, 0x4e, 0x65, 0x56, 0xf8, 0x97, 0x42, 0xce, 0x73, | ||||
| 	0xd8, 0xfc, 0xa9, 0x84, 0xae, 0x80, 0xf5, 0x8e, 0x14, 0x6a, 0x8e, 0x81, 0x5f, 0x1e, 0xd1, 0x0e, | ||||
| 	0xf4, 0x96, 0x41, 0x92, 0x13, 0xdb, 0x54, 0xb3, 0x8d, 0x70, 0x95, 0x05, 0xae, 0xb3, 0xc0, 0x47, | ||||
| 	0x69, 0xe1, 0x57, 0x90, 0x7d, 0xf3, 0x81, 0x31, 0x7e, 0x02, 0x9b, 0xfa, 0x69, 0xc1, 0x59, 0x2a, | ||||
| 	0x08, 0xda, 0x83, 0xff, 0x02, 0xce, 0x13, 0x4a, 0xc2, 0x56, 0xf6, 0xd4, 0xe0, 0xf1, 0x27, 0x13, | ||||
| 	0x86, 0xc7, 0x34, 0x8a, 0x6a, 0x8f, 0x6f, 0x41, 0x37, 0x21, 0x91, 0xb4, 0x8d, 0xf5, 0x7e, 0x29, | ||||
| 	0x10, 0xba, 0x0d, 0xbd, 0x8c, 0xc6, 0x67, 0xf2, 0x4f, 0xee, 0x56, 0x28, 0x74, 0x13, 0x60, 0x41, | ||||
| 	0x42, 0x1a, 0xbc, 0x2d, 0x6b, 0xb6, 0xa5, 0xa6, 0x1f, 0xa8, 0x9b, 0xd3, 0x82, 0x93, 0xd2, 0x95, | ||||
| 	0x8c, 0x44, 0x76, 0xb7, 0x72, 0x25, 0x23, 0x11, 0x3a, 0x81, 0x7e, 0x12, 0xcc, 0x48, 0x22, 0xec, | ||||
| 	0x9e, 0x7a, 0xe0, 0xde, 0xda, 0x2c, 0x1a, 0x63, 0xe0, 0x13, 0x45, 0xab, 0x82, 0xd0, 0x1a, 0xce, | ||||
| 	0x43, 0x18, 0x36, 0xae, 0x7f, 0x13, 0xc2, 0xa8, 0x19, 0xc2, 0xa0, 0x69, 0xf7, 0x21, 0x6c, 0x54, | ||||
| 	0xea, 0xda, 0xed, 0x7a, 0x13, 0xad, 0xb6, 0x9b, 0x38, 0xfd, 0x6c, 0x40, 0xb7, 0x94, 0x40, 0x6f, | ||||
| 	0xa0, 0xa7, 0x92, 0x43, 0xdb, 0xad, 0x17, 0xcb, 0xd9, 0x69, 0x03, 0xd5, 0xad, 0xbd, 0xd6, 0xef, | ||||
| 	0x4c, 0xda, 0x7a, 0xe5, 0x6c, 0xb7, 0x40, 0x56, 0xe2, 0x8f, 0x4e, 0xcf, 0x2f, 0xdc, 0xce, 0xd7, | ||||
| 	0x0b, 0xb7, 0xf3, 0x61, 0xe5, 0x1a, 0xe7, 0x2b, 0xd7, 0xf8, 0xb2, 0x72, 0x8d, 0x6f, 0x2b, 0xd7, | ||||
| 	0x78, 0xb5, 0xff, 0x4f, 0xff, 0x58, 0x07, 0xe5, 0xf7, 0x65, 0x67, 0xd6, 0x57, 0x7b, 0x7e, 0xf7, | ||||
| 	0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x85, 0x25, 0xb8, 0xf8, 0x04, 0x00, 0x00, | ||||
| } | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| @@ -400,6 +407,34 @@ func (m *ApplyRequest) MarshalTo(dAtA []byte) (int, error) { | ||||
| 			i += n | ||||
| 		} | ||||
| 	} | ||||
| 	if len(m.Payloads) > 0 { | ||||
| 		for k, _ := range m.Payloads { | ||||
| 			dAtA[i] = 0x1a | ||||
| 			i++ | ||||
| 			v := m.Payloads[k] | ||||
| 			msgSize := 0 | ||||
| 			if v != nil { | ||||
| 				msgSize = v.Size() | ||||
| 				msgSize += 1 + sovDiff(uint64(msgSize)) | ||||
| 			} | ||||
| 			mapSize := 1 + len(k) + sovDiff(uint64(len(k))) + msgSize | ||||
| 			i = encodeVarintDiff(dAtA, i, uint64(mapSize)) | ||||
| 			dAtA[i] = 0xa | ||||
| 			i++ | ||||
| 			i = encodeVarintDiff(dAtA, i, uint64(len(k))) | ||||
| 			i += copy(dAtA[i:], k) | ||||
| 			if v != nil { | ||||
| 				dAtA[i] = 0x12 | ||||
| 				i++ | ||||
| 				i = encodeVarintDiff(dAtA, i, uint64(v.Size())) | ||||
| 				n2, err := v.MarshalTo(dAtA[i:]) | ||||
| 				if err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 				i += n2 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		i += copy(dAtA[i:], m.XXX_unrecognized) | ||||
| 	} | ||||
| @@ -425,11 +460,11 @@ func (m *ApplyResponse) MarshalTo(dAtA []byte) (int, error) { | ||||
| 		dAtA[i] = 0xa | ||||
| 		i++ | ||||
| 		i = encodeVarintDiff(dAtA, i, uint64(m.Applied.Size())) | ||||
| 		n2, err := m.Applied.MarshalTo(dAtA[i:]) | ||||
| 		n3, err := m.Applied.MarshalTo(dAtA[i:]) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		i += n2 | ||||
| 		i += n3 | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		i += copy(dAtA[i:], m.XXX_unrecognized) | ||||
| @@ -530,11 +565,11 @@ func (m *DiffResponse) MarshalTo(dAtA []byte) (int, error) { | ||||
| 		dAtA[i] = 0x1a | ||||
| 		i++ | ||||
| 		i = encodeVarintDiff(dAtA, i, uint64(m.Diff.Size())) | ||||
| 		n3, err := m.Diff.MarshalTo(dAtA[i:]) | ||||
| 		n4, err := m.Diff.MarshalTo(dAtA[i:]) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		i += n3 | ||||
| 		i += n4 | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		i += copy(dAtA[i:], m.XXX_unrecognized) | ||||
| @@ -567,6 +602,19 @@ func (m *ApplyRequest) Size() (n int) { | ||||
| 			n += 1 + l + sovDiff(uint64(l)) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(m.Payloads) > 0 { | ||||
| 		for k, v := range m.Payloads { | ||||
| 			_ = k | ||||
| 			_ = v | ||||
| 			l = 0 | ||||
| 			if v != nil { | ||||
| 				l = v.Size() | ||||
| 				l += 1 + sovDiff(uint64(l)) | ||||
| 			} | ||||
| 			mapEntrySize := 1 + len(k) + sovDiff(uint64(len(k))) + l | ||||
| 			n += mapEntrySize + 1 + sovDiff(uint64(mapEntrySize)) | ||||
| 		} | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		n += len(m.XXX_unrecognized) | ||||
| 	} | ||||
| @@ -662,9 +710,20 @@ func (this *ApplyRequest) String() string { | ||||
| 	if this == nil { | ||||
| 		return "nil" | ||||
| 	} | ||||
| 	keysForPayloads := make([]string, 0, len(this.Payloads)) | ||||
| 	for k, _ := range this.Payloads { | ||||
| 		keysForPayloads = append(keysForPayloads, k) | ||||
| 	} | ||||
| 	github_com_gogo_protobuf_sortkeys.Strings(keysForPayloads) | ||||
| 	mapStringForPayloads := "map[string]*types1.Any{" | ||||
| 	for _, k := range keysForPayloads { | ||||
| 		mapStringForPayloads += fmt.Sprintf("%v: %v,", k, this.Payloads[k]) | ||||
| 	} | ||||
| 	mapStringForPayloads += "}" | ||||
| 	s := strings.Join([]string{`&ApplyRequest{`, | ||||
| 		`Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "types.Descriptor", 1) + `,`, | ||||
| 		`Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "types.Mount", 1) + `,`, | ||||
| 		`Payloads:` + mapStringForPayloads + `,`, | ||||
| 		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, | ||||
| 		`}`, | ||||
| 	}, "") | ||||
| @@ -824,6 +883,135 @@ func (m *ApplyRequest) Unmarshal(dAtA []byte) error { | ||||
| 				return err | ||||
| 			} | ||||
| 			iNdEx = postIndex | ||||
| 		case 3: | ||||
| 			if wireType != 2 { | ||||
| 				return fmt.Errorf("proto: wrong wireType = %d for field Payloads", wireType) | ||||
| 			} | ||||
| 			var msglen int | ||||
| 			for shift := uint(0); ; shift += 7 { | ||||
| 				if shift >= 64 { | ||||
| 					return ErrIntOverflowDiff | ||||
| 				} | ||||
| 				if iNdEx >= l { | ||||
| 					return io.ErrUnexpectedEOF | ||||
| 				} | ||||
| 				b := dAtA[iNdEx] | ||||
| 				iNdEx++ | ||||
| 				msglen |= int(b&0x7F) << shift | ||||
| 				if b < 0x80 { | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if msglen < 0 { | ||||
| 				return ErrInvalidLengthDiff | ||||
| 			} | ||||
| 			postIndex := iNdEx + msglen | ||||
| 			if postIndex < 0 { | ||||
| 				return ErrInvalidLengthDiff | ||||
| 			} | ||||
| 			if postIndex > l { | ||||
| 				return io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			if m.Payloads == nil { | ||||
| 				m.Payloads = make(map[string]*types1.Any) | ||||
| 			} | ||||
| 			var mapkey string | ||||
| 			var mapvalue *types1.Any | ||||
| 			for iNdEx < postIndex { | ||||
| 				entryPreIndex := iNdEx | ||||
| 				var wire uint64 | ||||
| 				for shift := uint(0); ; shift += 7 { | ||||
| 					if shift >= 64 { | ||||
| 						return ErrIntOverflowDiff | ||||
| 					} | ||||
| 					if iNdEx >= l { | ||||
| 						return io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					b := dAtA[iNdEx] | ||||
| 					iNdEx++ | ||||
| 					wire |= uint64(b&0x7F) << shift | ||||
| 					if b < 0x80 { | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
| 				fieldNum := int32(wire >> 3) | ||||
| 				if fieldNum == 1 { | ||||
| 					var stringLenmapkey uint64 | ||||
| 					for shift := uint(0); ; shift += 7 { | ||||
| 						if shift >= 64 { | ||||
| 							return ErrIntOverflowDiff | ||||
| 						} | ||||
| 						if iNdEx >= l { | ||||
| 							return io.ErrUnexpectedEOF | ||||
| 						} | ||||
| 						b := dAtA[iNdEx] | ||||
| 						iNdEx++ | ||||
| 						stringLenmapkey |= uint64(b&0x7F) << shift | ||||
| 						if b < 0x80 { | ||||
| 							break | ||||
| 						} | ||||
| 					} | ||||
| 					intStringLenmapkey := int(stringLenmapkey) | ||||
| 					if intStringLenmapkey < 0 { | ||||
| 						return ErrInvalidLengthDiff | ||||
| 					} | ||||
| 					postStringIndexmapkey := iNdEx + intStringLenmapkey | ||||
| 					if postStringIndexmapkey < 0 { | ||||
| 						return ErrInvalidLengthDiff | ||||
| 					} | ||||
| 					if postStringIndexmapkey > l { | ||||
| 						return io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) | ||||
| 					iNdEx = postStringIndexmapkey | ||||
| 				} else if fieldNum == 2 { | ||||
| 					var mapmsglen int | ||||
| 					for shift := uint(0); ; shift += 7 { | ||||
| 						if shift >= 64 { | ||||
| 							return ErrIntOverflowDiff | ||||
| 						} | ||||
| 						if iNdEx >= l { | ||||
| 							return io.ErrUnexpectedEOF | ||||
| 						} | ||||
| 						b := dAtA[iNdEx] | ||||
| 						iNdEx++ | ||||
| 						mapmsglen |= int(b&0x7F) << shift | ||||
| 						if b < 0x80 { | ||||
| 							break | ||||
| 						} | ||||
| 					} | ||||
| 					if mapmsglen < 0 { | ||||
| 						return ErrInvalidLengthDiff | ||||
| 					} | ||||
| 					postmsgIndex := iNdEx + mapmsglen | ||||
| 					if postmsgIndex < 0 { | ||||
| 						return ErrInvalidLengthDiff | ||||
| 					} | ||||
| 					if postmsgIndex > l { | ||||
| 						return io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					mapvalue = &types1.Any{} | ||||
| 					if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					iNdEx = postmsgIndex | ||||
| 				} else { | ||||
| 					iNdEx = entryPreIndex | ||||
| 					skippy, err := skipDiff(dAtA[iNdEx:]) | ||||
| 					if err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					if skippy < 0 { | ||||
| 						return ErrInvalidLengthDiff | ||||
| 					} | ||||
| 					if (iNdEx + skippy) > postIndex { | ||||
| 						return io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					iNdEx += skippy | ||||
| 				} | ||||
| 			} | ||||
| 			m.Payloads[mapkey] = mapvalue | ||||
| 			iNdEx = postIndex | ||||
| 		default: | ||||
| 			iNdEx = preIndex | ||||
| 			skippy, err := skipDiff(dAtA[iNdEx:]) | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/api/services/diff/v1/diff.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/api/services/diff/v1/diff.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ syntax = "proto3"; | ||||
| package containerd.services.diff.v1; | ||||
|  | ||||
| import weak "gogoproto/gogo.proto"; | ||||
| import "google/protobuf/any.proto"; | ||||
| import "github.com/containerd/containerd/api/types/mount.proto"; | ||||
| import "github.com/containerd/containerd/api/types/descriptor.proto"; | ||||
|  | ||||
| @@ -25,6 +26,8 @@ message ApplyRequest { | ||||
| 	containerd.types.Descriptor diff = 1; | ||||
|  | ||||
| 	repeated containerd.types.Mount mounts = 2; | ||||
|  | ||||
| 	map<string, google.protobuf.Any> payloads = 3; | ||||
| } | ||||
|  | ||||
| message ApplyResponse { | ||||
|   | ||||
							
								
								
									
										284
									
								
								vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										284
									
								
								vendor/github.com/containerd/containerd/api/services/introspection/v1/introspection.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -10,6 +10,7 @@ import ( | ||||
| 	rpc "github.com/gogo/googleapis/google/rpc" | ||||
| 	proto "github.com/gogo/protobuf/proto" | ||||
| 	github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" | ||||
| 	types1 "github.com/gogo/protobuf/types" | ||||
| 	grpc "google.golang.org/grpc" | ||||
| 	io "io" | ||||
| 	math "math" | ||||
| @@ -191,11 +192,51 @@ func (m *PluginsResponse) XXX_DiscardUnknown() { | ||||
|  | ||||
| var xxx_messageInfo_PluginsResponse proto.InternalMessageInfo | ||||
|  | ||||
| type ServerResponse struct { | ||||
| 	UUID                 string   `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *ServerResponse) Reset()      { *m = ServerResponse{} } | ||||
| func (*ServerResponse) ProtoMessage() {} | ||||
| func (*ServerResponse) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_1a14fda866f10715, []int{3} | ||||
| } | ||||
| func (m *ServerResponse) XXX_Unmarshal(b []byte) error { | ||||
| 	return m.Unmarshal(b) | ||||
| } | ||||
| func (m *ServerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	if deterministic { | ||||
| 		return xxx_messageInfo_ServerResponse.Marshal(b, m, deterministic) | ||||
| 	} else { | ||||
| 		b = b[:cap(b)] | ||||
| 		n, err := m.MarshalTo(b) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return b[:n], nil | ||||
| 	} | ||||
| } | ||||
| func (m *ServerResponse) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_ServerResponse.Merge(m, src) | ||||
| } | ||||
| func (m *ServerResponse) XXX_Size() int { | ||||
| 	return m.Size() | ||||
| } | ||||
| func (m *ServerResponse) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_ServerResponse.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_ServerResponse proto.InternalMessageInfo | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*Plugin)(nil), "containerd.services.introspection.v1.Plugin") | ||||
| 	proto.RegisterMapType((map[string]string)(nil), "containerd.services.introspection.v1.Plugin.ExportsEntry") | ||||
| 	proto.RegisterType((*PluginsRequest)(nil), "containerd.services.introspection.v1.PluginsRequest") | ||||
| 	proto.RegisterType((*PluginsResponse)(nil), "containerd.services.introspection.v1.PluginsResponse") | ||||
| 	proto.RegisterType((*ServerResponse)(nil), "containerd.services.introspection.v1.ServerResponse") | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| @@ -203,38 +244,42 @@ func init() { | ||||
| } | ||||
|  | ||||
| var fileDescriptor_1a14fda866f10715 = []byte{ | ||||
| 	// 487 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4d, 0x6f, 0xd3, 0x40, | ||||
| 	0x10, 0xcd, 0x3a, 0x69, 0xdc, 0x4c, 0xca, 0x87, 0x56, 0x15, 0x58, 0x3e, 0xb8, 0x51, 0xc4, 0x21, | ||||
| 	0x42, 0xb0, 0x56, 0x03, 0x48, 0xb4, 0x48, 0x1c, 0x22, 0x72, 0xa8, 0xd4, 0x43, 0xe5, 0x5e, 0x10, | ||||
| 	0x97, 0xca, 0x71, 0x36, 0x66, 0x85, 0xeb, 0xdd, 0xee, 0xae, 0x2d, 0x72, 0xe3, 0xc6, 0x5f, 0xcb, | ||||
| 	0x91, 0x23, 0xa7, 0x8a, 0xfa, 0x37, 0xf0, 0x03, 0x90, 0xbd, 0x76, 0x9b, 0xdc, 0x12, 0x71, 0x9b, | ||||
| 	0x79, 0x7e, 0x6f, 0xe6, 0xcd, 0x93, 0x17, 0x82, 0x98, 0xe9, 0xaf, 0xd9, 0x8c, 0x44, 0xfc, 0xda, | ||||
| 	0x8f, 0x78, 0xaa, 0x43, 0x96, 0x52, 0x39, 0x5f, 0x2f, 0x43, 0xc1, 0x7c, 0x45, 0x65, 0xce, 0x22, | ||||
| 	0xaa, 0x7c, 0x96, 0x6a, 0xc9, 0x95, 0xa0, 0x91, 0x66, 0x3c, 0xf5, 0xf3, 0xe3, 0x4d, 0x80, 0x08, | ||||
| 	0xc9, 0x35, 0xc7, 0x2f, 0x1e, 0xd4, 0xa4, 0x51, 0x92, 0x4d, 0x62, 0x7e, 0xec, 0x9e, 0x6c, 0xb5, | ||||
| 	0x59, 0x2f, 0x05, 0x55, 0xbe, 0x48, 0x42, 0xbd, 0xe0, 0xf2, 0xda, 0x2c, 0x70, 0x9f, 0xc7, 0x9c, | ||||
| 	0xc7, 0x09, 0xf5, 0xa5, 0x88, 0x7c, 0xa5, 0x43, 0x9d, 0xa9, 0xfa, 0xc3, 0x61, 0xcc, 0x63, 0x5e, | ||||
| 	0x95, 0x7e, 0x59, 0x19, 0x74, 0xf8, 0xd7, 0x82, 0xee, 0x45, 0x92, 0xc5, 0x2c, 0xc5, 0x18, 0x3a, | ||||
| 	0xe5, 0x44, 0x07, 0x0d, 0xd0, 0xa8, 0x17, 0x54, 0x35, 0x7e, 0x06, 0x16, 0x9b, 0x3b, 0x56, 0x89, | ||||
| 	0x4c, 0xba, 0xc5, 0xed, 0x91, 0x75, 0xf6, 0x29, 0xb0, 0xd8, 0x1c, 0xbb, 0xb0, 0x2f, 0xe9, 0x4d, | ||||
| 	0xc6, 0x24, 0x55, 0x4e, 0x7b, 0xd0, 0x1e, 0xf5, 0x82, 0xfb, 0x1e, 0x7f, 0x84, 0x5e, 0xe3, 0x49, | ||||
| 	0x39, 0x9d, 0x41, 0x7b, 0xd4, 0x1f, 0xbb, 0x64, 0xed, 0xec, 0xca, 0x36, 0xb9, 0xa8, 0x29, 0x93, | ||||
| 	0xce, 0xea, 0xf6, 0xa8, 0x15, 0x3c, 0x48, 0xf0, 0x25, 0xd8, 0xf4, 0xbb, 0xe0, 0x52, 0x2b, 0x67, | ||||
| 	0xaf, 0x52, 0x9f, 0x90, 0x6d, 0x42, 0x23, 0xe6, 0x0c, 0x32, 0x35, 0xda, 0x69, 0xaa, 0xe5, 0x32, | ||||
| 	0x68, 0x26, 0xe1, 0x21, 0x1c, 0x44, 0xa1, 0x08, 0x67, 0x2c, 0x61, 0x9a, 0x51, 0xe5, 0x74, 0x2b, | ||||
| 	0xd3, 0x1b, 0x18, 0x7e, 0x0d, 0xfb, 0x2c, 0x65, 0xfa, 0x8a, 0x4a, 0xe9, 0xd8, 0x03, 0x34, 0xea, | ||||
| 	0x8f, 0x31, 0x31, 0x69, 0x12, 0x29, 0x22, 0x72, 0x59, 0xa5, 0x19, 0xd8, 0x25, 0x67, 0x2a, 0xa5, | ||||
| 	0x7b, 0x0a, 0x07, 0xeb, 0xbb, 0xf0, 0x53, 0x68, 0x7f, 0xa3, 0xcb, 0x3a, 0xbe, 0xb2, 0xc4, 0x87, | ||||
| 	0xb0, 0x97, 0x87, 0x49, 0x46, 0x4d, 0x80, 0x81, 0x69, 0x4e, 0xad, 0xf7, 0x68, 0xf8, 0x12, 0x1e, | ||||
| 	0x1b, 0xbb, 0x2a, 0xa0, 0x37, 0x19, 0x55, 0x1a, 0x3b, 0x60, 0x2f, 0x58, 0xa2, 0xa9, 0x54, 0x0e, | ||||
| 	0xaa, 0xbc, 0x35, 0xed, 0xf0, 0x0a, 0x9e, 0xdc, 0x73, 0x95, 0xe0, 0xa9, 0xa2, 0xf8, 0x1c, 0x6c, | ||||
| 	0x61, 0xa0, 0x8a, 0xdc, 0x1f, 0xbf, 0xda, 0x25, 0xa2, 0x3a, 0xf2, 0x66, 0xc4, 0xf8, 0x27, 0x82, | ||||
| 	0x47, 0x67, 0xeb, 0x54, 0x9c, 0x83, 0x5d, 0xaf, 0xc4, 0x6f, 0x77, 0x99, 0xdc, 0x5c, 0xe3, 0xbe, | ||||
| 	0xdb, 0x51, 0x65, 0xee, 0x9a, 0x2c, 0x56, 0x77, 0x5e, 0xeb, 0xf7, 0x9d, 0xd7, 0xfa, 0x51, 0x78, | ||||
| 	0x68, 0x55, 0x78, 0xe8, 0x57, 0xe1, 0xa1, 0x3f, 0x85, 0x87, 0xbe, 0x9c, 0xff, 0xdf, 0x5b, 0xfc, | ||||
| 	0xb0, 0x01, 0x7c, 0xb6, 0x66, 0xdd, 0xea, 0xf7, 0x7f, 0xf3, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe6, | ||||
| 	0x72, 0xde, 0x35, 0xe4, 0x03, 0x00, 0x00, | ||||
| 	// 549 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xc1, 0x6e, 0xd3, 0x40, | ||||
| 	0x10, 0xad, 0x9d, 0x34, 0x6e, 0x37, 0xa5, 0xa0, 0x55, 0x55, 0x2c, 0x83, 0x9c, 0x28, 0xe2, 0x10, | ||||
| 	0x21, 0x58, 0xab, 0x01, 0x24, 0x5a, 0x24, 0x0e, 0x51, 0x73, 0x88, 0xd4, 0x43, 0xe5, 0xa8, 0x08, | ||||
| 	0x71, 0xa9, 0x1c, 0x67, 0x63, 0x56, 0x38, 0xde, 0xed, 0xee, 0xda, 0x22, 0x37, 0x3e, 0x2f, 0x47, | ||||
| 	0x8e, 0x9c, 0x02, 0xf5, 0x37, 0xf0, 0x01, 0xc8, 0xbb, 0x76, 0x9a, 0xdc, 0x12, 0x71, 0x9b, 0x79, | ||||
| 	0x33, 0x6f, 0xe6, 0xcd, 0xf3, 0xca, 0xc0, 0x8f, 0x88, 0xfc, 0x9a, 0x8e, 0x51, 0x48, 0x67, 0x5e, | ||||
| 	0x48, 0x13, 0x19, 0x90, 0x04, 0xf3, 0xc9, 0x7a, 0x18, 0x30, 0xe2, 0x09, 0xcc, 0x33, 0x12, 0x62, | ||||
| 	0xe1, 0x91, 0x44, 0x72, 0x2a, 0x18, 0x0e, 0x25, 0xa1, 0x89, 0x97, 0x9d, 0x6d, 0x02, 0x88, 0x71, | ||||
| 	0x2a, 0x29, 0x7c, 0xf1, 0xc0, 0x46, 0x15, 0x13, 0x6d, 0x36, 0x66, 0x67, 0xce, 0xf9, 0x56, 0x9b, | ||||
| 	0xe5, 0x9c, 0x61, 0xe1, 0xb1, 0x38, 0x90, 0x53, 0xca, 0x67, 0x7a, 0x81, 0xf3, 0x34, 0xa2, 0x34, | ||||
| 	0x8a, 0xb1, 0xc7, 0x59, 0xe8, 0x09, 0x19, 0xc8, 0x54, 0x94, 0x85, 0x67, 0x65, 0x41, 0x65, 0xe3, | ||||
| 	0x74, 0xea, 0xe1, 0x19, 0x93, 0xf3, 0xb2, 0x78, 0x12, 0xd1, 0x88, 0xaa, 0xd0, 0x2b, 0x22, 0x8d, | ||||
| 	0x76, 0xfe, 0x9a, 0xa0, 0x71, 0x1d, 0xa7, 0x11, 0x49, 0x20, 0x04, 0xf5, 0x62, 0x9d, 0x6d, 0xb4, | ||||
| 	0x8d, 0xee, 0xa1, 0xaf, 0x62, 0x78, 0x0a, 0x4c, 0x32, 0xb1, 0xcd, 0x02, 0xe9, 0x37, 0xf2, 0x65, | ||||
| 	0xcb, 0x1c, 0x5e, 0xfa, 0x26, 0x99, 0x40, 0x07, 0x1c, 0x70, 0x7c, 0x97, 0x12, 0x8e, 0x85, 0x5d, | ||||
| 	0x6b, 0xd7, 0xba, 0x87, 0xfe, 0x2a, 0x87, 0x1f, 0xc1, 0x61, 0x25, 0x58, 0xd8, 0xf5, 0x76, 0xad, | ||||
| 	0xdb, 0xec, 0x39, 0x68, 0xcd, 0x13, 0x75, 0x13, 0xba, 0x2e, 0x5b, 0xfa, 0xf5, 0xc5, 0xb2, 0xb5, | ||||
| 	0xe7, 0x3f, 0x50, 0xe0, 0x08, 0x58, 0xf8, 0x3b, 0xa3, 0x5c, 0x0a, 0x7b, 0x5f, 0xb1, 0xcf, 0xd1, | ||||
| 	0x36, 0x8e, 0x22, 0x7d, 0x06, 0x1a, 0x68, 0xee, 0x20, 0x91, 0x7c, 0xee, 0x57, 0x93, 0x60, 0x07, | ||||
| 	0x1c, 0x85, 0x01, 0x0b, 0xc6, 0x24, 0x26, 0x92, 0x60, 0x61, 0x37, 0x94, 0xe8, 0x0d, 0x0c, 0xbe, | ||||
| 	0x06, 0x07, 0x24, 0x21, 0xf2, 0x16, 0x73, 0x6e, 0x5b, 0x6d, 0xa3, 0xdb, 0xec, 0x41, 0xa4, 0x1d, | ||||
| 	0x45, 0x9c, 0x85, 0x68, 0xa4, 0xac, 0xf6, 0xad, 0xa2, 0x67, 0xc0, 0xb9, 0x73, 0x01, 0x8e, 0xd6, | ||||
| 	0x77, 0xc1, 0x27, 0xa0, 0xf6, 0x0d, 0xcf, 0x4b, 0xfb, 0x8a, 0x10, 0x9e, 0x80, 0xfd, 0x2c, 0x88, | ||||
| 	0x53, 0xac, 0x0d, 0xf4, 0x75, 0x72, 0x61, 0xbe, 0x37, 0x3a, 0x2f, 0xc1, 0xb1, 0x96, 0x2b, 0x7c, | ||||
| 	0x7c, 0x97, 0x62, 0x21, 0xa1, 0x0d, 0xac, 0x29, 0x89, 0x25, 0xe6, 0xc2, 0x36, 0x94, 0xb6, 0x2a, | ||||
| 	0xed, 0xdc, 0x82, 0xc7, 0xab, 0x5e, 0xc1, 0x68, 0x22, 0x30, 0xbc, 0x02, 0x16, 0xd3, 0x90, 0x6a, | ||||
| 	0x6e, 0xf6, 0x5e, 0xed, 0x62, 0x51, 0x69, 0x79, 0x35, 0xa2, 0x83, 0xc0, 0xf1, 0x08, 0xf3, 0x0c, | ||||
| 	0xf3, 0xd5, 0xfc, 0xe7, 0xa0, 0x9e, 0xa6, 0x64, 0xa2, 0x6f, 0xe9, 0x1f, 0xe4, 0xcb, 0x56, 0xfd, | ||||
| 	0xe6, 0x66, 0x78, 0xe9, 0x2b, 0xb4, 0xf7, 0xdb, 0x00, 0x8f, 0x86, 0xeb, 0xa3, 0x61, 0x06, 0xac, | ||||
| 	0x52, 0x22, 0x7c, 0xbb, 0x8b, 0x92, 0xea, 0x7a, 0xe7, 0xdd, 0x8e, 0xac, 0x52, 0xe7, 0x27, 0xd0, | ||||
| 	0xd0, 0xca, 0xe1, 0x69, 0xf5, 0xa5, 0xaa, 0xb7, 0x8f, 0x06, 0xc5, 0xdb, 0x77, 0xb6, 0x94, 0xb3, | ||||
| 	0x79, 0x7f, 0x7f, 0xba, 0xb8, 0x77, 0xf7, 0x7e, 0xdd, 0xbb, 0x7b, 0x3f, 0x72, 0xd7, 0x58, 0xe4, | ||||
| 	0xae, 0xf1, 0x33, 0x77, 0x8d, 0x3f, 0xb9, 0x6b, 0x7c, 0xb9, 0xfa, 0xbf, 0x1f, 0xc6, 0x87, 0x0d, | ||||
| 	0xe0, 0x73, 0x6d, 0xdc, 0x50, 0x7a, 0xdf, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xb3, 0x50, | ||||
| 	0xdc, 0x89, 0x04, 0x00, 0x00, | ||||
| } | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| @@ -254,6 +299,8 @@ type IntrospectionClient interface { | ||||
| 	// Clients can use this to detect features and capabilities when using | ||||
| 	// containerd. | ||||
| 	Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error) | ||||
| 	// Server returns information about the containerd server | ||||
| 	Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error) | ||||
| } | ||||
|  | ||||
| type introspectionClient struct { | ||||
| @@ -273,6 +320,15 @@ func (c *introspectionClient) Plugins(ctx context.Context, in *PluginsRequest, o | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| func (c *introspectionClient) Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error) { | ||||
| 	out := new(ServerResponse) | ||||
| 	err := c.cc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/Server", in, out, opts...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| // IntrospectionServer is the server API for Introspection service. | ||||
| type IntrospectionServer interface { | ||||
| 	// Plugins returns a list of plugins in containerd. | ||||
| @@ -280,6 +336,8 @@ type IntrospectionServer interface { | ||||
| 	// Clients can use this to detect features and capabilities when using | ||||
| 	// containerd. | ||||
| 	Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error) | ||||
| 	// Server returns information about the containerd server | ||||
| 	Server(context.Context, *types1.Empty) (*ServerResponse, error) | ||||
| } | ||||
|  | ||||
| func RegisterIntrospectionServer(s *grpc.Server, srv IntrospectionServer) { | ||||
| @@ -304,6 +362,24 @@ func _Introspection_Plugins_Handler(srv interface{}, ctx context.Context, dec fu | ||||
| 	return interceptor(ctx, in, info, handler) | ||||
| } | ||||
|  | ||||
| func _Introspection_Server_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||
| 	in := new(types1.Empty) | ||||
| 	if err := dec(in); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if interceptor == nil { | ||||
| 		return srv.(IntrospectionServer).Server(ctx, in) | ||||
| 	} | ||||
| 	info := &grpc.UnaryServerInfo{ | ||||
| 		Server:     srv, | ||||
| 		FullMethod: "/containerd.services.introspection.v1.Introspection/Server", | ||||
| 	} | ||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||
| 		return srv.(IntrospectionServer).Server(ctx, req.(*types1.Empty)) | ||||
| 	} | ||||
| 	return interceptor(ctx, in, info, handler) | ||||
| } | ||||
|  | ||||
| var _Introspection_serviceDesc = grpc.ServiceDesc{ | ||||
| 	ServiceName: "containerd.services.introspection.v1.Introspection", | ||||
| 	HandlerType: (*IntrospectionServer)(nil), | ||||
| @@ -312,6 +388,10 @@ var _Introspection_serviceDesc = grpc.ServiceDesc{ | ||||
| 			MethodName: "Plugins", | ||||
| 			Handler:    _Introspection_Plugins_Handler, | ||||
| 		}, | ||||
| 		{ | ||||
| 			MethodName: "Server", | ||||
| 			Handler:    _Introspection_Server_Handler, | ||||
| 		}, | ||||
| 	}, | ||||
| 	Streams:  []grpc.StreamDesc{}, | ||||
| 	Metadata: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto", | ||||
| @@ -488,6 +568,33 @@ func (m *PluginsResponse) MarshalTo(dAtA []byte) (int, error) { | ||||
| 	return i, nil | ||||
| } | ||||
|  | ||||
| func (m *ServerResponse) Marshal() (dAtA []byte, err error) { | ||||
| 	size := m.Size() | ||||
| 	dAtA = make([]byte, size) | ||||
| 	n, err := m.MarshalTo(dAtA) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return dAtA[:n], nil | ||||
| } | ||||
|  | ||||
| func (m *ServerResponse) MarshalTo(dAtA []byte) (int, error) { | ||||
| 	var i int | ||||
| 	_ = i | ||||
| 	var l int | ||||
| 	_ = l | ||||
| 	if len(m.UUID) > 0 { | ||||
| 		dAtA[i] = 0xa | ||||
| 		i++ | ||||
| 		i = encodeVarintIntrospection(dAtA, i, uint64(len(m.UUID))) | ||||
| 		i += copy(dAtA[i:], m.UUID) | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		i += copy(dAtA[i:], m.XXX_unrecognized) | ||||
| 	} | ||||
| 	return i, nil | ||||
| } | ||||
|  | ||||
| func encodeVarintIntrospection(dAtA []byte, offset int, v uint64) int { | ||||
| 	for v >= 1<<7 { | ||||
| 		dAtA[offset] = uint8(v&0x7f | 0x80) | ||||
| @@ -583,6 +690,22 @@ func (m *PluginsResponse) Size() (n int) { | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| func (m *ServerResponse) Size() (n int) { | ||||
| 	if m == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	var l int | ||||
| 	_ = l | ||||
| 	l = len(m.UUID) | ||||
| 	if l > 0 { | ||||
| 		n += 1 + l + sovIntrospection(uint64(l)) | ||||
| 	} | ||||
| 	if m.XXX_unrecognized != nil { | ||||
| 		n += len(m.XXX_unrecognized) | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| func sovIntrospection(x uint64) (n int) { | ||||
| 	for { | ||||
| 		n++ | ||||
| @@ -645,6 +768,17 @@ func (this *PluginsResponse) String() string { | ||||
| 	}, "") | ||||
| 	return s | ||||
| } | ||||
| func (this *ServerResponse) String() string { | ||||
| 	if this == nil { | ||||
| 		return "nil" | ||||
| 	} | ||||
| 	s := strings.Join([]string{`&ServerResponse{`, | ||||
| 		`UUID:` + fmt.Sprintf("%v", this.UUID) + `,`, | ||||
| 		`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, | ||||
| 		`}`, | ||||
| 	}, "") | ||||
| 	return s | ||||
| } | ||||
| func valueToStringIntrospection(v interface{}) string { | ||||
| 	rv := reflect.ValueOf(v) | ||||
| 	if rv.IsNil() { | ||||
| @@ -1206,6 +1340,92 @@ func (m *PluginsResponse) Unmarshal(dAtA []byte) error { | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| func (m *ServerResponse) Unmarshal(dAtA []byte) error { | ||||
| 	l := len(dAtA) | ||||
| 	iNdEx := 0 | ||||
| 	for iNdEx < l { | ||||
| 		preIndex := iNdEx | ||||
| 		var wire uint64 | ||||
| 		for shift := uint(0); ; shift += 7 { | ||||
| 			if shift >= 64 { | ||||
| 				return ErrIntOverflowIntrospection | ||||
| 			} | ||||
| 			if iNdEx >= l { | ||||
| 				return io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			b := dAtA[iNdEx] | ||||
| 			iNdEx++ | ||||
| 			wire |= uint64(b&0x7F) << shift | ||||
| 			if b < 0x80 { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		fieldNum := int32(wire >> 3) | ||||
| 		wireType := int(wire & 0x7) | ||||
| 		if wireType == 4 { | ||||
| 			return fmt.Errorf("proto: ServerResponse: wiretype end group for non-group") | ||||
| 		} | ||||
| 		if fieldNum <= 0 { | ||||
| 			return fmt.Errorf("proto: ServerResponse: illegal tag %d (wire type %d)", fieldNum, wire) | ||||
| 		} | ||||
| 		switch fieldNum { | ||||
| 		case 1: | ||||
| 			if wireType != 2 { | ||||
| 				return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType) | ||||
| 			} | ||||
| 			var stringLen uint64 | ||||
| 			for shift := uint(0); ; shift += 7 { | ||||
| 				if shift >= 64 { | ||||
| 					return ErrIntOverflowIntrospection | ||||
| 				} | ||||
| 				if iNdEx >= l { | ||||
| 					return io.ErrUnexpectedEOF | ||||
| 				} | ||||
| 				b := dAtA[iNdEx] | ||||
| 				iNdEx++ | ||||
| 				stringLen |= uint64(b&0x7F) << shift | ||||
| 				if b < 0x80 { | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			intStringLen := int(stringLen) | ||||
| 			if intStringLen < 0 { | ||||
| 				return ErrInvalidLengthIntrospection | ||||
| 			} | ||||
| 			postIndex := iNdEx + intStringLen | ||||
| 			if postIndex < 0 { | ||||
| 				return ErrInvalidLengthIntrospection | ||||
| 			} | ||||
| 			if postIndex > l { | ||||
| 				return io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			m.UUID = string(dAtA[iNdEx:postIndex]) | ||||
| 			iNdEx = postIndex | ||||
| 		default: | ||||
| 			iNdEx = preIndex | ||||
| 			skippy, err := skipIntrospection(dAtA[iNdEx:]) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if skippy < 0 { | ||||
| 				return ErrInvalidLengthIntrospection | ||||
| 			} | ||||
| 			if (iNdEx + skippy) < 0 { | ||||
| 				return ErrInvalidLengthIntrospection | ||||
| 			} | ||||
| 			if (iNdEx + skippy) > l { | ||||
| 				return io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) | ||||
| 			iNdEx += skippy | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if iNdEx > l { | ||||
| 		return io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| func skipIntrospection(dAtA []byte) (n int, err error) { | ||||
| 	l := len(dAtA) | ||||
| 	iNdEx := 0 | ||||
|   | ||||
| @@ -4,6 +4,7 @@ package containerd.services.introspection.v1; | ||||
|  | ||||
| import "github.com/containerd/containerd/api/types/platform.proto"; | ||||
| import "google/rpc/status.proto"; | ||||
| import "google/protobuf/empty.proto"; | ||||
| import weak "gogoproto/gogo.proto"; | ||||
|  | ||||
| option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection"; | ||||
| @@ -14,6 +15,8 @@ service Introspection { | ||||
| 	// Clients can use this to detect features and capabilities when using | ||||
| 	// containerd. | ||||
| 	rpc Plugins(PluginsRequest) returns (PluginsResponse); | ||||
| 	// Server returns information about the containerd server | ||||
| 	rpc Server(google.protobuf.Empty) returns (ServerResponse); | ||||
| } | ||||
|  | ||||
| message Plugin { | ||||
| @@ -79,3 +82,7 @@ message PluginsRequest { | ||||
| message PluginsResponse { | ||||
| 	repeated Plugin plugins = 1 [(gogoproto.nullable) = false]; | ||||
| } | ||||
|  | ||||
| message ServerResponse { | ||||
| 	string uuid = 1 [(gogoproto.customname) = "UUID"]; | ||||
| } | ||||
|   | ||||
							
								
								
									
										1228
									
								
								vendor/github.com/containerd/containerd/api/services/leases/v1/leases.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1228
									
								
								vendor/github.com/containerd/containerd/api/services/leases/v1/leases.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										38
									
								
								vendor/github.com/containerd/containerd/api/services/leases/v1/leases.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/containerd/api/services/leases/v1/leases.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,6 +22,15 @@ service Leases { | ||||
| 	// List lists all active leases, returning the full list of | ||||
| 	// leases and optionally including the referenced resources. | ||||
| 	rpc List(ListRequest) returns (ListResponse); | ||||
|  | ||||
| 	// AddResource references the resource by the provided lease. | ||||
| 	rpc AddResource(AddResourceRequest) returns (google.protobuf.Empty); | ||||
|  | ||||
| 	// DeleteResource dereferences the resource by the provided lease. | ||||
| 	rpc DeleteResource(DeleteResourceRequest) returns (google.protobuf.Empty); | ||||
|  | ||||
| 	// ListResources lists all the resources referenced by the lease. | ||||
| 	rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse); | ||||
| } | ||||
|  | ||||
| // Lease is an object which retains resources while it exists. | ||||
| @@ -62,3 +71,32 @@ message ListRequest { | ||||
| message ListResponse { | ||||
| 	repeated Lease leases = 1; | ||||
| } | ||||
|  | ||||
| message Resource { | ||||
| 	string id = 1; | ||||
|  | ||||
| 	// For snapshotter resource, there are many snapshotter types here, like | ||||
| 	// overlayfs, devmapper etc. The type will be formatted with type, | ||||
| 	// like "snapshotter/overlayfs". | ||||
| 	string type = 2; | ||||
| } | ||||
|  | ||||
| message AddResourceRequest { | ||||
| 	string id = 1; | ||||
|  | ||||
| 	Resource resource = 2 [(gogoproto.nullable) = false]; | ||||
| } | ||||
|  | ||||
| message DeleteResourceRequest { | ||||
| 	string id = 1; | ||||
|  | ||||
| 	Resource resource = 2 [(gogoproto.nullable) = false]; | ||||
| } | ||||
|  | ||||
| message ListResourcesRequest { | ||||
| 	string id = 1; | ||||
| } | ||||
|  | ||||
| message ListResourcesResponse { | ||||
| 	repeated Resource resources = 1	[(gogoproto.nullable) = false]; | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/archive/compression/compression.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/archive/compression/compression.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -180,7 +180,7 @@ func DecompressStream(archive io.Reader) (DecompressReadCloser, error) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CompressStream compresseses the dest with specified compression algorithm. | ||||
| // CompressStream compresses the dest with specified compression algorithm. | ||||
| func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { | ||||
| 	switch compression { | ||||
| 	case Uncompressed: | ||||
|   | ||||
							
								
								
									
										261
									
								
								vendor/github.com/containerd/containerd/archive/tar.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										261
									
								
								vendor/github.com/containerd/containerd/archive/tar.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -19,9 +19,7 @@ package archive | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| @@ -91,11 +89,6 @@ const ( | ||||
| 	// archives. | ||||
| 	whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix | ||||
|  | ||||
| 	// whiteoutLinkDir is a directory AUFS uses for storing hardlink links to other | ||||
| 	// layers. Normally these should not go into exported archives and all changed | ||||
| 	// hardlinks should be copied to the top layer. | ||||
| 	whiteoutLinkDir = whiteoutMetaPrefix + "plnk" | ||||
|  | ||||
| 	// whiteoutOpaqueDir file means directory has been made opaque - meaning | ||||
| 	// readdir calls to this directory do not follow to lower layers. | ||||
| 	whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq" | ||||
| @@ -117,11 +110,15 @@ func Apply(ctx context.Context, root string, r io.Reader, opts ...ApplyOpt) (int | ||||
| 	if options.Filter == nil { | ||||
| 		options.Filter = all | ||||
| 	} | ||||
| 	if options.applyFunc == nil { | ||||
| 		options.applyFunc = applyNaive | ||||
| 	} | ||||
|  | ||||
| 	return apply(ctx, root, tar.NewReader(r), options) | ||||
| 	return options.applyFunc(ctx, root, tar.NewReader(r), options) | ||||
| } | ||||
|  | ||||
| // applyNaive applies a tar stream of an OCI style diff tar. | ||||
| // applyNaive applies a tar stream of an OCI style diff tar to a directory | ||||
| // applying each file as either a whole file or whiteout. | ||||
| // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets | ||||
| func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { | ||||
| 	var ( | ||||
| @@ -131,11 +128,49 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO | ||||
| 		// may occur out of order | ||||
| 		unpackedPaths = make(map[string]struct{}) | ||||
|  | ||||
| 		// Used for aufs plink directory | ||||
| 		aufsTempdir   = "" | ||||
| 		aufsHardlinks = make(map[string]*tar.Header) | ||||
| 		convertWhiteout = options.ConvertWhiteout | ||||
| 	) | ||||
|  | ||||
| 	if convertWhiteout == nil { | ||||
| 		// handle whiteouts by removing the target files | ||||
| 		convertWhiteout = func(hdr *tar.Header, path string) (bool, error) { | ||||
| 			base := filepath.Base(path) | ||||
| 			dir := filepath.Dir(path) | ||||
| 			if base == whiteoutOpaqueDir { | ||||
| 				_, err := os.Lstat(dir) | ||||
| 				if err != nil { | ||||
| 					return false, err | ||||
| 				} | ||||
| 				err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { | ||||
| 					if err != nil { | ||||
| 						if os.IsNotExist(err) { | ||||
| 							err = nil // parent was deleted | ||||
| 						} | ||||
| 						return err | ||||
| 					} | ||||
| 					if path == dir { | ||||
| 						return nil | ||||
| 					} | ||||
| 					if _, exists := unpackedPaths[path]; !exists { | ||||
| 						err := os.RemoveAll(path) | ||||
| 						return err | ||||
| 					} | ||||
| 					return nil | ||||
| 				}) | ||||
| 				return false, err | ||||
| 			} | ||||
|  | ||||
| 			if strings.HasPrefix(base, whiteoutPrefix) { | ||||
| 				originalBase := base[len(whiteoutPrefix):] | ||||
| 				originalPath := filepath.Join(dir, originalBase) | ||||
|  | ||||
| 				return false, os.RemoveAll(originalPath) | ||||
| 			} | ||||
|  | ||||
| 			return true, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Iterate through the files in the archive. | ||||
| 	for { | ||||
| 		select { | ||||
| @@ -193,85 +228,21 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO | ||||
| 			if base == "" { | ||||
| 				parentPath = filepath.Dir(path) | ||||
| 			} | ||||
| 			if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) { | ||||
| 				err = mkdirAll(parentPath, 0755) | ||||
| 				if err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Skip AUFS metadata dirs | ||||
| 		if strings.HasPrefix(hdr.Name, whiteoutMetaPrefix) { | ||||
| 			// Regular files inside /.wh..wh.plnk can be used as hardlink targets | ||||
| 			// We don't want this directory, but we need the files in them so that | ||||
| 			// such hardlinks can be resolved. | ||||
| 			if strings.HasPrefix(hdr.Name, whiteoutLinkDir) && hdr.Typeflag == tar.TypeReg { | ||||
| 				basename := filepath.Base(hdr.Name) | ||||
| 				aufsHardlinks[basename] = hdr | ||||
| 				if aufsTempdir == "" { | ||||
| 					if aufsTempdir, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "dockerplnk"); err != nil { | ||||
| 						return 0, err | ||||
| 					} | ||||
| 					defer os.RemoveAll(aufsTempdir) | ||||
| 				} | ||||
| 				p, err := fs.RootPath(aufsTempdir, basename) | ||||
| 				if err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 				if err := createTarFile(ctx, p, root, hdr, tr); err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if hdr.Name != whiteoutOpaqueDir { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if strings.HasPrefix(base, whiteoutPrefix) { | ||||
| 			dir := filepath.Dir(path) | ||||
| 			if base == whiteoutOpaqueDir { | ||||
| 				_, err := os.Lstat(dir) | ||||
| 				if err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 				err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { | ||||
| 					if err != nil { | ||||
| 						if os.IsNotExist(err) { | ||||
| 							err = nil // parent was deleted | ||||
| 						} | ||||
| 						return err | ||||
| 					} | ||||
| 					if path == dir { | ||||
| 						return nil | ||||
| 					} | ||||
| 					if _, exists := unpackedPaths[path]; !exists { | ||||
| 						err := os.RemoveAll(path) | ||||
| 						return err | ||||
| 					} | ||||
| 					return nil | ||||
| 				}) | ||||
| 				if err != nil { | ||||
| 					return 0, err | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			originalBase := base[len(whiteoutPrefix):] | ||||
| 			originalPath := filepath.Join(dir, originalBase) | ||||
|  | ||||
| 			// Ensure originalPath is under dir | ||||
| 			if dir[len(dir)-1] != filepath.Separator { | ||||
| 				dir += string(filepath.Separator) | ||||
| 			} | ||||
| 			if !strings.HasPrefix(originalPath, dir) { | ||||
| 				return 0, errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base) | ||||
| 			} | ||||
|  | ||||
| 			if err := os.RemoveAll(originalPath); err != nil { | ||||
| 			if err := mkparent(ctx, parentPath, root, options.Parents); err != nil { | ||||
| 				return 0, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Naive whiteout convert function which handles whiteout files by | ||||
| 		// removing the target files. | ||||
| 		if err := validateWhiteout(path); err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		writeFile, err := convertWhiteout(hdr, path) | ||||
| 		if err != nil { | ||||
| 			return 0, errors.Wrapf(err, "failed to convert whiteout file %q", hdr.Name) | ||||
| 		} | ||||
| 		if !writeFile { | ||||
| 			continue | ||||
| 		} | ||||
| 		// If path exits we almost always just want to remove and replace it. | ||||
| @@ -289,26 +260,6 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO | ||||
| 		srcData := io.Reader(tr) | ||||
| 		srcHdr := hdr | ||||
|  | ||||
| 		// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so | ||||
| 		// we manually retarget these into the temporary files we extracted them into | ||||
| 		if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), whiteoutLinkDir) { | ||||
| 			linkBasename := filepath.Base(hdr.Linkname) | ||||
| 			srcHdr = aufsHardlinks[linkBasename] | ||||
| 			if srcHdr == nil { | ||||
| 				return 0, fmt.Errorf("invalid aufs hardlink") | ||||
| 			} | ||||
| 			p, err := fs.RootPath(aufsTempdir, linkBasename) | ||||
| 			if err != nil { | ||||
| 				return 0, err | ||||
| 			} | ||||
| 			tmpFile, err := os.Open(p) | ||||
| 			if err != nil { | ||||
| 				return 0, err | ||||
| 			} | ||||
| 			defer tmpFile.Close() | ||||
| 			srcData = tmpFile | ||||
| 		} | ||||
|  | ||||
| 		if err := createTarFile(ctx, path, root, srcHdr, srcData); err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| @@ -428,6 +379,66 @@ func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header | ||||
| 	return chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)) | ||||
| } | ||||
|  | ||||
| func mkparent(ctx context.Context, path, root string, parents []string) error { | ||||
| 	if dir, err := os.Lstat(path); err == nil { | ||||
| 		if dir.IsDir() { | ||||
| 			return nil | ||||
| 		} | ||||
| 		return &os.PathError{ | ||||
| 			Op:   "mkparent", | ||||
| 			Path: path, | ||||
| 			Err:  syscall.ENOTDIR, | ||||
| 		} | ||||
| 	} else if !os.IsNotExist(err) { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	i := len(path) | ||||
| 	for i > len(root) && !os.IsPathSeparator(path[i-1]) { | ||||
| 		i-- | ||||
| 	} | ||||
|  | ||||
| 	if i > len(root)+1 { | ||||
| 		if err := mkparent(ctx, path[:i-1], root, parents); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := mkdir(path, 0755); err != nil { | ||||
| 		// Check that still doesn't exist | ||||
| 		dir, err1 := os.Lstat(path) | ||||
| 		if err1 == nil && dir.IsDir() { | ||||
| 			return nil | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for _, p := range parents { | ||||
| 		ppath, err := fs.RootPath(p, path[len(root):]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		dir, err := os.Lstat(ppath) | ||||
| 		if err == nil { | ||||
| 			if !dir.IsDir() { | ||||
| 				// Replaced, do not copy attributes | ||||
| 				break | ||||
| 			} | ||||
| 			if err := copyDirInfo(dir, path); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			return copyUpXAttrs(path, ppath) | ||||
| 		} else if !os.IsNotExist(err) { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	log.G(ctx).Debugf("parent directory %q not found: default permissions(0755) used", path) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type changeWriter struct { | ||||
| 	tw        *tar.Writer | ||||
| 	source    string | ||||
| @@ -493,6 +504,12 @@ func (cw *changeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e | ||||
|  | ||||
| 		hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) | ||||
|  | ||||
| 		// truncate timestamp for compatibility. without PAX stdlib rounds timestamps instead | ||||
| 		hdr.Format = tar.FormatPAX | ||||
| 		hdr.ModTime = hdr.ModTime.Truncate(time.Second) | ||||
| 		hdr.AccessTime = time.Time{} | ||||
| 		hdr.ChangeTime = time.Time{} | ||||
|  | ||||
| 		name := p | ||||
| 		if strings.HasPrefix(name, string(filepath.Separator)) { | ||||
| 			name, err = filepath.Rel(string(filepath.Separator), name) | ||||
| @@ -598,6 +615,9 @@ func (cw *changeWriter) Close() error { | ||||
| } | ||||
|  | ||||
| func (cw *changeWriter) includeParents(hdr *tar.Header) error { | ||||
| 	if cw.addedDirs == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	name := strings.TrimRight(hdr.Name, "/") | ||||
| 	fname := filepath.Join(cw.source, name) | ||||
| 	parent := filepath.Dir(name) | ||||
| @@ -684,3 +704,26 @@ func hardlinkRootPath(root, linkname string) (string, error) { | ||||
| 	} | ||||
| 	return targetPath, nil | ||||
| } | ||||
|  | ||||
| func validateWhiteout(path string) error { | ||||
| 	base := filepath.Base(path) | ||||
| 	dir := filepath.Dir(path) | ||||
|  | ||||
| 	if base == whiteoutOpaqueDir { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if strings.HasPrefix(base, whiteoutPrefix) { | ||||
| 		originalBase := base[len(whiteoutPrefix):] | ||||
| 		originalPath := filepath.Join(dir, originalBase) | ||||
|  | ||||
| 		// Ensure originalPath is under dir | ||||
| 		if dir[len(dir)-1] != filepath.Separator { | ||||
| 			dir += string(filepath.Separator) | ||||
| 		} | ||||
| 		if !strings.HasPrefix(originalPath, dir) { | ||||
| 			return errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										38
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,7 +16,19 @@ | ||||
|  | ||||
| package archive | ||||
|  | ||||
| import "archive/tar" | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"context" | ||||
| ) | ||||
|  | ||||
| // ApplyOptions provides additional options for an Apply operation | ||||
| type ApplyOptions struct { | ||||
| 	Filter          Filter          // Filter tar headers | ||||
| 	ConvertWhiteout ConvertWhiteout // Convert whiteout files | ||||
| 	Parents         []string        // Parent directories to handle inherited attributes without CoW | ||||
|  | ||||
| 	applyFunc func(context.Context, string, *tar.Reader, ApplyOptions) (int64, error) | ||||
| } | ||||
|  | ||||
| // ApplyOpt allows setting mutable archive apply properties on creation | ||||
| type ApplyOpt func(options *ApplyOptions) error | ||||
| @@ -24,6 +36,9 @@ type ApplyOpt func(options *ApplyOptions) error | ||||
| // Filter specific files from the archive | ||||
| type Filter func(*tar.Header) (bool, error) | ||||
|  | ||||
| // ConvertWhiteout converts whiteout files from the archive | ||||
| type ConvertWhiteout func(*tar.Header, string) (bool, error) | ||||
|  | ||||
| // all allows all files | ||||
| func all(_ *tar.Header) (bool, error) { | ||||
| 	return true, nil | ||||
| @@ -36,3 +51,24 @@ func WithFilter(f Filter) ApplyOpt { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithConvertWhiteout uses the convert function to convert the whiteout files. | ||||
| func WithConvertWhiteout(c ConvertWhiteout) ApplyOpt { | ||||
| 	return func(options *ApplyOptions) error { | ||||
| 		options.ConvertWhiteout = c | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithParents provides parent directories for resolving inherited attributes | ||||
| // directory from the filesystem. | ||||
| // Inherited attributes are searched from first to last, making the first | ||||
| // element in the list the most immediate parent directory. | ||||
| // NOTE: When applying to a filesystem which supports CoW, file attributes | ||||
| // should be inherited by the filesystem. | ||||
| func WithParents(p []string) ApplyOpt { | ||||
| 	return func(options *ApplyOptions) error { | ||||
| 		options.Parents = p | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										59
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| // +build linux | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package archive | ||||
|  | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // AufsConvertWhiteout converts whiteout files for aufs. | ||||
| func AufsConvertWhiteout(_ *tar.Header, _ string) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| // OverlayConvertWhiteout converts whiteout files for overlay. | ||||
| func OverlayConvertWhiteout(hdr *tar.Header, path string) (bool, error) { | ||||
| 	base := filepath.Base(path) | ||||
| 	dir := filepath.Dir(path) | ||||
|  | ||||
| 	// if a directory is marked as opaque, we need to translate that to overlay | ||||
| 	if base == whiteoutOpaqueDir { | ||||
| 		// don't write the file itself | ||||
| 		return false, unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0) | ||||
| 	} | ||||
|  | ||||
| 	// if a file was deleted and we are using overlay, we need to create a character device | ||||
| 	if strings.HasPrefix(base, whiteoutPrefix) { | ||||
| 		originalBase := base[len(whiteoutPrefix):] | ||||
| 		originalPath := filepath.Join(dir, originalBase) | ||||
|  | ||||
| 		if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		// don't write the file itself | ||||
| 		return false, os.Chown(originalPath, hdr.Uid, hdr.Gid) | ||||
| 	} | ||||
|  | ||||
| 	return true, nil | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | ||||
| // +build !windows | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package archive | ||||
|  | ||||
| // ApplyOptions provides additional options for an Apply operation | ||||
| type ApplyOptions struct { | ||||
| 	Filter Filter // Filter tar headers | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/containerd/containerd/archive/tar_opts_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,28 +18,12 @@ | ||||
|  | ||||
| package archive | ||||
|  | ||||
| // ApplyOptions provides additional options for an Apply operation | ||||
| type ApplyOptions struct { | ||||
| 	ParentLayerPaths        []string // Parent layer paths used for Windows layer apply | ||||
| 	IsWindowsContainerLayer bool     // True if the tar stream to be applied is a Windows Container Layer | ||||
| 	Filter                  Filter   // Filter tar headers | ||||
| } | ||||
|  | ||||
| // WithParentLayers adds parent layers to the apply process this is required | ||||
| // for all Windows layers except the base layer. | ||||
| func WithParentLayers(parentPaths []string) ApplyOpt { | ||||
| 	return func(options *ApplyOptions) error { | ||||
| 		options.ParentLayerPaths = parentPaths | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AsWindowsContainerLayer indicates that the tar stream to apply is that of | ||||
| // a Windows Container Layer. The caller must be holding SeBackupPrivilege and | ||||
| // SeRestorePrivilege. | ||||
| func AsWindowsContainerLayer() ApplyOpt { | ||||
| 	return func(options *ApplyOptions) error { | ||||
| 		options.IsWindowsContainerLayer = true | ||||
| 		options.applyFunc = applyWindowsLayer | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										77
									
								
								vendor/github.com/containerd/containerd/archive/tar_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/containerd/containerd/archive/tar_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,11 +20,12 @@ package archive | ||||
|  | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"context" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/containerd/continuity/fs" | ||||
| 	"github.com/containerd/continuity/sysx" | ||||
| 	"github.com/opencontainers/runc/libcontainer/system" | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -74,10 +75,6 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { | ||||
| 	return f, err | ||||
| } | ||||
|  | ||||
| func mkdirAll(path string, perm os.FileMode) error { | ||||
| 	return os.MkdirAll(path, perm) | ||||
| } | ||||
|  | ||||
| func mkdir(path string, perm os.FileMode) error { | ||||
| 	if err := os.Mkdir(path, perm); err != nil { | ||||
| 		return err | ||||
| @@ -149,11 +146,71 @@ func getxattr(path, attr string) ([]byte, error) { | ||||
| } | ||||
|  | ||||
| func setxattr(path, key, value string) error { | ||||
| 	return sysx.LSetxattr(path, key, []byte(value), 0) | ||||
| 	// Do not set trusted attributes | ||||
| 	if strings.HasPrefix(key, "trusted.") { | ||||
| 		return errors.Wrap(unix.ENOTSUP, "admin attributes from archive not supported") | ||||
| 	} | ||||
| 	return unix.Lsetxattr(path, key, []byte(value), 0) | ||||
| } | ||||
|  | ||||
| // apply applies a tar stream of an OCI style diff tar. | ||||
| // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets | ||||
| func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { | ||||
| 	return applyNaive(ctx, root, tr, options) | ||||
| func copyDirInfo(fi os.FileInfo, path string) error { | ||||
| 	st := fi.Sys().(*syscall.Stat_t) | ||||
| 	if err := os.Lchown(path, int(st.Uid), int(st.Gid)); err != nil { | ||||
| 		if os.IsPermission(err) { | ||||
| 			// Normally if uid/gid are the same this would be a no-op, but some | ||||
| 			// filesystems may still return EPERM... for instance NFS does this. | ||||
| 			// In such a case, this is not an error. | ||||
| 			if dstStat, err2 := os.Lstat(path); err2 == nil { | ||||
| 				st2 := dstStat.Sys().(*syscall.Stat_t) | ||||
| 				if st.Uid == st2.Uid && st.Gid == st2.Gid { | ||||
| 					err = nil | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(err, "failed to chown %s", path) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := os.Chmod(path, fi.Mode()); err != nil { | ||||
| 		return errors.Wrapf(err, "failed to chmod %s", path) | ||||
| 	} | ||||
|  | ||||
| 	timespec := []unix.Timespec{unix.Timespec(fs.StatAtime(st)), unix.Timespec(fs.StatMtime(st))} | ||||
| 	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { | ||||
| 		return errors.Wrapf(err, "failed to utime %s", path) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func copyUpXAttrs(dst, src string) error { | ||||
| 	xattrKeys, err := sysx.LListxattr(src) | ||||
| 	if err != nil { | ||||
| 		if err == unix.ENOTSUP || err == sysx.ENODATA { | ||||
| 			return nil | ||||
| 		} | ||||
| 		return errors.Wrapf(err, "failed to list xattrs on %s", src) | ||||
| 	} | ||||
| 	for _, xattr := range xattrKeys { | ||||
| 		// Do not copy up trusted attributes | ||||
| 		if strings.HasPrefix(xattr, "trusted.") { | ||||
| 			continue | ||||
| 		} | ||||
| 		data, err := sysx.LGetxattr(src, xattr) | ||||
| 		if err != nil { | ||||
| 			if err == unix.ENOTSUP || err == sysx.ENODATA { | ||||
| 				continue | ||||
| 			} | ||||
| 			return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) | ||||
| 		} | ||||
| 		if err := unix.Lsetxattr(dst, xattr, data, unix.XATTR_CREATE); err != nil { | ||||
| 			if err == unix.ENOTSUP || err == unix.ENODATA || err == unix.EEXIST { | ||||
| 				continue | ||||
| 			} | ||||
| 			return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										31
									
								
								vendor/github.com/containerd/containerd/archive/tar_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/containerd/containerd/archive/tar_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,7 +23,6 @@ import ( | ||||
| 	"bufio" | ||||
| 	"context" | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| @@ -36,6 +35,7 @@ import ( | ||||
| 	"github.com/Microsoft/go-winio" | ||||
| 	"github.com/Microsoft/hcsshim" | ||||
| 	"github.com/containerd/containerd/sys" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -107,10 +107,6 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { | ||||
| 	return sys.OpenFileSequential(name, flag, perm) | ||||
| } | ||||
|  | ||||
| func mkdirAll(path string, perm os.FileMode) error { | ||||
| 	return sys.MkdirAll(path, perm) | ||||
| } | ||||
|  | ||||
| func mkdir(path string, perm os.FileMode) error { | ||||
| 	return os.Mkdir(path, perm) | ||||
| } | ||||
| @@ -153,16 +149,8 @@ func setxattr(path, key, value string) error { | ||||
| 	return errors.New("xattrs not supported on Windows") | ||||
| } | ||||
|  | ||||
| // apply applies a tar stream of an OCI style diff tar of a Windows layer. | ||||
| // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets | ||||
| func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { | ||||
| 	if options.IsWindowsContainerLayer { | ||||
| 		return applyWindowsLayer(ctx, root, tr, options) | ||||
| 	} | ||||
| 	return applyNaive(ctx, root, tr, options) | ||||
| } | ||||
|  | ||||
| // applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows layer. | ||||
| // applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows | ||||
| // layer using the hcsshim layer writer and backup streams. | ||||
| // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets | ||||
| func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { | ||||
| 	home, id := filepath.Split(root) | ||||
| @@ -170,7 +158,7 @@ func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options | ||||
| 		HomeDir: home, | ||||
| 	} | ||||
|  | ||||
| 	w, err := hcsshim.NewLayerWriter(info, id, options.ParentLayerPaths) | ||||
| 	w, err := hcsshim.NewLayerWriter(info, id, options.Parents) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| @@ -443,3 +431,14 @@ func writeBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) ( | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func copyDirInfo(fi os.FileInfo, path string) error { | ||||
| 	if err := os.Chmod(path, fi.Mode()); err != nil { | ||||
| 		return errors.Wrapf(err, "failed to chmod %s", path) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func copyUpXAttrs(dst, src string) error { | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/archive/time_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/archive/time_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,7 +32,7 @@ func chtimes(path string, atime, mtime time.Time) error { | ||||
| 	utimes[1] = unix.NsecToTimespec(mtime.UnixNano()) | ||||
|  | ||||
| 	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil { | ||||
| 		return errors.Wrap(err, "failed call to UtimesNanoAt") | ||||
| 		return errors.Wrapf(err, "failed call to UtimesNanoAt for %s", path) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|   | ||||
							
								
								
									
										29
									
								
								vendor/github.com/containerd/containerd/cio/io.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containerd/containerd/cio/io.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,10 +18,13 @@ package cio | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/containerd/containerd/defaults" | ||||
| @@ -242,17 +245,24 @@ func LogURI(uri *url.URL) Creator { | ||||
| // BinaryIO forwards container STDOUT|STDERR directly to a logging binary | ||||
| func BinaryIO(binary string, args map[string]string) Creator { | ||||
| 	return func(_ string) (IO, error) { | ||||
| 		binary = filepath.Clean(binary) | ||||
| 		if !strings.HasPrefix(binary, "/") { | ||||
| 			return nil, errors.New("absolute path needed") | ||||
| 		} | ||||
| 		uri := &url.URL{ | ||||
| 			Scheme: "binary", | ||||
| 			Host:   binary, | ||||
| 			Path:   binary, | ||||
| 		} | ||||
| 		q := uri.Query() | ||||
| 		for k, v := range args { | ||||
| 			uri.Query().Set(k, v) | ||||
| 			q.Set(k, v) | ||||
| 		} | ||||
| 		uri.RawQuery = q.Encode() | ||||
| 		res := uri.String() | ||||
| 		return &logURI{ | ||||
| 			config: Config{ | ||||
| 				Stdout: uri.String(), | ||||
| 				Stderr: uri.String(), | ||||
| 				Stdout: res, | ||||
| 				Stderr: res, | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
| @@ -262,14 +272,19 @@ func BinaryIO(binary string, args map[string]string) Creator { | ||||
| // If the log file already exists, the logs will be appended to the file. | ||||
| func LogFile(path string) Creator { | ||||
| 	return func(_ string) (IO, error) { | ||||
| 		path = filepath.Clean(path) | ||||
| 		if !strings.HasPrefix(path, "/") { | ||||
| 			return nil, errors.New("absolute path needed") | ||||
| 		} | ||||
| 		uri := &url.URL{ | ||||
| 			Scheme: "file", | ||||
| 			Host:   path, | ||||
| 			Path:   path, | ||||
| 		} | ||||
| 		res := uri.String() | ||||
| 		return &logURI{ | ||||
| 			config: Config{ | ||||
| 				Stdout: uri.String(), | ||||
| 				Stderr: uri.String(), | ||||
| 				Stdout: res, | ||||
| 				Stderr: res, | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										20
									
								
								vendor/github.com/containerd/containerd/cio/io_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/containerd/containerd/cio/io_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -72,17 +72,19 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) { | ||||
| 	} | ||||
|  | ||||
| 	var wg = &sync.WaitGroup{} | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		p := bufPool.Get().(*[]byte) | ||||
| 		defer bufPool.Put(p) | ||||
| 	if fifos.Stdout != "" { | ||||
| 		wg.Add(1) | ||||
| 		go func() { | ||||
| 			p := bufPool.Get().(*[]byte) | ||||
| 			defer bufPool.Put(p) | ||||
|  | ||||
| 		io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p) | ||||
| 		pipes.Stdout.Close() | ||||
| 		wg.Done() | ||||
| 	}() | ||||
| 			io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p) | ||||
| 			pipes.Stdout.Close() | ||||
| 			wg.Done() | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	if !fifos.Terminal { | ||||
| 	if !fifos.Terminal && fifos.Stderr != "" { | ||||
| 		wg.Add(1) | ||||
| 		go func() { | ||||
| 			p := bufPool.Get().(*[]byte) | ||||
|   | ||||
							
								
								
									
										159
									
								
								vendor/github.com/containerd/containerd/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										159
									
								
								vendor/github.com/containerd/containerd/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,6 +43,7 @@ import ( | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	contentproxy "github.com/containerd/containerd/content/proxy" | ||||
| 	"github.com/containerd/containerd/defaults" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/events" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/leases" | ||||
| @@ -56,6 +57,7 @@ import ( | ||||
| 	"github.com/containerd/containerd/snapshots" | ||||
| 	snproxy "github.com/containerd/containerd/snapshots/proxy" | ||||
| 	"github.com/containerd/typeurl" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| 	ptypes "github.com/gogo/protobuf/types" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| @@ -86,13 +88,23 @@ func New(address string, opts ...ClientOpt) (*Client, error) { | ||||
| 	if copts.timeout == 0 { | ||||
| 		copts.timeout = 10 * time.Second | ||||
| 	} | ||||
| 	rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS) | ||||
| 	if copts.defaultRuntime != "" { | ||||
| 		rt = copts.defaultRuntime | ||||
| 	} | ||||
|  | ||||
| 	c := &Client{ | ||||
| 		runtime: rt, | ||||
| 		defaultns: copts.defaultns, | ||||
| 	} | ||||
|  | ||||
| 	if copts.defaultRuntime != "" { | ||||
| 		c.runtime = copts.defaultRuntime | ||||
| 	} else { | ||||
| 		c.runtime = defaults.DefaultRuntime | ||||
| 	} | ||||
|  | ||||
| 	if copts.defaultPlatform != nil { | ||||
| 		c.platform = copts.defaultPlatform | ||||
| 	} else { | ||||
| 		c.platform = platforms.Default() | ||||
| 	} | ||||
|  | ||||
| 	if copts.services != nil { | ||||
| 		c.services = *copts.services | ||||
| 	} | ||||
| @@ -102,7 +114,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) { | ||||
| 			grpc.WithInsecure(), | ||||
| 			grpc.FailOnNonTempDialError(true), | ||||
| 			grpc.WithBackoffMaxDelay(3 * time.Second), | ||||
| 			grpc.WithDialer(dialer.Dialer), | ||||
| 			grpc.WithContextDialer(dialer.ContextDialer), | ||||
|  | ||||
| 			// TODO(stevvooe): We may need to allow configuration of this on the client. | ||||
| 			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), | ||||
| @@ -134,19 +146,15 @@ func New(address string, opts ...ClientOpt) (*Client, error) { | ||||
| 		c.conn, c.connector = conn, connector | ||||
| 	} | ||||
| 	if copts.services == nil && c.conn == nil { | ||||
| 		return nil, errors.New("no grpc connection or services is available") | ||||
| 		return nil, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection or services is available") | ||||
| 	} | ||||
|  | ||||
| 	// check namespace labels for default runtime | ||||
| 	if copts.defaultRuntime == "" && copts.defaultns != "" { | ||||
| 		namespaces := c.NamespaceService() | ||||
| 		ctx := context.Background() | ||||
| 		if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { | ||||
| 			if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { | ||||
| 				c.runtime = defaultRuntime | ||||
| 			} | ||||
| 		} else { | ||||
| 	if copts.defaultRuntime == "" && c.defaultns != "" { | ||||
| 		if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { | ||||
| 			return nil, err | ||||
| 		} else if label != "" { | ||||
| 			c.runtime = label | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -163,20 +171,17 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { | ||||
| 		} | ||||
| 	} | ||||
| 	c := &Client{ | ||||
| 		conn:    conn, | ||||
| 		runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS), | ||||
| 		defaultns: copts.defaultns, | ||||
| 		conn:      conn, | ||||
| 		runtime:   fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS), | ||||
| 	} | ||||
|  | ||||
| 	// check namespace labels for default runtime | ||||
| 	if copts.defaultRuntime == "" && copts.defaultns != "" { | ||||
| 		namespaces := c.NamespaceService() | ||||
| 		ctx := context.Background() | ||||
| 		if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { | ||||
| 			if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { | ||||
| 				c.runtime = defaultRuntime | ||||
| 			} | ||||
| 		} else { | ||||
| 	if copts.defaultRuntime == "" && c.defaultns != "" { | ||||
| 		if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { | ||||
| 			return nil, err | ||||
| 		} else if label != "" { | ||||
| 			c.runtime = label | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -193,13 +198,15 @@ type Client struct { | ||||
| 	connMu    sync.Mutex | ||||
| 	conn      *grpc.ClientConn | ||||
| 	runtime   string | ||||
| 	defaultns string | ||||
| 	platform  platforms.MatchComparer | ||||
| 	connector func() (*grpc.ClientConn, error) | ||||
| } | ||||
|  | ||||
| // Reconnect re-establishes the GRPC connection to the containerd daemon | ||||
| func (c *Client) Reconnect() error { | ||||
| 	if c.connector == nil { | ||||
| 		return errors.New("unable to reconnect to containerd, no connector available") | ||||
| 		return errors.Wrap(errdefs.ErrUnavailable, "unable to reconnect to containerd, no connector available") | ||||
| 	} | ||||
| 	c.connMu.Lock() | ||||
| 	defer c.connMu.Unlock() | ||||
| @@ -222,10 +229,10 @@ func (c *Client) IsServing(ctx context.Context) (bool, error) { | ||||
| 	c.connMu.Lock() | ||||
| 	if c.conn == nil { | ||||
| 		c.connMu.Unlock() | ||||
| 		return false, errors.New("no grpc connection available") | ||||
| 		return false, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") | ||||
| 	} | ||||
| 	c.connMu.Unlock() | ||||
| 	r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.FailFast(false)) | ||||
| 	r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true)) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| @@ -294,10 +301,14 @@ type RemoteContext struct { | ||||
| 	PlatformMatcher platforms.MatchComparer | ||||
|  | ||||
| 	// Unpack is done after an image is pulled to extract into a snapshotter. | ||||
| 	// It is done simultaneously for schema 2 images when they are pulled. | ||||
| 	// If an image is not unpacked on pull, it can be unpacked any time | ||||
| 	// afterwards. Unpacking is required to run an image. | ||||
| 	Unpack bool | ||||
|  | ||||
| 	// UnpackOpts handles options to the unpack call. | ||||
| 	UnpackOpts []UnpackOpt | ||||
|  | ||||
| 	// Snapshotter used for unpacking | ||||
| 	Snapshotter string | ||||
|  | ||||
| @@ -329,9 +340,8 @@ type RemoteContext struct { | ||||
| 	// MaxConcurrentDownloads is the max concurrent content downloads for each pull. | ||||
| 	MaxConcurrentDownloads int | ||||
|  | ||||
| 	// AppendDistributionSourceLabel allows fetcher to add distribute source | ||||
| 	// label for each blob content, which doesn't work for legacy schema1. | ||||
| 	AppendDistributionSourceLabel bool | ||||
| 	// AllMetadata downloads all manifests and known-configuration files | ||||
| 	AllMetadata bool | ||||
| } | ||||
|  | ||||
| func defaultRemoteContext() *RemoteContext { | ||||
| @@ -339,7 +349,6 @@ func defaultRemoteContext() *RemoteContext { | ||||
| 		Resolver: docker.NewResolver(docker.ResolverOptions{ | ||||
| 			Client: http.DefaultClient, | ||||
| 		}), | ||||
| 		Snapshotter: DefaultSnapshotter, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -354,7 +363,7 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag | ||||
| 	} | ||||
|  | ||||
| 	if fetchCtx.Unpack { | ||||
| 		return images.Image{}, errors.New("unpack on fetch not supported, try pull") | ||||
| 		return images.Image{}, errors.Wrap(errdefs.ErrNotImplemented, "unpack on fetch not supported, try pull") | ||||
| 	} | ||||
|  | ||||
| 	if fetchCtx.PlatformMatcher == nil { | ||||
| @@ -407,6 +416,11 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Annotate ref with digest to push only push tag for single digest | ||||
| 	if !strings.Contains(ref, "@") { | ||||
| 		ref = ref + "@" + desc.Digest.String() | ||||
| 	} | ||||
|  | ||||
| 	pusher, err := pushCtx.Resolver.Pusher(ctx, ref) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -490,6 +504,27 @@ func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref s | ||||
| 	return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) | ||||
| } | ||||
|  | ||||
| // GetLabel gets a label value from namespace store | ||||
| // If there is no default label, an empty string returned with nil error | ||||
| func (c *Client) GetLabel(ctx context.Context, label string) (string, error) { | ||||
| 	ns, err := namespaces.NamespaceRequired(ctx) | ||||
| 	if err != nil { | ||||
| 		if c.defaultns == "" { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		ns = c.defaultns | ||||
| 	} | ||||
|  | ||||
| 	srv := c.NamespaceService() | ||||
| 	labels, err := srv.Labels(ctx, ns) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	value := labels[label] | ||||
| 	return value, nil | ||||
| } | ||||
|  | ||||
| // Subscribe to events that match one or more of the provided filters. | ||||
| // | ||||
| // Callers should listen on both the envelope and errs channels. If the errs | ||||
| @@ -543,6 +578,10 @@ func (c *Client) ContentStore() content.Store { | ||||
|  | ||||
| // SnapshotService returns the underlying snapshotter for the provided snapshotter name | ||||
| func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter { | ||||
| 	snapshotterName, err := c.resolveSnapshotterName(context.Background(), snapshotterName) | ||||
| 	if err != nil { | ||||
| 		snapshotterName = DefaultSnapshotter | ||||
| 	} | ||||
| 	if c.snapshotters != nil { | ||||
| 		return c.snapshotters[snapshotterName] | ||||
| 	} | ||||
| @@ -642,7 +681,7 @@ func (c *Client) Version(ctx context.Context) (Version, error) { | ||||
| 	c.connMu.Lock() | ||||
| 	if c.conn == nil { | ||||
| 		c.connMu.Unlock() | ||||
| 		return Version{}, errors.New("no grpc connection available") | ||||
| 		return Version{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") | ||||
| 	} | ||||
| 	c.connMu.Unlock() | ||||
| 	response, err := c.VersionService().Version(ctx, &ptypes.Empty{}) | ||||
| @@ -655,6 +694,58 @@ func (c *Client) Version(ctx context.Context) (Version, error) { | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type ServerInfo struct { | ||||
| 	UUID string | ||||
| } | ||||
|  | ||||
| func (c *Client) Server(ctx context.Context) (ServerInfo, error) { | ||||
| 	c.connMu.Lock() | ||||
| 	if c.conn == nil { | ||||
| 		c.connMu.Unlock() | ||||
| 		return ServerInfo{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") | ||||
| 	} | ||||
| 	c.connMu.Unlock() | ||||
|  | ||||
| 	response, err := c.IntrospectionService().Server(ctx, &types.Empty{}) | ||||
| 	if err != nil { | ||||
| 		return ServerInfo{}, err | ||||
| 	} | ||||
| 	return ServerInfo{ | ||||
| 		UUID: response.UUID, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) { | ||||
| 	if name == "" { | ||||
| 		label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
|  | ||||
| 		if label != "" { | ||||
| 			name = label | ||||
| 		} else { | ||||
| 			name = DefaultSnapshotter | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return name, nil | ||||
| } | ||||
|  | ||||
| func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { | ||||
| 	name, err := c.resolveSnapshotterName(ctx, name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	s := c.SnapshotService(name) | ||||
| 	if s == nil { | ||||
| 		return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name) | ||||
| 	} | ||||
|  | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // CheckRuntime returns true if the current runtime matches the expected | ||||
| // runtime. Providing various parts of the runtime schema will match those | ||||
| // parts of the expected runtime | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/containerd/client_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/containerd/client_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -26,11 +26,12 @@ import ( | ||||
| ) | ||||
|  | ||||
| type clientOpts struct { | ||||
| 	defaultns      string | ||||
| 	defaultRuntime string | ||||
| 	services       *services | ||||
| 	dialOptions    []grpc.DialOption | ||||
| 	timeout        time.Duration | ||||
| 	defaultns       string | ||||
| 	defaultRuntime  string | ||||
| 	defaultPlatform platforms.MatchComparer | ||||
| 	services        *services | ||||
| 	dialOptions     []grpc.DialOption | ||||
| 	timeout         time.Duration | ||||
| } | ||||
|  | ||||
| // ClientOpt allows callers to set options on the containerd client | ||||
| @@ -55,6 +56,14 @@ func WithDefaultRuntime(rt string) ClientOpt { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDefaultPlatform sets the default platform matcher on the client | ||||
| func WithDefaultPlatform(platform platforms.MatchComparer) ClientOpt { | ||||
| 	return func(c *clientOpts) error { | ||||
| 		c.defaultPlatform = platform | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDialOpts allows grpc.DialOptions to be set on the connection | ||||
| func WithDialOpts(opts []grpc.DialOption) ClientOpt { | ||||
| 	return func(c *clientOpts) error { | ||||
| @@ -195,11 +204,10 @@ func WithMaxConcurrentDownloads(max int) RemoteOpt { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithAppendDistributionSourceLabel allows fetcher to add distribute source | ||||
| // label for each blob content, which doesn't work for legacy schema1. | ||||
| func WithAppendDistributionSourceLabel() RemoteOpt { | ||||
| // WithAllMetadata downloads all manifests and known-configuration files | ||||
| func WithAllMetadata() RemoteOpt { | ||||
| 	return func(_ *Client, c *RemoteContext) error { | ||||
| 		c.AppendDistributionSourceLabel = true | ||||
| 		c.AllMetadata = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										41
									
								
								vendor/github.com/containerd/containerd/container.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/containerd/containerd/container.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -25,6 +25,7 @@ import ( | ||||
|  | ||||
| 	"github.com/containerd/containerd/api/services/tasks/v1" | ||||
| 	"github.com/containerd/containerd/api/types" | ||||
| 	tasktypes "github.com/containerd/containerd/api/types/task" | ||||
| 	"github.com/containerd/containerd/cio" | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| @@ -49,7 +50,7 @@ type Container interface { | ||||
| 	// ID identifies the container | ||||
| 	ID() string | ||||
| 	// Info returns the underlying container record type | ||||
| 	Info(context.Context) (containers.Container, error) | ||||
| 	Info(context.Context, ...InfoOpts) (containers.Container, error) | ||||
| 	// Delete removes the container | ||||
| 	Delete(context.Context, ...DeleteOpts) error | ||||
| 	// NewTask creates a new task based on the container metadata | ||||
| @@ -80,16 +81,18 @@ type Container interface { | ||||
|  | ||||
| func containerFromRecord(client *Client, c containers.Container) *container { | ||||
| 	return &container{ | ||||
| 		client: client, | ||||
| 		id:     c.ID, | ||||
| 		client:   client, | ||||
| 		id:       c.ID, | ||||
| 		metadata: c, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var _ = (Container)(&container{}) | ||||
|  | ||||
| type container struct { | ||||
| 	client *Client | ||||
| 	id     string | ||||
| 	client   *Client | ||||
| 	id       string | ||||
| 	metadata containers.Container | ||||
| } | ||||
|  | ||||
| // ID returns the container's unique id | ||||
| @@ -97,8 +100,22 @@ func (c *container) ID() string { | ||||
| 	return c.id | ||||
| } | ||||
|  | ||||
| func (c *container) Info(ctx context.Context) (containers.Container, error) { | ||||
| 	return c.get(ctx) | ||||
| func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Container, error) { | ||||
| 	i := &InfoConfig{ | ||||
| 		// default to refreshing the container's local metadata | ||||
| 		Refresh: true, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(i) | ||||
| 	} | ||||
| 	if i.Refresh { | ||||
| 		metadata, err := c.get(ctx) | ||||
| 		if err != nil { | ||||
| 			return c.metadata, err | ||||
| 		} | ||||
| 		c.metadata = metadata | ||||
| 	} | ||||
| 	return c.metadata, nil | ||||
| } | ||||
|  | ||||
| func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) { | ||||
| @@ -217,7 +234,11 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N | ||||
| 		} | ||||
|  | ||||
| 		// get the rootfs from the snapshotter and add it to the request | ||||
| 		mounts, err := c.client.SnapshotService(r.Snapshotter).Mounts(ctx, r.SnapshotKey) | ||||
| 		s, err := c.client.getSnapshotter(ctx, r.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		mounts, err := s.Mounts(ctx, r.SnapshotKey) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -362,7 +383,9 @@ func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, er | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var i cio.IO | ||||
| 	if ioAttach != nil { | ||||
| 	if ioAttach != nil && response.Process.Status != tasktypes.StatusUnknown { | ||||
| 		// Do not attach IO for task in unknown state, because there | ||||
| 		// are no fifo paths anyway. | ||||
| 		if i, err = attachExistingIO(response, ioAttach); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										88
									
								
								vendor/github.com/containerd/containerd/container_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/containerd/containerd/container_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,11 +20,8 @@ import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	"github.com/containerd/containerd/defaults" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/namespaces" | ||||
| 	"github.com/containerd/containerd/oci" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/containerd/containerd/snapshots" | ||||
| 	"github.com/containerd/typeurl" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| @@ -41,6 +38,15 @@ type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Co | ||||
| // UpdateContainerOpts allows the caller to set additional options when updating a container | ||||
| type UpdateContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error | ||||
|  | ||||
| // InfoOpts controls how container metadata is fetched and returned | ||||
| type InfoOpts func(*InfoConfig) | ||||
|  | ||||
| // InfoConfig specifies how container metadata is fetched | ||||
| type InfoConfig struct { | ||||
| 	// Refresh will to a fetch of the latest container metadata | ||||
| 	Refresh bool | ||||
| } | ||||
|  | ||||
| // WithRuntime allows a user to specify the runtime name and additional options that should | ||||
| // be used to create tasks for the container | ||||
| func WithRuntime(name string, options interface{}) NewContainerOpts { | ||||
| @@ -71,6 +77,14 @@ func WithImage(i Image) NewContainerOpts { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithImageName allows setting the image name as the base for the container | ||||
| func WithImageName(n string) NewContainerOpts { | ||||
| 	return func(ctx context.Context, _ *Client, c *containers.Container) error { | ||||
| 		c.Image = n | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithContainerLabels adds the provided labels to the container | ||||
| func WithContainerLabels(labels map[string]string) NewContainerOpts { | ||||
| 	return func(_ context.Context, _ *Client, c *containers.Container) error { | ||||
| @@ -109,9 +123,17 @@ func WithSnapshotter(name string) NewContainerOpts { | ||||
| // WithSnapshot uses an existing root filesystem for the container | ||||
| func WithSnapshot(id string) NewContainerOpts { | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		setSnapshotterIfEmpty(ctx, client, c) | ||||
| 		// check that the snapshot exists, if not, fail on creation | ||||
| 		if _, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, id); err != nil { | ||||
| 		var err error | ||||
| 		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		s, err := client.getSnapshotter(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := s.Mounts(ctx, id); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		c.SnapshotKey = id | ||||
| @@ -123,13 +145,21 @@ func WithSnapshot(id string) NewContainerOpts { | ||||
| // root filesystem in read-write mode | ||||
| func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) | ||||
| 		diffIDs, err := i.RootFS(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		setSnapshotterIfEmpty(ctx, client, c) | ||||
|  | ||||
| 		parent := identity.ChainID(diffIDs).String() | ||||
| 		if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent, opts...); err != nil { | ||||
| 		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		s, err := client.getSnapshotter(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := s.Prepare(ctx, id, parent, opts...); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		c.SnapshotKey = id | ||||
| @@ -144,7 +174,13 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta | ||||
| 		if c.Snapshotter == "" { | ||||
| 			return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot") | ||||
| 		} | ||||
| 		return client.SnapshotService(c.Snapshotter).Remove(ctx, c.SnapshotKey) | ||||
| 		s, err := client.getSnapshotter(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := s.Remove(ctx, c.SnapshotKey); err != nil && !errdefs.IsNotFound(err) { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -153,13 +189,21 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta | ||||
| // root filesystem in read-only mode | ||||
| func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		setSnapshotterIfEmpty(ctx, client, c) | ||||
|  | ||||
| 		parent := identity.ChainID(diffIDs).String() | ||||
| 		if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent, opts...); err != nil { | ||||
| 		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		s, err := client.getSnapshotter(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := s.View(ctx, id, parent, opts...); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		c.SnapshotKey = id | ||||
| @@ -168,21 +212,6 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Container) { | ||||
| 	if c.Snapshotter == "" { | ||||
| 		defaultSnapshotter := DefaultSnapshotter | ||||
| 		namespaceService := client.NamespaceService() | ||||
| 		if ns, err := namespaces.NamespaceRequired(ctx); err == nil { | ||||
| 			if labels, err := namespaceService.Labels(ctx, ns); err == nil { | ||||
| 				if snapshotLabel, ok := labels[defaults.DefaultSnapshotterNSLabel]; ok { | ||||
| 					defaultSnapshotter = snapshotLabel | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		c.Snapshotter = defaultSnapshotter | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithContainerExtension appends extension data to the container object. | ||||
| // Use this to decorate the container object with additional data for the client | ||||
| // integration. | ||||
| @@ -235,3 +264,8 @@ func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts { | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithoutRefreshedMetadata will use the current metadata attached to the container object | ||||
| func WithoutRefreshedMetadata(i *InfoConfig) { | ||||
| 	i.Refresh = false | ||||
| } | ||||
|   | ||||
							
								
								
									
										18
									
								
								vendor/github.com/containerd/containerd/container_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/containerd/containerd/container_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -28,7 +28,6 @@ import ( | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/mount" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/opencontainers/image-spec/identity" | ||||
| ) | ||||
|  | ||||
| @@ -45,18 +44,23 @@ func WithRemappedSnapshotView(id string, i Image, uid, gid uint32) NewContainerO | ||||
|  | ||||
| func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool) NewContainerOpts { | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		setSnapshotterIfEmpty(ctx, client, c) | ||||
|  | ||||
| 		var ( | ||||
| 			snapshotter = client.SnapshotService(c.Snapshotter) | ||||
| 			parent      = identity.ChainID(diffIDs).String() | ||||
| 			usernsID    = fmt.Sprintf("%s-%d-%d", parent, uid, gid) | ||||
| 			parent   = identity.ChainID(diffIDs).String() | ||||
| 			usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) | ||||
| 		) | ||||
| 		c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if _, err := snapshotter.Stat(ctx, usernsID); err == nil { | ||||
| 			if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil { | ||||
| 				c.SnapshotKey = id | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/container_restore_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/container_restore_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,7 +22,6 @@ import ( | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/gogo/protobuf/proto" | ||||
| 	ptypes "github.com/gogo/protobuf/types" | ||||
| 	"github.com/opencontainers/image-spec/identity" | ||||
| @@ -58,7 +57,7 @@ func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) | ||||
| 		diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/containerd.service
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/containerd.service
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| [Unit] | ||||
| Description=containerd container runtime | ||||
| Documentation=https://containerd.io | ||||
| After=network.target | ||||
| After=network.target local-fs.target | ||||
|  | ||||
| [Service] | ||||
| ExecStartPre=-/sbin/modprobe overlay | ||||
| @@ -9,6 +9,7 @@ ExecStart=/usr/local/bin/containerd | ||||
|  | ||||
| Delegate=yes | ||||
| KillMode=process | ||||
| Restart=always | ||||
| # Having non-zero Limit*s causes performance problems due to accounting overhead | ||||
| # in the kernel. We recommend using cgroups to do container-local accounting. | ||||
| LimitNPROC=infinity | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/containers/containers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/containers/containers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -49,7 +49,7 @@ type Container struct { | ||||
| 	// This property is required and immutable. | ||||
| 	Runtime RuntimeInfo | ||||
|  | ||||
| 	// Spec should carry the the runtime specification used to implement the | ||||
| 	// Spec should carry the runtime specification used to implement the | ||||
| 	// container. | ||||
| 	// | ||||
| 	// This field is required but mutable. | ||||
|   | ||||
							
								
								
									
										31
									
								
								vendor/github.com/containerd/containerd/content/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/containerd/containerd/content/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -55,7 +55,14 @@ func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ( | ||||
|  | ||||
| 	p := make([]byte, ra.Size()) | ||||
|  | ||||
| 	_, err = ra.ReadAt(p, 0) | ||||
| 	n, err := ra.ReadAt(p, 0) | ||||
| 	if err == io.EOF { | ||||
| 		if int64(n) != ra.Size() { | ||||
| 			err = io.ErrUnexpectedEOF | ||||
| 		} else { | ||||
| 			err = nil | ||||
| 		} | ||||
| 	} | ||||
| 	return p, err | ||||
| } | ||||
|  | ||||
| @@ -162,6 +169,28 @@ func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // CopyReader copies to a writer from a given reader, returning | ||||
| // the number of bytes copied. | ||||
| // Note: if the writer has a non-zero offset, the total number | ||||
| // of bytes read may be greater than those copied if the reader | ||||
| // is not an io.Seeker. | ||||
| // This copy does not commit the writer. | ||||
| func CopyReader(cw Writer, r io.Reader) (int64, error) { | ||||
| 	ws, err := cw.Status() | ||||
| 	if err != nil { | ||||
| 		return 0, errors.Wrap(err, "failed to get status") | ||||
| 	} | ||||
|  | ||||
| 	if ws.Offset > 0 { | ||||
| 		r, err = seekReader(r, ws.Offset, 0) | ||||
| 		if err != nil { | ||||
| 			return 0, errors.Wrapf(err, "unable to resume write to %v", ws.Ref) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return copyWithBuffer(cw, r) | ||||
| } | ||||
|  | ||||
| // seekReader attempts to seek the reader to the given offset, either by | ||||
| // resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding | ||||
| // up to the given offset. | ||||
|   | ||||
							
								
								
									
										18
									
								
								vendor/github.com/containerd/containerd/content/local/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/containerd/containerd/content/local/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -35,7 +35,6 @@ import ( | ||||
| 	"github.com/containerd/containerd/log" | ||||
| 	"github.com/sirupsen/logrus" | ||||
|  | ||||
| 	"github.com/containerd/continuity" | ||||
| 	digest "github.com/opencontainers/go-digest" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -661,6 +660,19 @@ func writeTimestampFile(p string, t time.Time) error { | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return continuity.AtomicWriteFile(p, b, 0666) | ||||
| 	return atomicWrite(p, b, 0666) | ||||
| } | ||||
|  | ||||
| func atomicWrite(path string, data []byte, mode os.FileMode) error { | ||||
| 	tmp := fmt.Sprintf("%s.tmp", path) | ||||
| 	f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "create tmp file") | ||||
| 	} | ||||
| 	_, err = f.Write(data) | ||||
| 	f.Close() | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "write atomic data") | ||||
| 	} | ||||
| 	return os.Rename(tmp, path) | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/containerd/containerd/defaults/defaults.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containerd/containerd/defaults/defaults.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,10 +23,10 @@ const ( | ||||
| 	// DefaultMaxSendMsgSize defines the default maximum message size for | ||||
| 	// sending protobufs passed over the GRPC API. | ||||
| 	DefaultMaxSendMsgSize = 16 << 20 | ||||
| 	// DefaultRuntimeNSLabel defines the namespace label to check for | ||||
| 	// DefaultRuntimeNSLabel defines the namespace label to check for the | ||||
| 	// default runtime | ||||
| 	DefaultRuntimeNSLabel = "containerd.io/defaults/runtime" | ||||
| 	// DefaultSnapshotterNSLabel defines the namespances label to check for | ||||
| 	// DefaultSnapshotterNSLabel defines the namespace label to check for the | ||||
| 	// default snapshotter | ||||
| 	DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter" | ||||
| ) | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/defaults/defaults_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/defaults/defaults_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,4 +32,6 @@ const ( | ||||
| 	// DefaultFIFODir is the default location used by client-side cio library | ||||
| 	// to store FIFOs. | ||||
| 	DefaultFIFODir = "/run/containerd/fifo" | ||||
| 	// DefaultRuntime is the default linux runtime | ||||
| 	DefaultRuntime = "io.containerd.runc.v2" | ||||
| ) | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/defaults/defaults_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/defaults/defaults_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -40,4 +40,6 @@ const ( | ||||
| 	// DefaultFIFODir is the default location used by client-side cio library | ||||
| 	// to store FIFOs. Unused on Windows. | ||||
| 	DefaultFIFODir = "" | ||||
| 	// DefaultRuntime is the default windows runtime | ||||
| 	DefaultRuntime = "io.containerd.runhcs.v1" | ||||
| ) | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/containerd/containerd/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/containerd/containerd/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -45,10 +45,17 @@ type diffRemote struct { | ||||
| 	client diffapi.DiffClient | ||||
| } | ||||
|  | ||||
| func (r *diffRemote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts []mount.Mount) (ocispec.Descriptor, error) { | ||||
| func (r *diffRemote) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (ocispec.Descriptor, error) { | ||||
| 	var config diff.ApplyConfig | ||||
| 	for _, opt := range opts { | ||||
| 		if err := opt(ctx, desc, &config); err != nil { | ||||
| 			return ocispec.Descriptor{}, err | ||||
| 		} | ||||
| 	} | ||||
| 	req := &diffapi.ApplyRequest{ | ||||
| 		Diff:   fromDescriptor(diff), | ||||
| 		Mounts: fromMounts(mounts), | ||||
| 		Diff:     fromDescriptor(desc), | ||||
| 		Mounts:   fromMounts(mounts), | ||||
| 		Payloads: config.ProcessorPayloads, | ||||
| 	} | ||||
| 	resp, err := r.client.Apply(ctx, req) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										20
									
								
								vendor/github.com/containerd/containerd/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/containerd/containerd/diff/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,6 +20,7 @@ import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/containerd/containerd/mount" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| ) | ||||
|  | ||||
| @@ -51,6 +52,15 @@ type Comparer interface { | ||||
| 	Compare(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error) | ||||
| } | ||||
|  | ||||
| // ApplyConfig is used to hold parameters needed for a apply operation | ||||
| type ApplyConfig struct { | ||||
| 	// ProcessorPayloads specifies the payload sent to various processors | ||||
| 	ProcessorPayloads map[string]*types.Any | ||||
| } | ||||
|  | ||||
| // ApplyOpt is used to configure an Apply operation | ||||
| type ApplyOpt func(context.Context, ocispec.Descriptor, *ApplyConfig) error | ||||
|  | ||||
| // Applier allows applying diffs between mounts | ||||
| type Applier interface { | ||||
| 	// Apply applies the content referred to by the given descriptor to | ||||
| @@ -58,7 +68,7 @@ type Applier interface { | ||||
| 	// implementation and content descriptor. For example, in the common | ||||
| 	// case the descriptor is a file system difference in tar format, | ||||
| 	// that tar would be applied on top of the mounts. | ||||
| 	Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error) | ||||
| 	Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount, opts ...ApplyOpt) (ocispec.Descriptor, error) | ||||
| } | ||||
|  | ||||
| // WithMediaType sets the media type to use for creating the diff, without | ||||
| @@ -87,3 +97,11 @@ func WithLabels(labels map[string]string) Opt { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithPayloads sets the apply processor payloads to the config | ||||
| func WithPayloads(payloads map[string]*types.Any) ApplyOpt { | ||||
| 	return func(_ context.Context, _ ocispec.Descriptor, c *ApplyConfig) error { | ||||
| 		c.ProcessorPayloads = payloads | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										187
									
								
								vendor/github.com/containerd/containerd/diff/stream.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								vendor/github.com/containerd/containerd/diff/stream.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package diff | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/containerd/containerd/archive/compression" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	handlers []Handler | ||||
|  | ||||
| 	// ErrNoProcessor is returned when no stream processor is available for a media-type | ||||
| 	ErrNoProcessor = errors.New("no processor for media-type") | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	// register the default compression handler | ||||
| 	RegisterProcessor(compressedHandler) | ||||
| } | ||||
|  | ||||
| // RegisterProcessor registers a stream processor for media-types | ||||
| func RegisterProcessor(handler Handler) { | ||||
| 	handlers = append(handlers, handler) | ||||
| } | ||||
|  | ||||
| // GetProcessor returns the processor for a media-type | ||||
| func GetProcessor(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { | ||||
| 	// reverse this list so that user configured handlers come up first | ||||
| 	for i := len(handlers) - 1; i >= 0; i-- { | ||||
| 		processor, ok := handlers[i](ctx, stream.MediaType()) | ||||
| 		if ok { | ||||
| 			return processor(ctx, stream, payloads) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, ErrNoProcessor | ||||
| } | ||||
|  | ||||
| // Handler checks a media-type and initializes the processor | ||||
| type Handler func(ctx context.Context, mediaType string) (StreamProcessorInit, bool) | ||||
|  | ||||
| // StaticHandler returns the processor init func for a static media-type | ||||
| func StaticHandler(expectedMediaType string, fn StreamProcessorInit) Handler { | ||||
| 	return func(ctx context.Context, mediaType string) (StreamProcessorInit, bool) { | ||||
| 		if mediaType == expectedMediaType { | ||||
| 			return fn, true | ||||
| 		} | ||||
| 		return nil, false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // StreamProcessorInit returns the initialized stream processor | ||||
| type StreamProcessorInit func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) | ||||
|  | ||||
| // RawProcessor provides access to direct fd for processing | ||||
| type RawProcessor interface { | ||||
| 	// File returns the fd for the read stream of the underlying processor | ||||
| 	File() *os.File | ||||
| } | ||||
|  | ||||
| // StreamProcessor handles processing a content stream and transforming it into a different media-type | ||||
| type StreamProcessor interface { | ||||
| 	io.ReadCloser | ||||
|  | ||||
| 	// MediaType is the resulting media-type that the processor processes the stream into | ||||
| 	MediaType() string | ||||
| } | ||||
|  | ||||
| func compressedHandler(ctx context.Context, mediaType string) (StreamProcessorInit, bool) { | ||||
| 	compressed, err := images.DiffCompression(ctx, mediaType) | ||||
| 	if err != nil { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 	if compressed != "" { | ||||
| 		return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { | ||||
| 			ds, err := compression.DecompressStream(stream) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			return &compressedProcessor{ | ||||
| 				rc: ds, | ||||
| 			}, nil | ||||
| 		}, true | ||||
| 	} | ||||
| 	return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { | ||||
| 		return &stdProcessor{ | ||||
| 			rc: stream, | ||||
| 		}, nil | ||||
| 	}, true | ||||
| } | ||||
|  | ||||
| // NewProcessorChain initialized the root StreamProcessor | ||||
| func NewProcessorChain(mt string, r io.Reader) StreamProcessor { | ||||
| 	return &processorChain{ | ||||
| 		mt: mt, | ||||
| 		rc: r, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type processorChain struct { | ||||
| 	mt string | ||||
| 	rc io.Reader | ||||
| } | ||||
|  | ||||
| func (c *processorChain) MediaType() string { | ||||
| 	return c.mt | ||||
| } | ||||
|  | ||||
| func (c *processorChain) Read(p []byte) (int, error) { | ||||
| 	return c.rc.Read(p) | ||||
| } | ||||
|  | ||||
| func (c *processorChain) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type stdProcessor struct { | ||||
| 	rc StreamProcessor | ||||
| } | ||||
|  | ||||
| func (c *stdProcessor) MediaType() string { | ||||
| 	return ocispec.MediaTypeImageLayer | ||||
| } | ||||
|  | ||||
| func (c *stdProcessor) Read(p []byte) (int, error) { | ||||
| 	return c.rc.Read(p) | ||||
| } | ||||
|  | ||||
| func (c *stdProcessor) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type compressedProcessor struct { | ||||
| 	rc io.ReadCloser | ||||
| } | ||||
|  | ||||
| func (c *compressedProcessor) MediaType() string { | ||||
| 	return ocispec.MediaTypeImageLayer | ||||
| } | ||||
|  | ||||
| func (c *compressedProcessor) Read(p []byte) (int, error) { | ||||
| 	return c.rc.Read(p) | ||||
| } | ||||
|  | ||||
| func (c *compressedProcessor) Close() error { | ||||
| 	return c.rc.Close() | ||||
| } | ||||
|  | ||||
| func BinaryHandler(id, returnsMediaType string, mediaTypes []string, path string, args []string) Handler { | ||||
| 	set := make(map[string]struct{}, len(mediaTypes)) | ||||
| 	for _, m := range mediaTypes { | ||||
| 		set[m] = struct{}{} | ||||
| 	} | ||||
| 	return func(_ context.Context, mediaType string) (StreamProcessorInit, bool) { | ||||
| 		if _, ok := set[mediaType]; ok { | ||||
| 			return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { | ||||
| 				payload := payloads[id] | ||||
| 				return NewBinaryProcessor(ctx, mediaType, returnsMediaType, stream, path, args, payload) | ||||
| 			}, true | ||||
| 		} | ||||
| 		return nil, false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const mediaTypeEnvVar = "STREAM_PROCESSOR_MEDIATYPE" | ||||
							
								
								
									
										146
									
								
								vendor/github.com/containerd/containerd/diff/stream_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								vendor/github.com/containerd/containerd/diff/stream_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| // +build !windows | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package diff | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/gogo/protobuf/proto" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // NewBinaryProcessor returns a binary processor for use with processing content streams | ||||
| func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) { | ||||
| 	cmd := exec.CommandContext(ctx, name, args...) | ||||
| 	cmd.Env = os.Environ() | ||||
|  | ||||
| 	var payloadC io.Closer | ||||
| 	if payload != nil { | ||||
| 		data, err := proto.Marshal(payload) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		r, w, err := os.Pipe() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		go func() { | ||||
| 			io.Copy(w, bytes.NewReader(data)) | ||||
| 			w.Close() | ||||
| 		}() | ||||
|  | ||||
| 		cmd.ExtraFiles = append(cmd.ExtraFiles, r) | ||||
| 		payloadC = r | ||||
| 	} | ||||
| 	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt)) | ||||
| 	var ( | ||||
| 		stdin  io.Reader | ||||
| 		closer func() error | ||||
| 		err    error | ||||
| 	) | ||||
| 	if f, ok := stream.(RawProcessor); ok { | ||||
| 		stdin = f.File() | ||||
| 		closer = f.File().Close | ||||
| 	} else { | ||||
| 		stdin = stream | ||||
| 	} | ||||
| 	cmd.Stdin = stdin | ||||
| 	r, w, err := os.Pipe() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cmd.Stdout = w | ||||
|  | ||||
| 	stderr := bytes.NewBuffer(nil) | ||||
| 	cmd.Stderr = stderr | ||||
|  | ||||
| 	if err := cmd.Start(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	p := &binaryProcessor{ | ||||
| 		cmd:    cmd, | ||||
| 		r:      r, | ||||
| 		mt:     rmt, | ||||
| 		stderr: stderr, | ||||
| 	} | ||||
| 	go p.wait() | ||||
|  | ||||
| 	// close after start and dup | ||||
| 	w.Close() | ||||
| 	if closer != nil { | ||||
| 		closer() | ||||
| 	} | ||||
| 	if payloadC != nil { | ||||
| 		payloadC.Close() | ||||
| 	} | ||||
| 	return p, nil | ||||
| } | ||||
|  | ||||
| type binaryProcessor struct { | ||||
| 	cmd    *exec.Cmd | ||||
| 	r      *os.File | ||||
| 	mt     string | ||||
| 	stderr *bytes.Buffer | ||||
|  | ||||
| 	mu  sync.Mutex | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Err() error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	return c.err | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) wait() { | ||||
| 	if err := c.cmd.Wait(); err != nil { | ||||
| 		if _, ok := err.(*exec.ExitError); ok { | ||||
| 			c.mu.Lock() | ||||
| 			c.err = errors.New(c.stderr.String()) | ||||
| 			c.mu.Unlock() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) File() *os.File { | ||||
| 	return c.r | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) MediaType() string { | ||||
| 	return c.mt | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Read(p []byte) (int, error) { | ||||
| 	return c.r.Read(p) | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Close() error { | ||||
| 	err := c.r.Close() | ||||
| 	if kerr := c.cmd.Process.Kill(); err == nil { | ||||
| 		err = kerr | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										165
									
								
								vendor/github.com/containerd/containerd/diff/stream_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								vendor/github.com/containerd/containerd/diff/stream_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| // +build windows | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package diff | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"sync" | ||||
|  | ||||
| 	winio "github.com/Microsoft/go-winio" | ||||
| 	"github.com/gogo/protobuf/proto" | ||||
| 	"github.com/gogo/protobuf/types" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| const processorPipe = "STREAM_PROCESSOR_PIPE" | ||||
|  | ||||
| // NewBinaryProcessor returns a binary processor for use with processing content streams | ||||
| func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) { | ||||
| 	cmd := exec.CommandContext(ctx, name, args...) | ||||
| 	cmd.Env = os.Environ() | ||||
|  | ||||
| 	if payload != nil { | ||||
| 		data, err := proto.Marshal(payload) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		up, err := getUiqPath() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		path := fmt.Sprintf("\\\\.\\pipe\\containerd-processor-%s-pipe", up) | ||||
| 		l, err := winio.ListenPipe(path, nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		go func() { | ||||
| 			defer l.Close() | ||||
| 			conn, err := l.Accept() | ||||
| 			if err != nil { | ||||
| 				logrus.WithError(err).Error("accept npipe connection") | ||||
| 				return | ||||
| 			} | ||||
| 			io.Copy(conn, bytes.NewReader(data)) | ||||
| 			conn.Close() | ||||
| 		}() | ||||
| 		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", processorPipe, path)) | ||||
| 	} | ||||
| 	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt)) | ||||
| 	var ( | ||||
| 		stdin  io.Reader | ||||
| 		closer func() error | ||||
| 		err    error | ||||
| 	) | ||||
| 	if f, ok := stream.(RawProcessor); ok { | ||||
| 		stdin = f.File() | ||||
| 		closer = f.File().Close | ||||
| 	} else { | ||||
| 		stdin = stream | ||||
| 	} | ||||
| 	cmd.Stdin = stdin | ||||
| 	r, w, err := os.Pipe() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cmd.Stdout = w | ||||
| 	stderr := bytes.NewBuffer(nil) | ||||
| 	cmd.Stderr = stderr | ||||
|  | ||||
| 	if err := cmd.Start(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	p := &binaryProcessor{ | ||||
| 		cmd:    cmd, | ||||
| 		r:      r, | ||||
| 		mt:     rmt, | ||||
| 		stderr: stderr, | ||||
| 	} | ||||
| 	go p.wait() | ||||
|  | ||||
| 	// close after start and dup | ||||
| 	w.Close() | ||||
| 	if closer != nil { | ||||
| 		closer() | ||||
| 	} | ||||
| 	return p, nil | ||||
| } | ||||
|  | ||||
| type binaryProcessor struct { | ||||
| 	cmd    *exec.Cmd | ||||
| 	r      *os.File | ||||
| 	mt     string | ||||
| 	stderr *bytes.Buffer | ||||
|  | ||||
| 	mu  sync.Mutex | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Err() error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	return c.err | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) wait() { | ||||
| 	if err := c.cmd.Wait(); err != nil { | ||||
| 		if _, ok := err.(*exec.ExitError); ok { | ||||
| 			c.mu.Lock() | ||||
| 			c.err = errors.New(c.stderr.String()) | ||||
| 			c.mu.Unlock() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) File() *os.File { | ||||
| 	return c.r | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) MediaType() string { | ||||
| 	return c.mt | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Read(p []byte) (int, error) { | ||||
| 	return c.r.Read(p) | ||||
| } | ||||
|  | ||||
| func (c *binaryProcessor) Close() error { | ||||
| 	err := c.r.Close() | ||||
| 	if kerr := c.cmd.Process.Kill(); err == nil { | ||||
| 		err = kerr | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func getUiqPath() (string, error) { | ||||
| 	dir, err := ioutil.TempDir("", "") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	os.Remove(dir) | ||||
| 	return filepath.Base(dir), nil | ||||
| } | ||||
							
								
								
									
										17
									
								
								vendor/github.com/containerd/containerd/errdefs/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/containerd/containerd/errdefs/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -26,7 +26,11 @@ | ||||
| // client-side errors to the correct types. | ||||
| package errdefs | ||||
|  | ||||
| import "github.com/pkg/errors" | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // Definitions of common error types used throughout containerd. All containerd | ||||
| // errors returned by most packages will map into one of these errors classes. | ||||
| @@ -76,3 +80,14 @@ func IsUnavailable(err error) bool { | ||||
| func IsNotImplemented(err error) bool { | ||||
| 	return errors.Cause(err) == ErrNotImplemented | ||||
| } | ||||
|  | ||||
| // IsCanceled returns true if the error is due to `context.Canceled`. | ||||
| func IsCanceled(err error) bool { | ||||
| 	return errors.Cause(err) == context.Canceled | ||||
| } | ||||
|  | ||||
| // IsDeadlineExceeded returns true if the error is due to | ||||
| // `context.DeadlineExceeded`. | ||||
| func IsDeadlineExceeded(err error) bool { | ||||
| 	return errors.Cause(err) == context.DeadlineExceeded | ||||
| } | ||||
|   | ||||
							
								
								
									
										9
									
								
								vendor/github.com/containerd/containerd/errdefs/grpc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/containerd/containerd/errdefs/grpc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package errdefs | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -55,6 +56,10 @@ func ToGRPC(err error) error { | ||||
| 		return status.Errorf(codes.Unavailable, err.Error()) | ||||
| 	case IsNotImplemented(err): | ||||
| 		return status.Errorf(codes.Unimplemented, err.Error()) | ||||
| 	case IsCanceled(err): | ||||
| 		return status.Errorf(codes.Canceled, err.Error()) | ||||
| 	case IsDeadlineExceeded(err): | ||||
| 		return status.Errorf(codes.DeadlineExceeded, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| @@ -89,6 +94,10 @@ func FromGRPC(err error) error { | ||||
| 		cls = ErrFailedPrecondition | ||||
| 	case codes.Unimplemented: | ||||
| 		cls = ErrNotImplemented | ||||
| 	case codes.Canceled: | ||||
| 		cls = context.Canceled | ||||
| 	case codes.DeadlineExceeded: | ||||
| 		cls = context.DeadlineExceeded | ||||
| 	default: | ||||
| 		cls = ErrUnknown | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/events/exchange/exchange.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/events/exchange/exchange.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -50,7 +50,7 @@ var _ events.Publisher = &Exchange{} | ||||
| var _ events.Forwarder = &Exchange{} | ||||
| var _ events.Subscriber = &Exchange{} | ||||
|  | ||||
| // Forward accepts an envelope to be direcly distributed on the exchange. | ||||
| // Forward accepts an envelope to be directly distributed on the exchange. | ||||
| // | ||||
| // This is useful when an event is forwarded on behalf of another namespace or | ||||
| // when the event is propagated on behalf of another publisher. | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/containerd/export.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/containerd/export.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,26 +20,12 @@ import ( | ||||
| 	"context" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/containerd/containerd/images/oci" | ||||
|  | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/containerd/containerd/images/archive" | ||||
| ) | ||||
|  | ||||
| // Export exports an image to a Tar stream. | ||||
| // OCI format is used by default. | ||||
| // It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc. | ||||
| // TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream. | ||||
| func (c *Client) Export(ctx context.Context, desc ocispec.Descriptor, opts ...oci.V1ExporterOpt) (io.ReadCloser, error) { | ||||
|  | ||||
| 	exporter, err := oci.ResolveV1ExportOpt(opts...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	pr, pw := io.Pipe() | ||||
| 	go func() { | ||||
| 		pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed")) | ||||
| 	}() | ||||
| 	return pr, nil | ||||
| // Export exports images to a Tar stream. | ||||
| // The tar archive is in OCI format with a Docker compatible manifest | ||||
| // when a single target platform is given. | ||||
| func (c *Client) Export(ctx context.Context, w io.Writer, opts ...archive.ExportOpt) error { | ||||
| 	return archive.Export(ctx, c.ContentStore(), w, opts...) | ||||
| } | ||||
|   | ||||
							
								
								
									
										183
									
								
								vendor/github.com/containerd/containerd/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										183
									
								
								vendor/github.com/containerd/containerd/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -19,16 +19,21 @@ package containerd | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/diff" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/containerd/containerd/rootfs" | ||||
| 	digest "github.com/opencontainers/go-digest" | ||||
| 	"github.com/containerd/containerd/snapshots" | ||||
| 	"github.com/opencontainers/go-digest" | ||||
| 	"github.com/opencontainers/image-spec/identity" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"golang.org/x/sync/semaphore" | ||||
| ) | ||||
|  | ||||
| // Image describes an image used by containers | ||||
| @@ -40,11 +45,13 @@ type Image interface { | ||||
| 	// Labels of the image | ||||
| 	Labels() map[string]string | ||||
| 	// Unpack unpacks the image's content into a snapshot | ||||
| 	Unpack(context.Context, string) error | ||||
| 	Unpack(context.Context, string, ...UnpackOpt) error | ||||
| 	// RootFS returns the unpacked diffids that make up images rootfs. | ||||
| 	RootFS(ctx context.Context) ([]digest.Digest, error) | ||||
| 	// Size returns the total size of the image's packed resources. | ||||
| 	Size(ctx context.Context) (int64, error) | ||||
| 	// Usage returns a usage calculation for the image. | ||||
| 	Usage(context.Context, ...UsageOpt) (int64, error) | ||||
| 	// Config descriptor for the image. | ||||
| 	Config(ctx context.Context) (ocispec.Descriptor, error) | ||||
| 	// IsUnpacked returns whether or not an image is unpacked. | ||||
| @@ -53,6 +60,49 @@ type Image interface { | ||||
| 	ContentStore() content.Store | ||||
| } | ||||
|  | ||||
| type usageOptions struct { | ||||
| 	manifestLimit *int | ||||
| 	manifestOnly  bool | ||||
| 	snapshots     bool | ||||
| } | ||||
|  | ||||
| // UsageOpt is used to configure the usage calculation | ||||
| type UsageOpt func(*usageOptions) error | ||||
|  | ||||
| // WithUsageManifestLimit sets the limit to the number of manifests which will | ||||
| // be walked for usage. Setting this value to 0 will require all manifests to | ||||
| // be walked, returning ErrNotFound if manifests are missing. | ||||
| // NOTE: By default all manifests which exist will be walked | ||||
| // and any non-existent manifests and their subobjects will be ignored. | ||||
| func WithUsageManifestLimit(i int) UsageOpt { | ||||
| 	// If 0 then don't filter any manifests | ||||
| 	// By default limits to current platform | ||||
| 	return func(o *usageOptions) error { | ||||
| 		o.manifestLimit = &i | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithSnapshotUsage will check for referenced snapshots from the image objects | ||||
| // and include the snapshot size in the total usage. | ||||
| func WithSnapshotUsage() UsageOpt { | ||||
| 	return func(o *usageOptions) error { | ||||
| 		o.snapshots = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithManifestUsage is used to get the usage for an image based on what is | ||||
| // reported by the manifests rather than what exists in the content store. | ||||
| // NOTE: This function is best used with the manifest limit set to get a | ||||
| // consistent value, otherwise non-existent manifests will be excluded. | ||||
| func WithManifestUsage() UsageOpt { | ||||
| 	return func(o *usageOptions) error { | ||||
| 		o.manifestOnly = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var _ = (Image)(&image{}) | ||||
|  | ||||
| // NewImage returns a client image object from the metadata image | ||||
| @@ -60,7 +110,7 @@ func NewImage(client *Client, i images.Image) Image { | ||||
| 	return &image{ | ||||
| 		client:   client, | ||||
| 		i:        i, | ||||
| 		platform: platforms.Default(), | ||||
| 		platform: client.platform, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -98,8 +148,95 @@ func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) { | ||||
| } | ||||
|  | ||||
| func (i *image) Size(ctx context.Context) (int64, error) { | ||||
| 	provider := i.client.ContentStore() | ||||
| 	return i.i.Size(ctx, provider, i.platform) | ||||
| 	return i.Usage(ctx, WithUsageManifestLimit(1), WithManifestUsage()) | ||||
| } | ||||
|  | ||||
| func (i *image) Usage(ctx context.Context, opts ...UsageOpt) (int64, error) { | ||||
| 	var config usageOptions | ||||
| 	for _, opt := range opts { | ||||
| 		if err := opt(&config); err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		provider  = i.client.ContentStore() | ||||
| 		handler   = images.ChildrenHandler(provider) | ||||
| 		size      int64 | ||||
| 		mustExist bool | ||||
| 	) | ||||
|  | ||||
| 	if config.manifestLimit != nil { | ||||
| 		handler = images.LimitManifests(handler, i.platform, *config.manifestLimit) | ||||
| 		mustExist = true | ||||
| 	} | ||||
|  | ||||
| 	var wh images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { | ||||
| 		var usage int64 | ||||
| 		children, err := handler(ctx, desc) | ||||
| 		if err != nil { | ||||
| 			if !errdefs.IsNotFound(err) || mustExist { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if !config.manifestOnly { | ||||
| 				// Do not count size of non-existent objects | ||||
| 				desc.Size = 0 | ||||
| 			} | ||||
| 		} else if config.snapshots || !config.manifestOnly { | ||||
| 			info, err := provider.Info(ctx, desc.Digest) | ||||
| 			if err != nil { | ||||
| 				if !errdefs.IsNotFound(err) { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				if !config.manifestOnly { | ||||
| 					// Do not count size of non-existent objects | ||||
| 					desc.Size = 0 | ||||
| 				} | ||||
| 			} else if info.Size > desc.Size { | ||||
| 				// Count actual usage, Size may be unset or -1 | ||||
| 				desc.Size = info.Size | ||||
| 			} | ||||
|  | ||||
| 			for k, v := range info.Labels { | ||||
| 				const prefix = "containerd.io/gc.ref.snapshot." | ||||
| 				if !strings.HasPrefix(k, prefix) { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				sn := i.client.SnapshotService(k[len(prefix):]) | ||||
| 				if sn == nil { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				u, err := sn.Usage(ctx, v) | ||||
| 				if err != nil { | ||||
| 					if !errdefs.IsNotFound(err) && !errdefs.IsInvalidArgument(err) { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 				} else { | ||||
| 					usage += u.Size | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Ignore unknown sizes. Generally unknown sizes should | ||||
| 		// never be set in manifests, however, the usage | ||||
| 		// calculation does not need to enforce this. | ||||
| 		if desc.Size >= 0 { | ||||
| 			usage += desc.Size | ||||
| 		} | ||||
|  | ||||
| 		atomic.AddInt64(&size, usage) | ||||
|  | ||||
| 		return children, nil | ||||
| 	} | ||||
|  | ||||
| 	l := semaphore.NewWeighted(3) | ||||
| 	if err := images.Dispatch(ctx, wh, l, i.i.Target); err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return size, nil | ||||
| } | ||||
|  | ||||
| func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { | ||||
| @@ -108,7 +245,10 @@ func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { | ||||
| } | ||||
|  | ||||
| func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) { | ||||
| 	sn := i.client.SnapshotService(snapshotterName) | ||||
| 	sn, err := i.client.getSnapshotter(ctx, snapshotterName) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	cs := i.client.ContentStore() | ||||
|  | ||||
| 	diffs, err := i.i.RootFS(ctx, cs, i.platform) | ||||
| @@ -127,28 +267,53 @@ func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, e | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func (i *image) Unpack(ctx context.Context, snapshotterName string) error { | ||||
| // UnpackConfig provides configuration for the unpack of an image | ||||
| type UnpackConfig struct { | ||||
| 	// ApplyOpts for applying a diff to a snapshotter | ||||
| 	ApplyOpts []diff.ApplyOpt | ||||
| 	// SnapshotOpts for configuring a snapshotter | ||||
| 	SnapshotOpts []snapshots.Opt | ||||
| } | ||||
|  | ||||
| // UnpackOpt provides configuration for unpack | ||||
| type UnpackOpt func(context.Context, *UnpackConfig) error | ||||
|  | ||||
| func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...UnpackOpt) error { | ||||
| 	ctx, done, err := i.client.WithLease(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer done(ctx) | ||||
|  | ||||
| 	var config UnpackConfig | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(ctx, &config); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	layers, err := i.getLayers(ctx, i.platform) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		sn = i.client.SnapshotService(snapshotterName) | ||||
| 		a  = i.client.DiffService() | ||||
| 		cs = i.client.ContentStore() | ||||
|  | ||||
| 		chain    []digest.Digest | ||||
| 		unpacked bool | ||||
| 	) | ||||
| 	snapshotterName, err = i.client.resolveSnapshotterName(ctx, snapshotterName) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	sn, err := i.client.getSnapshotter(ctx, snapshotterName) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, layer := range layers { | ||||
| 		unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a) | ||||
| 		unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -14,14 +14,10 @@ | ||||
|    limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package devices | ||||
| package images | ||||
| 
 | ||||
| import ( | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/pkg/errors" | ||||
| const ( | ||||
| 	// AnnotationImageName is an annotation on a Descriptor in an index.json | ||||
| 	// containing the `Name` value as used by an `Image` struct | ||||
| 	AnnotationImageName = "io.containerd.image.name" | ||||
| ) | ||||
| 
 | ||||
| func DeviceInfo(fi os.FileInfo) (uint64, uint64, error) { | ||||
| 	return 0, 0, errors.Wrap(ErrNotSupported, "cannot get device info on windows") | ||||
| } | ||||
							
								
								
									
										468
									
								
								vendor/github.com/containerd/containerd/images/archive/exporter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										468
									
								
								vendor/github.com/containerd/containerd/images/archive/exporter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,468 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package archive | ||||
|  | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"path" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	digest "github.com/opencontainers/go-digest" | ||||
| 	ocispecs "github.com/opencontainers/image-spec/specs-go" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type exportOptions struct { | ||||
| 	manifests          []ocispec.Descriptor | ||||
| 	platform           platforms.MatchComparer | ||||
| 	allPlatforms       bool | ||||
| 	skipDockerManifest bool | ||||
| } | ||||
|  | ||||
| // ExportOpt defines options for configuring exported descriptors | ||||
| type ExportOpt func(context.Context, *exportOptions) error | ||||
|  | ||||
| // WithPlatform defines the platform to require manifest lists have | ||||
| // not exporting all platforms. | ||||
| // Additionally, platform is used to resolve image configs for | ||||
| // Docker v1.1, v1.2 format compatibility. | ||||
| func WithPlatform(p platforms.MatchComparer) ExportOpt { | ||||
| 	return func(ctx context.Context, o *exportOptions) error { | ||||
| 		o.platform = p | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithAllPlatforms exports all manifests from a manifest list. | ||||
| // Missing content will fail the export. | ||||
| func WithAllPlatforms() ExportOpt { | ||||
| 	return func(ctx context.Context, o *exportOptions) error { | ||||
| 		o.allPlatforms = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithSkipDockerManifest skips creation of the Docker compatible | ||||
| // manifest.json file. | ||||
| func WithSkipDockerManifest() ExportOpt { | ||||
| 	return func(ctx context.Context, o *exportOptions) error { | ||||
| 		o.skipDockerManifest = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithImage adds the provided images to the exported archive. | ||||
| func WithImage(is images.Store, name string) ExportOpt { | ||||
| 	return func(ctx context.Context, o *exportOptions) error { | ||||
| 		img, err := is.Get(ctx, name) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		img.Target.Annotations = addNameAnnotation(name, img.Target.Annotations) | ||||
| 		o.manifests = append(o.manifests, img.Target) | ||||
|  | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithManifest adds a manifest to the exported archive. | ||||
| // When names are given they will be set on the manifest in the | ||||
| // exported archive, creating an index record for each name. | ||||
| // When no names are provided, it is up to caller to put name annotation to | ||||
| // on the manifest descriptor if needed. | ||||
| func WithManifest(manifest ocispec.Descriptor, names ...string) ExportOpt { | ||||
| 	return func(ctx context.Context, o *exportOptions) error { | ||||
| 		if len(names) == 0 { | ||||
| 			o.manifests = append(o.manifests, manifest) | ||||
| 		} | ||||
| 		for _, name := range names { | ||||
| 			mc := manifest | ||||
| 			mc.Annotations = addNameAnnotation(name, manifest.Annotations) | ||||
| 			o.manifests = append(o.manifests, mc) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func addNameAnnotation(name string, base map[string]string) map[string]string { | ||||
| 	annotations := map[string]string{} | ||||
| 	for k, v := range base { | ||||
| 		annotations[k] = v | ||||
| 	} | ||||
|  | ||||
| 	annotations[images.AnnotationImageName] = name | ||||
| 	annotations[ocispec.AnnotationRefName] = ociReferenceName(name) | ||||
|  | ||||
| 	return annotations | ||||
| } | ||||
|  | ||||
| // Export implements Exporter. | ||||
| func Export(ctx context.Context, store content.Provider, writer io.Writer, opts ...ExportOpt) error { | ||||
| 	var eo exportOptions | ||||
| 	for _, opt := range opts { | ||||
| 		if err := opt(ctx, &eo); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	records := []tarRecord{ | ||||
| 		ociLayoutFile(""), | ||||
| 		ociIndexRecord(eo.manifests), | ||||
| 	} | ||||
|  | ||||
| 	algorithms := map[string]struct{}{} | ||||
| 	dManifests := map[digest.Digest]*exportManifest{} | ||||
| 	resolvedIndex := map[digest.Digest]digest.Digest{} | ||||
| 	for _, desc := range eo.manifests { | ||||
| 		switch desc.MediaType { | ||||
| 		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: | ||||
| 			mt, ok := dManifests[desc.Digest] | ||||
| 			if !ok { | ||||
| 				// TODO(containerd): Skip if already added | ||||
| 				r, err := getRecords(ctx, store, desc, algorithms) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				records = append(records, r...) | ||||
|  | ||||
| 				mt = &exportManifest{ | ||||
| 					manifest: desc, | ||||
| 				} | ||||
| 				dManifests[desc.Digest] = mt | ||||
| 			} | ||||
|  | ||||
| 			name := desc.Annotations[images.AnnotationImageName] | ||||
| 			if name != "" && !eo.skipDockerManifest { | ||||
| 				mt.names = append(mt.names, name) | ||||
| 			} | ||||
| 		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: | ||||
| 			d, ok := resolvedIndex[desc.Digest] | ||||
| 			if !ok { | ||||
| 				records = append(records, blobRecord(store, desc)) | ||||
|  | ||||
| 				p, err := content.ReadBlob(ctx, store, desc) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
|  | ||||
| 				var index ocispec.Index | ||||
| 				if err := json.Unmarshal(p, &index); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
|  | ||||
| 				var manifests []ocispec.Descriptor | ||||
| 				for _, m := range index.Manifests { | ||||
| 					if eo.platform != nil { | ||||
| 						if m.Platform == nil || eo.platform.Match(*m.Platform) { | ||||
| 							manifests = append(manifests, m) | ||||
| 						} else if !eo.allPlatforms { | ||||
| 							continue | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					r, err := getRecords(ctx, store, m, algorithms) | ||||
| 					if err != nil { | ||||
| 						return err | ||||
| 					} | ||||
|  | ||||
| 					records = append(records, r...) | ||||
| 				} | ||||
|  | ||||
| 				if !eo.skipDockerManifest { | ||||
| 					if len(manifests) >= 1 { | ||||
| 						if len(manifests) > 1 { | ||||
| 							sort.SliceStable(manifests, func(i, j int) bool { | ||||
| 								if manifests[i].Platform == nil { | ||||
| 									return false | ||||
| 								} | ||||
| 								if manifests[j].Platform == nil { | ||||
| 									return true | ||||
| 								} | ||||
| 								return eo.platform.Less(*manifests[i].Platform, *manifests[j].Platform) | ||||
| 							}) | ||||
| 						} | ||||
| 						d = manifests[0].Digest | ||||
| 						dManifests[d] = &exportManifest{ | ||||
| 							manifest: manifests[0], | ||||
| 						} | ||||
| 					} else if eo.platform != nil { | ||||
| 						return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform") | ||||
| 					} | ||||
| 				} | ||||
| 				resolvedIndex[desc.Digest] = d | ||||
| 			} | ||||
| 			if d != "" { | ||||
| 				if name := desc.Annotations[images.AnnotationImageName]; name != "" { | ||||
| 					mt := dManifests[d] | ||||
| 					mt.names = append(mt.names, name) | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 		default: | ||||
| 			return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(dManifests) > 0 { | ||||
| 		tr, err := manifestsRecord(ctx, store, dManifests) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "unable to create manifests file") | ||||
| 		} | ||||
|  | ||||
| 		records = append(records, tr) | ||||
| 	} | ||||
|  | ||||
| 	if len(algorithms) > 0 { | ||||
| 		records = append(records, directoryRecord("blobs/", 0755)) | ||||
| 		for alg := range algorithms { | ||||
| 			records = append(records, directoryRecord("blobs/"+alg+"/", 0755)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tw := tar.NewWriter(writer) | ||||
| 	defer tw.Close() | ||||
| 	return writeTar(ctx, tw, records) | ||||
| } | ||||
|  | ||||
| func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descriptor, algorithms map[string]struct{}) ([]tarRecord, error) { | ||||
| 	var records []tarRecord | ||||
| 	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { | ||||
| 		records = append(records, blobRecord(store, desc)) | ||||
| 		algorithms[desc.Digest.Algorithm().String()] = struct{}{} | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	childrenHandler := images.ChildrenHandler(store) | ||||
|  | ||||
| 	handlers := images.Handlers( | ||||
| 		childrenHandler, | ||||
| 		images.HandlerFunc(exportHandler), | ||||
| 	) | ||||
|  | ||||
| 	// Walk sequentially since the number of fetches is likely one and doing in | ||||
| 	// parallel requires locking the export handler | ||||
| 	if err := images.Walk(ctx, handlers, desc); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return records, nil | ||||
| } | ||||
|  | ||||
| type tarRecord struct { | ||||
| 	Header *tar.Header | ||||
| 	CopyTo func(context.Context, io.Writer) (int64, error) | ||||
| } | ||||
|  | ||||
| func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord { | ||||
| 	path := path.Join("blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     path, | ||||
| 			Mode:     0444, | ||||
| 			Size:     desc.Size, | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			r, err := cs.ReaderAt(ctx, desc) | ||||
| 			if err != nil { | ||||
| 				return 0, errors.Wrap(err, "failed to get reader") | ||||
| 			} | ||||
| 			defer r.Close() | ||||
|  | ||||
| 			// Verify digest | ||||
| 			dgstr := desc.Digest.Algorithm().Digester() | ||||
|  | ||||
| 			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r)) | ||||
| 			if err != nil { | ||||
| 				return 0, errors.Wrap(err, "failed to copy to tar") | ||||
| 			} | ||||
| 			if dgstr.Digest() != desc.Digest { | ||||
| 				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest()) | ||||
| 			} | ||||
| 			return n, nil | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func directoryRecord(name string, mode int64) tarRecord { | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     name, | ||||
| 			Mode:     mode, | ||||
| 			Typeflag: tar.TypeDir, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ociLayoutFile(version string) tarRecord { | ||||
| 	if version == "" { | ||||
| 		version = ocispec.ImageLayoutVersion | ||||
| 	} | ||||
| 	layout := ocispec.ImageLayout{ | ||||
| 		Version: version, | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(layout) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     ocispec.ImageLayoutFile, | ||||
| 			Mode:     0444, | ||||
| 			Size:     int64(len(b)), | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			n, err := w.Write(b) | ||||
| 			return int64(n), err | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func ociIndexRecord(manifests []ocispec.Descriptor) tarRecord { | ||||
| 	index := ocispec.Index{ | ||||
| 		Versioned: ocispecs.Versioned{ | ||||
| 			SchemaVersion: 2, | ||||
| 		}, | ||||
| 		Manifests: manifests, | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(index) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     "index.json", | ||||
| 			Mode:     0644, | ||||
| 			Size:     int64(len(b)), | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			n, err := w.Write(b) | ||||
| 			return int64(n), err | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type exportManifest struct { | ||||
| 	manifest ocispec.Descriptor | ||||
| 	names    []string | ||||
| } | ||||
|  | ||||
| func manifestsRecord(ctx context.Context, store content.Provider, manifests map[digest.Digest]*exportManifest) (tarRecord, error) { | ||||
| 	mfsts := make([]struct { | ||||
| 		Config   string | ||||
| 		RepoTags []string | ||||
| 		Layers   []string | ||||
| 	}, len(manifests)) | ||||
|  | ||||
| 	var i int | ||||
| 	for _, m := range manifests { | ||||
| 		p, err := content.ReadBlob(ctx, store, m.manifest) | ||||
| 		if err != nil { | ||||
| 			return tarRecord{}, err | ||||
| 		} | ||||
|  | ||||
| 		var manifest ocispec.Manifest | ||||
| 		if err := json.Unmarshal(p, &manifest); err != nil { | ||||
| 			return tarRecord{}, err | ||||
| 		} | ||||
| 		if err := manifest.Config.Digest.Validate(); err != nil { | ||||
| 			return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest) | ||||
| 		} | ||||
|  | ||||
| 		dgst := manifest.Config.Digest | ||||
| 		mfsts[i].Config = path.Join("blobs", dgst.Algorithm().String(), dgst.Encoded()) | ||||
| 		for _, l := range manifest.Layers { | ||||
| 			path := path.Join("blobs", l.Digest.Algorithm().String(), l.Digest.Encoded()) | ||||
| 			mfsts[i].Layers = append(mfsts[i].Layers, path) | ||||
| 		} | ||||
|  | ||||
| 		for _, name := range m.names { | ||||
| 			nname, err := familiarizeReference(name) | ||||
| 			if err != nil { | ||||
| 				return tarRecord{}, err | ||||
| 			} | ||||
|  | ||||
| 			mfsts[i].RepoTags = append(mfsts[i].RepoTags, nname) | ||||
| 		} | ||||
|  | ||||
| 		i++ | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(mfsts) | ||||
| 	if err != nil { | ||||
| 		return tarRecord{}, err | ||||
| 	} | ||||
|  | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     "manifest.json", | ||||
| 			Mode:     0644, | ||||
| 			Size:     int64(len(b)), | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			n, err := w.Write(b) | ||||
| 			return int64(n), err | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error { | ||||
| 	sort.Slice(records, func(i, j int) bool { | ||||
| 		return records[i].Header.Name < records[j].Header.Name | ||||
| 	}) | ||||
|  | ||||
| 	var last string | ||||
| 	for _, record := range records { | ||||
| 		if record.Header.Name == last { | ||||
| 			continue | ||||
| 		} | ||||
| 		last = record.Header.Name | ||||
| 		if err := tw.WriteHeader(record.Header); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if record.CopyTo != nil { | ||||
| 			n, err := record.CopyTo(ctx, tw) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if n != record.Header.Size { | ||||
| 				return errors.Errorf("unexpected copy size for %s", record.Header.Name) | ||||
| 			} | ||||
| 		} else if record.Header.Size > 0 { | ||||
| 			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										154
									
								
								vendor/github.com/containerd/containerd/images/archive/importer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										154
									
								
								vendor/github.com/containerd/containerd/images/archive/importer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,12 +22,14 @@ import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"path" | ||||
|  | ||||
| 	"github.com/containerd/containerd/archive/compression" | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/log" | ||||
| 	digest "github.com/opencontainers/go-digest" | ||||
| @@ -36,6 +38,22 @@ import ( | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type importOpts struct { | ||||
| 	compress bool | ||||
| } | ||||
|  | ||||
| // ImportOpt is an option for importing an OCI index | ||||
| type ImportOpt func(*importOpts) error | ||||
|  | ||||
| // WithImportCompression compresses uncompressed layers on import. | ||||
| // This is used for import formats which do not include the manifest. | ||||
| func WithImportCompression() ImportOpt { | ||||
| 	return func(io *importOpts) error { | ||||
| 		io.compress = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ImportIndex imports an index from a tar archive image bundle | ||||
| // - implements Docker v1.1, v1.2 and OCI v1. | ||||
| // - prefers OCI v1 when provided | ||||
| @@ -43,8 +61,7 @@ import ( | ||||
| // - normalizes Docker references and adds as OCI ref name | ||||
| //      e.g. alpine:latest -> docker.io/library/alpine:latest | ||||
| // - existing OCI reference names are untouched | ||||
| // - TODO: support option to compress layers on ingest | ||||
| func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error) { | ||||
| func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opts ...ImportOpt) (ocispec.Descriptor, error) { | ||||
| 	var ( | ||||
| 		tr = tar.NewReader(reader) | ||||
|  | ||||
| @@ -56,7 +73,15 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc | ||||
| 		} | ||||
| 		symlinks = make(map[string]string) | ||||
| 		blobs    = make(map[string]ocispec.Descriptor) | ||||
| 		iopts    importOpts | ||||
| 	) | ||||
|  | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(&iopts); err != nil { | ||||
| 			return ocispec.Descriptor{}, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		hdr, err := tr.Next() | ||||
| 		if err == io.EOF { | ||||
| @@ -99,7 +124,7 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc | ||||
| 	} | ||||
|  | ||||
| 	// If OCI layout was given, interpret the tar as an OCI layout. | ||||
| 	// When not provided, the layout of the tar will be interpretted | ||||
| 	// When not provided, the layout of the tar will be interpreted | ||||
| 	// as Docker v1.1 or v1.2. | ||||
| 	if ociLayout.Version != "" { | ||||
| 		if ociLayout.Version != ocispec.ImageLayoutVersion { | ||||
| @@ -137,19 +162,23 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc | ||||
| 		if !ok { | ||||
| 			return ocispec.Descriptor{}, errors.Errorf("image config %q not found", mfst.Config) | ||||
| 		} | ||||
| 		config.MediaType = ocispec.MediaTypeImageConfig | ||||
| 		config.MediaType = images.MediaTypeDockerSchema2Config | ||||
|  | ||||
| 		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs) | ||||
| 		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress) | ||||
| 		if err != nil { | ||||
| 			return ocispec.Descriptor{}, errors.Wrap(err, "failed to resolve layers") | ||||
| 		} | ||||
|  | ||||
| 		manifest := ocispec.Manifest{ | ||||
| 			Versioned: specs.Versioned{ | ||||
| 				SchemaVersion: 2, | ||||
| 			}, | ||||
| 			Config: config, | ||||
| 			Layers: layers, | ||||
| 		manifest := struct { | ||||
| 			SchemaVersion int                  `json:"schemaVersion"` | ||||
| 			MediaType     string               `json:"mediaType"` | ||||
| 			Config        ocispec.Descriptor   `json:"config"` | ||||
| 			Layers        []ocispec.Descriptor `json:"layers"` | ||||
| 		}{ | ||||
| 			SchemaVersion: 2, | ||||
| 			MediaType:     images.MediaTypeDockerSchema2Manifest, | ||||
| 			Config:        config, | ||||
| 			Layers:        layers, | ||||
| 		} | ||||
|  | ||||
| 		desc, err := writeManifest(ctx, store, manifest, ocispec.MediaTypeImageManifest) | ||||
| @@ -181,7 +210,8 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (oc | ||||
| 				} | ||||
|  | ||||
| 				mfstdesc.Annotations = map[string]string{ | ||||
| 					ocispec.AnnotationRefName: normalized, | ||||
| 					images.AnnotationImageName: normalized, | ||||
| 					ocispec.AnnotationRefName:  ociReferenceName(normalized), | ||||
| 				} | ||||
|  | ||||
| 				idx.Manifests = append(idx.Manifests, mfstdesc) | ||||
| @@ -210,36 +240,118 @@ func onUntarBlob(ctx context.Context, r io.Reader, store content.Ingester, size | ||||
| 	return dgstr.Digest(), nil | ||||
| } | ||||
|  | ||||
| func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor) ([]ocispec.Descriptor, error) { | ||||
| 	var layers []ocispec.Descriptor | ||||
| 	for _, f := range layerFiles { | ||||
| func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor, compress bool) ([]ocispec.Descriptor, error) { | ||||
| 	layers := make([]ocispec.Descriptor, len(layerFiles)) | ||||
| 	descs := map[digest.Digest]*ocispec.Descriptor{} | ||||
| 	filters := []string{} | ||||
| 	for i, f := range layerFiles { | ||||
| 		desc, ok := blobs[f] | ||||
| 		if !ok { | ||||
| 			return nil, errors.Errorf("layer %q not found", f) | ||||
| 		} | ||||
| 		layers[i] = desc | ||||
| 		descs[desc.Digest] = &layers[i] | ||||
| 		filters = append(filters, "labels.\"containerd.io/uncompressed\"=="+desc.Digest.String()) | ||||
| 	} | ||||
|  | ||||
| 	err := store.Walk(ctx, func(info content.Info) error { | ||||
| 		dgst, ok := info.Labels["containerd.io/uncompressed"] | ||||
| 		if ok { | ||||
| 			desc := descs[digest.Digest(dgst)] | ||||
| 			if desc != nil { | ||||
| 				desc.MediaType = images.MediaTypeDockerSchema2LayerGzip | ||||
| 				desc.Digest = info.Digest | ||||
| 				desc.Size = info.Size | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	}, filters...) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failure checking for compressed blobs") | ||||
| 	} | ||||
|  | ||||
| 	for i, desc := range layers { | ||||
| 		if desc.MediaType != "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Open blob, resolve media type | ||||
| 		ra, err := store.ReaderAt(ctx, desc) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "failed to open %q (%s)", f, desc.Digest) | ||||
| 			return nil, errors.Wrapf(err, "failed to open %q (%s)", layerFiles[i], desc.Digest) | ||||
| 		} | ||||
| 		s, err := compression.DecompressStream(content.NewReader(ra)) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "failed to detect compression for %q", f) | ||||
| 			return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i]) | ||||
| 		} | ||||
| 		if s.GetCompression() == compression.Uncompressed { | ||||
| 			// TODO: Support compressing and writing back to content store | ||||
| 			desc.MediaType = ocispec.MediaTypeImageLayer | ||||
| 			if compress { | ||||
| 				ref := fmt.Sprintf("compress-blob-%s-%s", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) | ||||
| 				labels := map[string]string{ | ||||
| 					"containerd.io/uncompressed": desc.Digest.String(), | ||||
| 				} | ||||
| 				layers[i], err = compressBlob(ctx, store, s, ref, content.WithLabels(labels)) | ||||
| 				if err != nil { | ||||
| 					s.Close() | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip | ||||
| 			} else { | ||||
| 				layers[i].MediaType = images.MediaTypeDockerSchema2Layer | ||||
| 			} | ||||
| 		} else { | ||||
| 			desc.MediaType = ocispec.MediaTypeImageLayerGzip | ||||
| 			layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip | ||||
| 		} | ||||
| 		s.Close() | ||||
|  | ||||
| 		layers = append(layers, desc) | ||||
| 	} | ||||
| 	return layers, nil | ||||
| } | ||||
|  | ||||
| func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string, opts ...content.Opt) (desc ocispec.Descriptor, err error) { | ||||
| 	w, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) | ||||
| 	if err != nil { | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to open writer") | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		w.Close() | ||||
| 		if err != nil { | ||||
| 			cs.Abort(ctx, ref) | ||||
| 		} | ||||
| 	}() | ||||
| 	if err := w.Truncate(0); err != nil { | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to truncate writer") | ||||
| 	} | ||||
|  | ||||
| 	cw, err := compression.CompressStream(w, compression.Gzip) | ||||
| 	if err != nil { | ||||
| 		return ocispec.Descriptor{}, err | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.Copy(cw, r); err != nil { | ||||
| 		return ocispec.Descriptor{}, err | ||||
| 	} | ||||
| 	if err := cw.Close(); err != nil { | ||||
| 		return ocispec.Descriptor{}, err | ||||
| 	} | ||||
|  | ||||
| 	cst, err := w.Status() | ||||
| 	if err != nil { | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to get writer status") | ||||
| 	} | ||||
|  | ||||
| 	desc.Digest = w.Digest() | ||||
| 	desc.Size = cst.Offset | ||||
|  | ||||
| 	if err := w.Commit(ctx, desc.Size, desc.Digest, opts...); err != nil { | ||||
| 		if !errdefs.IsAlreadyExists(err) { | ||||
| 			return ocispec.Descriptor{}, errors.Wrap(err, "failed to commit") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return desc, nil | ||||
| } | ||||
|  | ||||
| func writeManifest(ctx context.Context, cs content.Ingester, manifest interface{}, mediaType string) (ocispec.Descriptor, error) { | ||||
| 	manifestBytes, err := json.Marshal(manifest) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										30
									
								
								vendor/github.com/containerd/containerd/images/archive/reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/containerd/containerd/images/archive/reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -19,7 +19,8 @@ package archive | ||||
| import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/docker/distribution/reference" | ||||
| 	"github.com/containerd/containerd/reference" | ||||
| 	distref "github.com/containerd/containerd/reference/docker" | ||||
| 	"github.com/opencontainers/go-digest" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
| @@ -69,7 +70,7 @@ func isImagePrefix(s, prefix string) bool { | ||||
|  | ||||
| func normalizeReference(ref string) (string, error) { | ||||
| 	// TODO: Replace this function to not depend on reference package | ||||
| 	normalized, err := reference.ParseDockerRef(ref) | ||||
| 	normalized, err := distref.ParseDockerRef(ref) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "normalize image ref %q", ref) | ||||
| 	} | ||||
| @@ -77,6 +78,31 @@ func normalizeReference(ref string) (string, error) { | ||||
| 	return normalized.String(), nil | ||||
| } | ||||
|  | ||||
| func familiarizeReference(ref string) (string, error) { | ||||
| 	named, err := distref.ParseNormalizedNamed(ref) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to parse %q", ref) | ||||
| 	} | ||||
| 	named = distref.TagNameOnly(named) | ||||
|  | ||||
| 	return distref.FamiliarString(named), nil | ||||
| } | ||||
|  | ||||
| func ociReferenceName(name string) string { | ||||
| 	// OCI defines the reference name as only a tag excluding the | ||||
| 	// repository. The containerd annotation contains the full image name | ||||
| 	// since the tag is insufficient for correctly naming and referring to an | ||||
| 	// image | ||||
| 	var ociRef string | ||||
| 	if spec, err := reference.Parse(name); err == nil { | ||||
| 		ociRef = spec.Object | ||||
| 	} else { | ||||
| 		ociRef = name | ||||
| 	} | ||||
|  | ||||
| 	return ociRef | ||||
| } | ||||
|  | ||||
| // DigestTranslator creates a digest reference by adding the | ||||
| // digest to an image name | ||||
| func DigestTranslator(prefix string) func(digest.Digest) string { | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/containerd/containerd/images/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/containerd/containerd/images/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -117,7 +117,7 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err | ||||
| // | ||||
| // If any handler returns an error, the dispatch session will be canceled. | ||||
| func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error { | ||||
| 	eg, ctx := errgroup.WithContext(ctx) | ||||
| 	eg, ctx2 := errgroup.WithContext(ctx) | ||||
| 	for _, desc := range descs { | ||||
| 		desc := desc | ||||
|  | ||||
| @@ -126,10 +126,11 @@ func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		eg.Go(func() error { | ||||
| 			desc := desc | ||||
|  | ||||
| 			children, err := handler.Handle(ctx, desc) | ||||
| 			children, err := handler.Handle(ctx2, desc) | ||||
| 			if limiter != nil { | ||||
| 				limiter.Release(1) | ||||
| 			} | ||||
| @@ -141,7 +142,7 @@ func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, | ||||
| 			} | ||||
|  | ||||
| 			if len(children) > 0 { | ||||
| 				return Dispatch(ctx, handler, limiter, children...) | ||||
| 				return Dispatch(ctx2, handler, limiter, children...) | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
|   | ||||
							
								
								
									
										60
									
								
								vendor/github.com/containerd/containerd/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/containerd/containerd/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,7 +20,6 @@ import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/containerd/containerd/content" | ||||
| @@ -119,7 +118,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor | ||||
| 		} | ||||
| 		size += desc.Size | ||||
| 		return nil, nil | ||||
| 	}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target) | ||||
| 	}), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target) | ||||
| } | ||||
|  | ||||
| type platformManifest struct { | ||||
| @@ -142,6 +141,7 @@ type platformManifest struct { | ||||
| // this direction because this abstraction is not needed.` | ||||
| func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) { | ||||
| 	var ( | ||||
| 		limit    = 1 | ||||
| 		m        []platformManifest | ||||
| 		wasIndex bool | ||||
| 	) | ||||
| @@ -210,10 +210,22 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			sort.SliceStable(descs, func(i, j int) bool { | ||||
| 				if descs[i].Platform == nil { | ||||
| 					return false | ||||
| 				} | ||||
| 				if descs[j].Platform == nil { | ||||
| 					return true | ||||
| 				} | ||||
| 				return platform.Less(*descs[i].Platform, *descs[j].Platform) | ||||
| 			}) | ||||
|  | ||||
| 			wasIndex = true | ||||
|  | ||||
| 			if len(descs) > limit { | ||||
| 				return descs[:limit], nil | ||||
| 			} | ||||
| 			return descs, nil | ||||
|  | ||||
| 		} | ||||
| 		return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest) | ||||
| 	}), image); err != nil { | ||||
| @@ -227,17 +239,6 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc | ||||
| 		} | ||||
| 		return ocispec.Manifest{}, err | ||||
| 	} | ||||
|  | ||||
| 	sort.SliceStable(m, func(i, j int) bool { | ||||
| 		if m[i].p == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		if m[j].p == nil { | ||||
| 			return true | ||||
| 		} | ||||
| 		return platform.Less(*m[i].p, *m[j].p) | ||||
| 	}) | ||||
|  | ||||
| 	return *m[0].m, nil | ||||
| } | ||||
|  | ||||
| @@ -356,15 +357,11 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr | ||||
| 		} | ||||
|  | ||||
| 		descs = append(descs, index.Manifests...) | ||||
| 	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, | ||||
| 		MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip, | ||||
| 		MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig, | ||||
| 		ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip, | ||||
| 		ocispec.MediaTypeImageLayerNonDistributable, ocispec.MediaTypeImageLayerNonDistributableGzip, | ||||
| 		MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig: | ||||
| 		// childless data types. | ||||
| 		return nil, nil | ||||
| 	default: | ||||
| 		if IsLayerType(desc.MediaType) || IsKnownConfig(desc.MediaType) { | ||||
| 			// childless data types. | ||||
| 			return nil, nil | ||||
| 		} | ||||
| 		log.G(ctx).Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType) | ||||
| 	} | ||||
|  | ||||
| @@ -387,22 +384,3 @@ func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.D | ||||
| 	} | ||||
| 	return config.RootFS.DiffIDs, nil | ||||
| } | ||||
|  | ||||
| // IsCompressedDiff returns true if mediaType is a known compressed diff media type. | ||||
| // It returns false if the media type is a diff, but not compressed. If the media type | ||||
| // is not a known diff type, it returns errdefs.ErrNotImplemented | ||||
| func IsCompressedDiff(ctx context.Context, mediaType string) (bool, error) { | ||||
| 	switch mediaType { | ||||
| 	case ocispec.MediaTypeImageLayer, MediaTypeDockerSchema2Layer: | ||||
| 	case ocispec.MediaTypeImageLayerGzip, MediaTypeDockerSchema2LayerGzip: | ||||
| 		return true, nil | ||||
| 	default: | ||||
| 		// Still apply all generic media types *.tar[.+]gzip and *.tar | ||||
| 		if strings.HasSuffix(mediaType, ".tar.gzip") || strings.HasSuffix(mediaType, ".tar+gzip") { | ||||
| 			return true, nil | ||||
| 		} else if !strings.HasSuffix(mediaType, ".tar") { | ||||
| 			return false, errdefs.ErrNotImplemented | ||||
| 		} | ||||
| 	} | ||||
| 	return false, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										84
									
								
								vendor/github.com/containerd/containerd/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										84
									
								
								vendor/github.com/containerd/containerd/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,6 +16,15 @@ | ||||
|  | ||||
| package images | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| ) | ||||
|  | ||||
| // mediatype definitions for image components handled in containerd. | ||||
| // | ||||
| // oci components are generally referenced directly, although we may centralize | ||||
| @@ -40,3 +49,78 @@ const ( | ||||
| 	// Legacy Docker schema1 manifest | ||||
| 	MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws" | ||||
| ) | ||||
|  | ||||
| // DiffCompression returns the compression as defined by the layer diff media | ||||
| // type. For Docker media types without compression, "unknown" is returned to | ||||
| // indicate that the media type may be compressed. If the media type is not | ||||
| // recognized as a layer diff, then it returns errdefs.ErrNotImplemented | ||||
| func DiffCompression(ctx context.Context, mediaType string) (string, error) { | ||||
| 	base, ext := parseMediaTypes(mediaType) | ||||
| 	switch base { | ||||
| 	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign: | ||||
| 		if len(ext) > 0 { | ||||
| 			// Type is wrapped | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		// These media types may have been compressed but failed to | ||||
| 		// use the correct media type. The decompression function | ||||
| 		// should detect and handle this case. | ||||
| 		return "unknown", nil | ||||
| 	case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip: | ||||
| 		if len(ext) > 0 { | ||||
| 			// Type is wrapped | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		return "gzip", nil | ||||
| 	case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable: | ||||
| 		if len(ext) > 0 { | ||||
| 			switch ext[len(ext)-1] { | ||||
| 			case "gzip": | ||||
| 				return "gzip", nil | ||||
| 			} | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	default: | ||||
| 		return "", errdefs.ErrNotImplemented | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // parseMediaTypes splits the media type into the base type and | ||||
| // an array of sorted extensions | ||||
| func parseMediaTypes(mt string) (string, []string) { | ||||
| 	if mt == "" { | ||||
| 		return "", []string{} | ||||
| 	} | ||||
|  | ||||
| 	s := strings.Split(mt, "+") | ||||
| 	ext := s[1:] | ||||
| 	sort.Strings(ext) | ||||
|  | ||||
| 	return s[0], ext | ||||
| } | ||||
|  | ||||
| // IsLayerTypes returns true if the media type is a layer | ||||
| func IsLayerType(mt string) bool { | ||||
| 	if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// Parse Docker media types, strip off any + suffixes first | ||||
| 	base, _ := parseMediaTypes(mt) | ||||
| 	switch base { | ||||
| 	case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, | ||||
| 		MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // IsKnownConfig returns true if the media type is a known config type | ||||
| func IsKnownConfig(mt string) bool { | ||||
| 	switch mt { | ||||
| 	case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig, | ||||
| 		MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig: | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
							
								
								
									
										241
									
								
								vendor/github.com/containerd/containerd/images/oci/exporter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										241
									
								
								vendor/github.com/containerd/containerd/images/oci/exporter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,241 +0,0 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package oci | ||||
|  | ||||
| import ( | ||||
| 	"archive/tar" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	ocispecs "github.com/opencontainers/image-spec/specs-go" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // V1Exporter implements OCI Image Spec v1. | ||||
| // It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc. | ||||
| // | ||||
| // TODO(AkihiroSuda): add V1Exporter{TranslateMediaTypes: true} that transforms media types, | ||||
| //                    e.g. application/vnd.docker.image.rootfs.diff.tar.gzip | ||||
| //                         -> application/vnd.oci.image.layer.v1.tar+gzip | ||||
| type V1Exporter struct { | ||||
| 	AllPlatforms bool | ||||
| } | ||||
|  | ||||
| // V1ExporterOpt allows the caller to set additional options to a new V1Exporter | ||||
| type V1ExporterOpt func(c *V1Exporter) error | ||||
|  | ||||
| // DefaultV1Exporter return a default V1Exporter pointer | ||||
| func DefaultV1Exporter() *V1Exporter { | ||||
| 	return &V1Exporter{ | ||||
| 		AllPlatforms: false, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ResolveV1ExportOpt return a new V1Exporter with V1ExporterOpt | ||||
| func ResolveV1ExportOpt(opts ...V1ExporterOpt) (*V1Exporter, error) { | ||||
| 	exporter := DefaultV1Exporter() | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(exporter); err != nil { | ||||
| 			return exporter, err | ||||
| 		} | ||||
| 	} | ||||
| 	return exporter, nil | ||||
| } | ||||
|  | ||||
| // WithAllPlatforms set V1Exporter`s AllPlatforms option | ||||
| func WithAllPlatforms(allPlatforms bool) V1ExporterOpt { | ||||
| 	return func(c *V1Exporter) error { | ||||
| 		c.AllPlatforms = allPlatforms | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Export implements Exporter. | ||||
| func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error { | ||||
| 	tw := tar.NewWriter(writer) | ||||
| 	defer tw.Close() | ||||
|  | ||||
| 	records := []tarRecord{ | ||||
| 		ociLayoutFile(""), | ||||
| 		ociIndexRecord(desc), | ||||
| 	} | ||||
|  | ||||
| 	algorithms := map[string]struct{}{} | ||||
| 	exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { | ||||
| 		records = append(records, blobRecord(store, desc)) | ||||
| 		algorithms[desc.Digest.Algorithm().String()] = struct{}{} | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	childrenHandler := images.ChildrenHandler(store) | ||||
|  | ||||
| 	if !oe.AllPlatforms { | ||||
| 		// get local default platform to fetch image manifest | ||||
| 		childrenHandler = images.FilterPlatforms(childrenHandler, platforms.Any(platforms.DefaultSpec())) | ||||
| 	} | ||||
|  | ||||
| 	handlers := images.Handlers( | ||||
| 		childrenHandler, | ||||
| 		images.HandlerFunc(exportHandler), | ||||
| 	) | ||||
|  | ||||
| 	// Walk sequentially since the number of fetchs is likely one and doing in | ||||
| 	// parallel requires locking the export handler | ||||
| 	if err := images.Walk(ctx, handlers, desc); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if len(algorithms) > 0 { | ||||
| 		records = append(records, directoryRecord("blobs/", 0755)) | ||||
| 		for alg := range algorithms { | ||||
| 			records = append(records, directoryRecord("blobs/"+alg+"/", 0755)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return writeTar(ctx, tw, records) | ||||
| } | ||||
|  | ||||
| type tarRecord struct { | ||||
| 	Header *tar.Header | ||||
| 	CopyTo func(context.Context, io.Writer) (int64, error) | ||||
| } | ||||
|  | ||||
| func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord { | ||||
| 	path := "blobs/" + desc.Digest.Algorithm().String() + "/" + desc.Digest.Hex() | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     path, | ||||
| 			Mode:     0444, | ||||
| 			Size:     desc.Size, | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			r, err := cs.ReaderAt(ctx, desc) | ||||
| 			if err != nil { | ||||
| 				return 0, errors.Wrap(err, "failed to get reader") | ||||
| 			} | ||||
| 			defer r.Close() | ||||
|  | ||||
| 			// Verify digest | ||||
| 			dgstr := desc.Digest.Algorithm().Digester() | ||||
|  | ||||
| 			n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r)) | ||||
| 			if err != nil { | ||||
| 				return 0, errors.Wrap(err, "failed to copy to tar") | ||||
| 			} | ||||
| 			if dgstr.Digest() != desc.Digest { | ||||
| 				return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest()) | ||||
| 			} | ||||
| 			return n, nil | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func directoryRecord(name string, mode int64) tarRecord { | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     name, | ||||
| 			Mode:     mode, | ||||
| 			Typeflag: tar.TypeDir, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ociLayoutFile(version string) tarRecord { | ||||
| 	if version == "" { | ||||
| 		version = ocispec.ImageLayoutVersion | ||||
| 	} | ||||
| 	layout := ocispec.ImageLayout{ | ||||
| 		Version: version, | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(layout) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     ocispec.ImageLayoutFile, | ||||
| 			Mode:     0444, | ||||
| 			Size:     int64(len(b)), | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			n, err := w.Write(b) | ||||
| 			return int64(n), err | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func ociIndexRecord(manifests ...ocispec.Descriptor) tarRecord { | ||||
| 	index := ocispec.Index{ | ||||
| 		Versioned: ocispecs.Versioned{ | ||||
| 			SchemaVersion: 2, | ||||
| 		}, | ||||
| 		Manifests: manifests, | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(index) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	return tarRecord{ | ||||
| 		Header: &tar.Header{ | ||||
| 			Name:     "index.json", | ||||
| 			Mode:     0644, | ||||
| 			Size:     int64(len(b)), | ||||
| 			Typeflag: tar.TypeReg, | ||||
| 		}, | ||||
| 		CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { | ||||
| 			n, err := w.Write(b) | ||||
| 			return int64(n), err | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error { | ||||
| 	sort.Slice(records, func(i, j int) bool { | ||||
| 		return records[i].Header.Name < records[j].Header.Name | ||||
| 	}) | ||||
|  | ||||
| 	for _, record := range records { | ||||
| 		if err := tw.WriteHeader(record.Header); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if record.CopyTo != nil { | ||||
| 			n, err := record.CopyTo(ctx, tw) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if n != record.Header.Size { | ||||
| 				return errors.Errorf("unexpected copy size for %s", record.Header.Name) | ||||
| 			} | ||||
| 		} else if record.Header.Size > 0 { | ||||
| 			return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										51
									
								
								vendor/github.com/containerd/containerd/import.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/containerd/containerd/import.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -35,6 +35,7 @@ type importOpts struct { | ||||
| 	imageRefT    func(string) string | ||||
| 	dgstRefT     func(digest.Digest) string | ||||
| 	allPlatforms bool | ||||
| 	compress     bool | ||||
| } | ||||
|  | ||||
| // ImportOpt allows the caller to specify import specific options | ||||
| @@ -74,9 +75,18 @@ func WithAllPlatforms(allPlatforms bool) ImportOpt { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithImportCompression compresses uncompressed layers on import. | ||||
| // This is used for import formats which do not include the manifest. | ||||
| func WithImportCompression() ImportOpt { | ||||
| 	return func(c *importOpts) error { | ||||
| 		c.compress = true | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Import imports an image from a Tar stream using reader. | ||||
| // Caller needs to specify importer. Future version may use oci.v1 as the default. | ||||
| // Note that unreferrenced blobs may be imported to the content store as well. | ||||
| // Note that unreferenced blobs may be imported to the content store as well. | ||||
| func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt) ([]images.Image, error) { | ||||
| 	var iopts importOpts | ||||
| 	for _, o := range opts { | ||||
| @@ -91,7 +101,12 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt | ||||
| 	} | ||||
| 	defer done(ctx) | ||||
|  | ||||
| 	index, err := archive.ImportIndex(ctx, c.ContentStore(), reader) | ||||
| 	var aio []archive.ImportOpt | ||||
| 	if iopts.compress { | ||||
| 		aio = append(aio, archive.WithImportCompression()) | ||||
| 	} | ||||
|  | ||||
| 	index, err := archive.ImportIndex(ctx, c.ContentStore(), reader, aio...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -110,7 +125,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt | ||||
| 	} | ||||
| 	var platformMatcher = platforms.All | ||||
| 	if !iopts.allPlatforms { | ||||
| 		platformMatcher = platforms.Default() | ||||
| 		platformMatcher = c.platform | ||||
| 	} | ||||
|  | ||||
| 	var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { | ||||
| @@ -130,16 +145,12 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt | ||||
| 		} | ||||
|  | ||||
| 		for _, m := range idx.Manifests { | ||||
| 			if ref := m.Annotations[ocispec.AnnotationRefName]; ref != "" { | ||||
| 				if iopts.imageRefT != nil { | ||||
| 					ref = iopts.imageRefT(ref) | ||||
| 				} | ||||
| 				if ref != "" { | ||||
| 					imgs = append(imgs, images.Image{ | ||||
| 						Name:   ref, | ||||
| 						Target: m, | ||||
| 					}) | ||||
| 				} | ||||
| 			name := imageName(m.Annotations, iopts.imageRefT) | ||||
| 			if name != "" { | ||||
| 				imgs = append(imgs, images.Image{ | ||||
| 					Name:   name, | ||||
| 					Target: m, | ||||
| 				}) | ||||
| 			} | ||||
| 			if iopts.dgstRefT != nil { | ||||
| 				ref := iopts.dgstRefT(m.Digest) | ||||
| @@ -178,3 +189,17 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt | ||||
|  | ||||
| 	return imgs, nil | ||||
| } | ||||
|  | ||||
| func imageName(annotations map[string]string, ociCleanup func(string) string) string { | ||||
| 	name := annotations[images.AnnotationImageName] | ||||
| 	if name != "" { | ||||
| 		return name | ||||
| 	} | ||||
| 	name = annotations[ocispec.AnnotationRefName] | ||||
| 	if name != "" { | ||||
| 		if ociCleanup != nil { | ||||
| 			name = ociCleanup(name) | ||||
| 		} | ||||
| 	} | ||||
| 	return name | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/install.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/install.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -27,7 +27,6 @@ import ( | ||||
| 	"github.com/containerd/containerd/archive/compression" | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| @@ -43,7 +42,7 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts) | ||||
| 	} | ||||
| 	var ( | ||||
| 		cs       = image.ContentStore() | ||||
| 		platform = platforms.Default() | ||||
| 		platform = c.platform | ||||
| 	) | ||||
| 	manifest, err := images.Manifest(ctx, cs, image.Target(), platform) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										12
									
								
								vendor/github.com/containerd/containerd/lease.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/containerd/containerd/lease.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -24,7 +24,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| // WithLease attaches a lease on the context | ||||
| func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.Context) error, error) { | ||||
| func (c *Client) WithLease(ctx context.Context, opts ...leases.Opt) (context.Context, func(context.Context) error, error) { | ||||
| 	_, ok := leases.FromContext(ctx) | ||||
| 	if ok { | ||||
| 		return ctx, func(context.Context) error { | ||||
| @@ -34,7 +34,15 @@ func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.C | ||||
|  | ||||
| 	ls := c.LeasesService() | ||||
|  | ||||
| 	l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(24*time.Hour)) | ||||
| 	if len(opts) == 0 { | ||||
| 		// Use default lease configuration if no options provided | ||||
| 		opts = []leases.Opt{ | ||||
| 			leases.WithRandomID(), | ||||
| 			leases.WithExpiration(24 * time.Hour), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	l, err := ls.Create(ctx, opts...) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/containerd/containerd/leases/lease.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/containerd/containerd/leases/lease.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,6 +32,9 @@ type Manager interface { | ||||
| 	Create(context.Context, ...Opt) (Lease, error) | ||||
| 	Delete(context.Context, Lease, ...DeleteOpt) error | ||||
| 	List(context.Context, ...string) ([]Lease, error) | ||||
| 	AddResource(context.Context, Lease, Resource) error | ||||
| 	DeleteResource(context.Context, Lease, Resource) error | ||||
| 	ListResources(context.Context, Lease) ([]Resource, error) | ||||
| } | ||||
|  | ||||
| // Lease retains resources to prevent cleanup before | ||||
| @@ -42,6 +45,13 @@ type Lease struct { | ||||
| 	Labels    map[string]string | ||||
| } | ||||
|  | ||||
| // Resource represents low level resource of image, like content, ingest and | ||||
| // snapshotter. | ||||
| type Resource struct { | ||||
| 	ID   string | ||||
| 	Type string | ||||
| } | ||||
|  | ||||
| // DeleteOptions provide options on image delete | ||||
| type DeleteOptions struct { | ||||
| 	Synchronous bool | ||||
|   | ||||
							
								
								
									
										40
									
								
								vendor/github.com/containerd/containerd/leases/proxy/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/containerd/containerd/leases/proxy/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -91,3 +91,43 @@ func (pm *proxyManager) List(ctx context.Context, filters ...string) ([]leases.L | ||||
|  | ||||
| 	return l, nil | ||||
| } | ||||
|  | ||||
| func (pm *proxyManager) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { | ||||
| 	_, err := pm.client.AddResource(ctx, &leasesapi.AddResourceRequest{ | ||||
| 		ID: lease.ID, | ||||
| 		Resource: leasesapi.Resource{ | ||||
| 			ID:   r.ID, | ||||
| 			Type: r.Type, | ||||
| 		}, | ||||
| 	}) | ||||
| 	return errdefs.FromGRPC(err) | ||||
| } | ||||
|  | ||||
| func (pm *proxyManager) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { | ||||
| 	_, err := pm.client.DeleteResource(ctx, &leasesapi.DeleteResourceRequest{ | ||||
| 		ID: lease.ID, | ||||
| 		Resource: leasesapi.Resource{ | ||||
| 			ID:   r.ID, | ||||
| 			Type: r.Type, | ||||
| 		}, | ||||
| 	}) | ||||
| 	return errdefs.FromGRPC(err) | ||||
| } | ||||
|  | ||||
| func (pm *proxyManager) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) { | ||||
| 	resp, err := pm.client.ListResources(ctx, &leasesapi.ListResourcesRequest{ | ||||
| 		ID: lease.ID, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, errdefs.FromGRPC(err) | ||||
| 	} | ||||
|  | ||||
| 	rs := make([]leases.Resource, 0, len(resp.Resources)) | ||||
| 	for _, i := range resp.Resources { | ||||
| 		rs = append(rs, leases.Resource{ | ||||
| 			ID:   i.ID, | ||||
| 			Type: i.Type, | ||||
| 		}) | ||||
| 	} | ||||
| 	return rs, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/log/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/log/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -30,7 +30,7 @@ var ( | ||||
| 	// messages. | ||||
| 	G = GetLogger | ||||
|  | ||||
| 	// L is an alias for the the standard logger. | ||||
| 	// L is an alias for the standard logger. | ||||
| 	L = logrus.NewEntry(logrus.StandardLogger()) | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/containerd/containerd/namespaces.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/containerd/containerd/namespaces.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -100,10 +100,18 @@ func (r *remoteNamespaces) List(ctx context.Context) ([]string, error) { | ||||
| 	return namespaces, nil | ||||
| } | ||||
|  | ||||
| func (r *remoteNamespaces) Delete(ctx context.Context, namespace string) error { | ||||
| 	var req api.DeleteNamespaceRequest | ||||
|  | ||||
| 	req.Name = namespace | ||||
| func (r *remoteNamespaces) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { | ||||
| 	i := namespaces.DeleteInfo{ | ||||
| 		Name: namespace, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(ctx, &i); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	req := api.DeleteNamespaceRequest{ | ||||
| 		Name: namespace, | ||||
| 	} | ||||
| 	_, err := r.client.Delete(ctx, &req) | ||||
| 	if err != nil { | ||||
| 		return errdefs.FromGRPC(err) | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/containerd/containerd/namespaces/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/containerd/containerd/namespaces/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -36,10 +36,9 @@ type namespaceKey struct{} | ||||
| // WithNamespace sets a given namespace on the context | ||||
| func WithNamespace(ctx context.Context, namespace string) context.Context { | ||||
| 	ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace | ||||
|  | ||||
| 	// also store on the grpc headers so it gets picked up by any clients that | ||||
| 	// also store on the grpc and ttrpc headers so it gets picked up by any clients that | ||||
| 	// are using this. | ||||
| 	return withGRPCNamespaceHeader(ctx, namespace) | ||||
| 	return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace) | ||||
| } | ||||
|  | ||||
| // NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or | ||||
| @@ -58,22 +57,21 @@ func NamespaceFromEnv(ctx context.Context) context.Context { | ||||
| func Namespace(ctx context.Context) (string, bool) { | ||||
| 	namespace, ok := ctx.Value(namespaceKey{}).(string) | ||||
| 	if !ok { | ||||
| 		return fromGRPCHeader(ctx) | ||||
| 		if namespace, ok = fromGRPCHeader(ctx); !ok { | ||||
| 			return fromTTRPCHeader(ctx) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return namespace, ok | ||||
| } | ||||
|  | ||||
| // NamespaceRequired returns the valid namepace from the context or an error. | ||||
| // NamespaceRequired returns the valid namespace from the context or an error. | ||||
| func NamespaceRequired(ctx context.Context) (string, error) { | ||||
| 	namespace, ok := Namespace(ctx) | ||||
| 	if !ok || namespace == "" { | ||||
| 		return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required") | ||||
| 	} | ||||
|  | ||||
| 	if err := Validate(namespace); err != nil { | ||||
| 		return "", errors.Wrap(err, "namespace validation") | ||||
| 	} | ||||
|  | ||||
| 	return namespace, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								vendor/github.com/containerd/containerd/namespaces/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/containerd/containerd/namespaces/store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -33,5 +33,14 @@ type Store interface { | ||||
| 	List(ctx context.Context) ([]string, error) | ||||
|  | ||||
| 	// Delete removes the namespace. The namespace must be empty to be deleted. | ||||
| 	Delete(ctx context.Context, namespace string) error | ||||
| 	Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error | ||||
| } | ||||
|  | ||||
| // DeleteInfo specifies information for the deletion of a namespace | ||||
| type DeleteInfo struct { | ||||
| 	// Name of the namespace | ||||
| 	Name string | ||||
| } | ||||
|  | ||||
| // DeleteOpts allows the caller to set options for namespace deletion | ||||
| type DeleteOpts func(context.Context, *DeleteInfo) error | ||||
|   | ||||
							
								
								
									
										51
									
								
								vendor/github.com/containerd/containerd/namespaces/ttrpc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/containerd/containerd/namespaces/ttrpc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package namespaces | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"github.com/containerd/ttrpc" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// TTRPCHeader defines the header name for specifying a containerd namespace | ||||
| 	TTRPCHeader = "containerd-namespace-ttrpc" | ||||
| ) | ||||
|  | ||||
| func copyMetadata(src ttrpc.MD) ttrpc.MD { | ||||
| 	md := ttrpc.MD{} | ||||
| 	for k, v := range src { | ||||
| 		md[k] = append(md[k], v...) | ||||
| 	} | ||||
| 	return md | ||||
| } | ||||
|  | ||||
| func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context { | ||||
| 	md, ok := ttrpc.GetMetadata(ctx) | ||||
| 	if !ok { | ||||
| 		md = ttrpc.MD{} | ||||
| 	} else { | ||||
| 		md = copyMetadata(md) | ||||
| 	} | ||||
| 	md.Set(TTRPCHeader, namespace) | ||||
| 	return ttrpc.WithMetadata(ctx, md) | ||||
| } | ||||
|  | ||||
| func fromTTRPCHeader(ctx context.Context) (string, bool) { | ||||
| 	return ttrpc.GetMetadataValue(ctx, TTRPCHeader) | ||||
| } | ||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/oci/spec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/oci/spec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -78,7 +78,7 @@ func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // ApplyOpts applys the options to the given spec, injecting data from the | ||||
| // ApplyOpts applies the options to the given spec, injecting data from the | ||||
| // context, client and container instance. | ||||
| func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error { | ||||
| 	for _, o := range opts { | ||||
| @@ -141,7 +141,6 @@ func populateDefaultUnixSpec(ctx context.Context, s *Spec, id string) error { | ||||
| 			Path: defaultRootfsPath, | ||||
| 		}, | ||||
| 		Process: &specs.Process{ | ||||
| 			Env:             defaultUnixEnv, | ||||
| 			Cwd:             "/", | ||||
| 			NoNewPrivileges: true, | ||||
| 			User: specs.User{ | ||||
|   | ||||
							
								
								
									
										132
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package oci | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| @@ -76,6 +77,20 @@ func setLinux(s *Spec) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // nolint | ||||
| func setResources(s *Spec) { | ||||
| 	if s.Linux != nil { | ||||
| 		if s.Linux.Resources == nil { | ||||
| 			s.Linux.Resources = &specs.LinuxResources{} | ||||
| 		} | ||||
| 	} | ||||
| 	if s.Windows != nil { | ||||
| 		if s.Windows.Resources == nil { | ||||
| 			s.Windows.Resources = &specs.WindowsResources{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // setCapabilities sets Linux Capabilities to empty if unset | ||||
| func setCapabilities(s *Spec) { | ||||
| 	setProcess(s) | ||||
| @@ -104,7 +119,7 @@ func WithDefaultSpecForPlatform(platform string) SpecOpts { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithSpecFromBytes loads the the spec from the provided byte slice. | ||||
| // WithSpecFromBytes loads the spec from the provided byte slice. | ||||
| func WithSpecFromBytes(p []byte) SpecOpts { | ||||
| 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 		*s = Spec{} // make sure spec is cleared. | ||||
| @@ -137,6 +152,13 @@ func WithEnv(environmentVariables []string) SpecOpts { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDefaultPathEnv sets the $PATH environment variable to the | ||||
| // default PATH defined in this package. | ||||
| func WithDefaultPathEnv(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 	s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, defaultUnixEnv) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // replaceOrAppendEnvValues returns the defaults with the overrides either | ||||
| // replaced by env key or appended to the list | ||||
| func replaceOrAppendEnvValues(defaults, overrides []string) []string { | ||||
| @@ -312,7 +334,11 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts { | ||||
|  | ||||
| 		setProcess(s) | ||||
| 		if s.Linux != nil { | ||||
| 			s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env) | ||||
| 			defaults := config.Env | ||||
| 			if len(defaults) == 0 { | ||||
| 				defaults = defaultUnixEnv | ||||
| 			} | ||||
| 			s.Process.Env = replaceOrAppendEnvValues(defaults, s.Process.Env) | ||||
| 			cmd := config.Cmd | ||||
| 			if len(args) > 0 { | ||||
| 				cmd = args | ||||
| @@ -334,7 +360,7 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts { | ||||
| 			// even if there is no specified user in the image config | ||||
| 			return WithAdditionalGIDs("root")(ctx, client, c, s) | ||||
| 		} else if s.Windows != nil { | ||||
| 			s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env) | ||||
| 			s.Process.Env = replaceOrAppendEnvValues(config.Env, s.Process.Env) | ||||
| 			cmd := config.Cmd | ||||
| 			if len(args) > 0 { | ||||
| 				cmd = args | ||||
| @@ -607,7 +633,7 @@ func WithUserID(uid uint32) SpecOpts { | ||||
| } | ||||
|  | ||||
| // WithUsername sets the correct UID and GID for the container | ||||
| // based on the the image's /etc/passwd contents. If /etc/passwd | ||||
| // based on the image's /etc/passwd contents. If /etc/passwd | ||||
| // does not exist, or the username is not found in /etc/passwd, | ||||
| // it returns error. | ||||
| func WithUsername(username string) SpecOpts { | ||||
| @@ -980,6 +1006,21 @@ func WithParentCgroupDevices(_ context.Context, _ Client, _ *containers.Containe | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // WithAllDevicesAllowed permits READ WRITE MKNOD on all devices nodes for the container | ||||
| func WithAllDevicesAllowed(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 	setLinux(s) | ||||
| 	if s.Linux.Resources == nil { | ||||
| 		s.Linux.Resources = &specs.LinuxResources{} | ||||
| 	} | ||||
| 	s.Linux.Resources.Devices = []specs.LinuxDeviceCgroup{ | ||||
| 		{ | ||||
| 			Allow:  true, | ||||
| 			Access: rwm, | ||||
| 		}, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // WithDefaultUnixDevices adds the default devices for unix such as /dev/null, /dev/random to | ||||
| // the container's resource cgroup spec | ||||
| func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| @@ -1074,7 +1115,6 @@ func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container | ||||
| } | ||||
|  | ||||
| // WithPrivileged sets up options for a privileged container | ||||
| // TODO(justincormack) device handling | ||||
| var WithPrivileged = Compose( | ||||
| 	WithAllCapabilities, | ||||
| 	WithMaskedPaths(nil), | ||||
| @@ -1139,3 +1179,85 @@ func WithAnnotations(annotations map[string]string) SpecOpts { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithLinuxDevices adds the provided linux devices to the spec | ||||
| func WithLinuxDevices(devices []specs.LinuxDevice) SpecOpts { | ||||
| 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 		setLinux(s) | ||||
| 		s.Linux.Devices = append(s.Linux.Devices, devices...) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var ErrNotADevice = errors.New("not a device node") | ||||
|  | ||||
| // WithLinuxDevice adds the device specified by path to the spec | ||||
| func WithLinuxDevice(path, permissions string) SpecOpts { | ||||
| 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 		setLinux(s) | ||||
| 		setResources(s) | ||||
|  | ||||
| 		dev, err := deviceFromPath(path, permissions) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		s.Linux.Devices = append(s.Linux.Devices, *dev) | ||||
|  | ||||
| 		s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{ | ||||
| 			Type:   dev.Type, | ||||
| 			Allow:  true, | ||||
| 			Major:  &dev.Major, | ||||
| 			Minor:  &dev.Minor, | ||||
| 			Access: permissions, | ||||
| 		}) | ||||
|  | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithEnvFile adds environment variables from a file to the container's spec | ||||
| func WithEnvFile(path string) SpecOpts { | ||||
| 	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 		var vars []string | ||||
| 		f, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		defer f.Close() | ||||
|  | ||||
| 		sc := bufio.NewScanner(f) | ||||
| 		for sc.Scan() { | ||||
| 			if sc.Err() != nil { | ||||
| 				return sc.Err() | ||||
| 			} | ||||
| 			vars = append(vars, sc.Text()) | ||||
| 		} | ||||
| 		return WithEnv(vars)(nil, nil, nil, s) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ErrNoShmMount is returned when there is no /dev/shm mount specified in the config | ||||
| // and an Opts was trying to set a configuration value on the mount. | ||||
| var ErrNoShmMount = errors.New("no /dev/shm mount specified") | ||||
|  | ||||
| // WithDevShmSize sets the size of the /dev/shm mount for the container. | ||||
| // | ||||
| // The size value is specified in kb, kilobytes. | ||||
| func WithDevShmSize(kb int64) SpecOpts { | ||||
| 	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { | ||||
| 		for _, m := range s.Mounts { | ||||
| 			if m.Source == "shm" && m.Type == "tmpfs" { | ||||
| 				for i, o := range m.Options { | ||||
| 					if strings.HasPrefix(o, "size=") { | ||||
| 						m.Options[i] = fmt.Sprintf("size=%dk", kb) | ||||
| 						return nil | ||||
| 					} | ||||
| 				} | ||||
| 				m.Options = append(m.Options, fmt.Sprintf("size=%dk", kb)) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		return ErrNoShmMount | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										121
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| // +build linux | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package oci | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // WithHostDevices adds all the hosts device nodes to the container's spec | ||||
| func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 	setLinux(s) | ||||
|  | ||||
| 	devs, err := getDevices("/dev") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	s.Linux.Devices = append(s.Linux.Devices, devs...) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getDevices(path string) ([]specs.LinuxDevice, error) { | ||||
| 	files, err := ioutil.ReadDir(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var out []specs.LinuxDevice | ||||
| 	for _, f := range files { | ||||
| 		switch { | ||||
| 		case f.IsDir(): | ||||
| 			switch f.Name() { | ||||
| 			// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 | ||||
| 			// ".udev" added to address https://github.com/opencontainers/runc/issues/2093 | ||||
| 			case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": | ||||
| 				continue | ||||
| 			default: | ||||
| 				sub, err := getDevices(filepath.Join(path, f.Name())) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
|  | ||||
| 				out = append(out, sub...) | ||||
| 				continue | ||||
| 			} | ||||
| 		case f.Name() == "console": | ||||
| 			continue | ||||
| 		} | ||||
| 		device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm") | ||||
| 		if err != nil { | ||||
| 			if err == ErrNotADevice { | ||||
| 				continue | ||||
| 			} | ||||
| 			if os.IsNotExist(err) { | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		out = append(out, *device) | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { | ||||
| 	var stat unix.Stat_t | ||||
| 	if err := unix.Lstat(path, &stat); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		// The type is 32bit on mips. | ||||
| 		devNumber = uint64(stat.Rdev) // nolint: unconvert | ||||
| 		major     = unix.Major(devNumber) | ||||
| 		minor     = unix.Minor(devNumber) | ||||
| 	) | ||||
| 	if major == 0 { | ||||
| 		return nil, ErrNotADevice | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		devType string | ||||
| 		mode    = stat.Mode | ||||
| 	) | ||||
| 	switch { | ||||
| 	case mode&unix.S_IFBLK == unix.S_IFBLK: | ||||
| 		devType = "b" | ||||
| 	case mode&unix.S_IFCHR == unix.S_IFCHR: | ||||
| 		devType = "c" | ||||
| 	} | ||||
| 	fm := os.FileMode(mode) | ||||
| 	return &specs.LinuxDevice{ | ||||
| 		Type:     devType, | ||||
| 		Path:     path, | ||||
| 		Major:    int64(major), | ||||
| 		Minor:    int64(minor), | ||||
| 		FileMode: &fm, | ||||
| 		UID:      &stat.Uid, | ||||
| 		GID:      &stat.Gid, | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										120
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| // +build !linux,!windows | ||||
|  | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package oci | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // WithHostDevices adds all the hosts device nodes to the container's spec | ||||
| func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 	setLinux(s) | ||||
|  | ||||
| 	devs, err := getDevices("/dev") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	s.Linux.Devices = append(s.Linux.Devices, devs...) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getDevices(path string) ([]specs.LinuxDevice, error) { | ||||
| 	files, err := ioutil.ReadDir(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var out []specs.LinuxDevice | ||||
| 	for _, f := range files { | ||||
| 		switch { | ||||
| 		case f.IsDir(): | ||||
| 			switch f.Name() { | ||||
| 			// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 | ||||
| 			// ".udev" added to address https://github.com/opencontainers/runc/issues/2093 | ||||
| 			case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": | ||||
| 				continue | ||||
| 			default: | ||||
| 				sub, err := getDevices(filepath.Join(path, f.Name())) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
|  | ||||
| 				out = append(out, sub...) | ||||
| 				continue | ||||
| 			} | ||||
| 		case f.Name() == "console": | ||||
| 			continue | ||||
| 		} | ||||
| 		device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm") | ||||
| 		if err != nil { | ||||
| 			if err == ErrNotADevice { | ||||
| 				continue | ||||
| 			} | ||||
| 			if os.IsNotExist(err) { | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		out = append(out, *device) | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { | ||||
| 	var stat unix.Stat_t | ||||
| 	if err := unix.Lstat(path, &stat); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		devNumber = uint64(stat.Rdev) | ||||
| 		major     = unix.Major(devNumber) | ||||
| 		minor     = unix.Minor(devNumber) | ||||
| 	) | ||||
| 	if major == 0 { | ||||
| 		return nil, ErrNotADevice | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		devType string | ||||
| 		mode    = stat.Mode | ||||
| 	) | ||||
| 	switch { | ||||
| 	case mode&unix.S_IFBLK == unix.S_IFBLK: | ||||
| 		devType = "b" | ||||
| 	case mode&unix.S_IFCHR == unix.S_IFCHR: | ||||
| 		devType = "c" | ||||
| 	} | ||||
| 	fm := os.FileMode(mode) | ||||
| 	return &specs.LinuxDevice{ | ||||
| 		Type:     devType, | ||||
| 		Path:     path, | ||||
| 		Major:    int64(major), | ||||
| 		Minor:    int64(minor), | ||||
| 		FileMode: &fm, | ||||
| 		UID:      &stat.Uid, | ||||
| 		GID:      &stat.Gid, | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,6 +23,7 @@ import ( | ||||
|  | ||||
| 	"github.com/containerd/containerd/containers" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the | ||||
| @@ -65,3 +66,14 @@ func WithWindowNetworksAllowUnqualifiedDNSQuery() SpecOpts { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithHostDevices adds all the hosts device nodes to the container's spec | ||||
| // | ||||
| // Not supported on windows | ||||
| func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { | ||||
| 	return nil, errors.New("device from path not supported on Windows") | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/containerd/containerd/pkg/dialer/dialer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/containerd/containerd/pkg/dialer/dialer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package dialer | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"net" | ||||
| 	"time" | ||||
|  | ||||
| @@ -28,8 +29,19 @@ type dialResult struct { | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| // ContextDialer returns a GRPC net.Conn connected to the provided address | ||||
| func ContextDialer(ctx context.Context, address string) (net.Conn, error) { | ||||
| 	if deadline, ok := ctx.Deadline(); ok { | ||||
| 		return timeoutDialer(address, time.Until(deadline)) | ||||
| 	} | ||||
| 	return timeoutDialer(address, 0) | ||||
| } | ||||
|  | ||||
| // Dialer returns a GRPC net.Conn connected to the provided address | ||||
| func Dialer(address string, timeout time.Duration) (net.Conn, error) { | ||||
| // Deprecated: use ContextDialer and grpc.WithContextDialer. | ||||
| var Dialer = timeoutDialer | ||||
|  | ||||
| func timeoutDialer(address string, timeout time.Duration) (net.Conn, error) { | ||||
| 	var ( | ||||
| 		stopC = make(chan struct{}) | ||||
| 		synC  = make(chan *dialResult) | ||||
|   | ||||
							
								
								
									
										37
									
								
								vendor/github.com/containerd/containerd/platforms/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/containerd/containerd/platforms/compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,11 +29,48 @@ type MatchComparer interface { | ||||
| // Only returns a match comparer for a single platform | ||||
| // using default resolution logic for the platform. | ||||
| // | ||||
| // For ARMv8, will also match ARMv7, ARMv6 and ARMv5 (for 32bit runtimes) | ||||
| // For ARMv7, will also match ARMv6 and ARMv5 | ||||
| // For ARMv6, will also match ARMv5 | ||||
| func Only(platform specs.Platform) MatchComparer { | ||||
| 	platform = Normalize(platform) | ||||
| 	if platform.Architecture == "arm" { | ||||
| 		if platform.Variant == "v8" { | ||||
| 			return orderedPlatformComparer{ | ||||
| 				matchers: []Matcher{ | ||||
| 					&matcher{ | ||||
| 						Platform: platform, | ||||
| 					}, | ||||
| 					&matcher{ | ||||
| 						Platform: specs.Platform{ | ||||
| 							Architecture: platform.Architecture, | ||||
| 							OS:           platform.OS, | ||||
| 							OSVersion:    platform.OSVersion, | ||||
| 							OSFeatures:   platform.OSFeatures, | ||||
| 							Variant:      "v7", | ||||
| 						}, | ||||
| 					}, | ||||
| 					&matcher{ | ||||
| 						Platform: specs.Platform{ | ||||
| 							Architecture: platform.Architecture, | ||||
| 							OS:           platform.OS, | ||||
| 							OSVersion:    platform.OSVersion, | ||||
| 							OSFeatures:   platform.OSFeatures, | ||||
| 							Variant:      "v6", | ||||
| 						}, | ||||
| 					}, | ||||
| 					&matcher{ | ||||
| 						Platform: specs.Platform{ | ||||
| 							Architecture: platform.Architecture, | ||||
| 							OS:           platform.OS, | ||||
| 							OSVersion:    platform.OSVersion, | ||||
| 							OSFeatures:   platform.OSFeatures, | ||||
| 							Variant:      "v5", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 		} | ||||
| 		if platform.Variant == "v7" { | ||||
| 			return orderedPlatformComparer{ | ||||
| 				matchers: []Matcher{ | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/platforms/cpuinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/platforms/cpuinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -97,7 +97,7 @@ func getCPUVariant() string { | ||||
| 	} | ||||
|  | ||||
| 	switch variant { | ||||
| 	case "8": | ||||
| 	case "8", "AArch64": | ||||
| 		variant = "v8" | ||||
| 	case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)": | ||||
| 		variant = "v7" | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/containerd/containerd/platforms/database.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/containerd/containerd/platforms/database.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -28,7 +28,7 @@ func isLinuxOS(os string) bool { | ||||
| 	return os == "linux" | ||||
| } | ||||
|  | ||||
| // These function are generated from from https://golang.org/src/go/build/syslist.go. | ||||
| // These function are generated from https://golang.org/src/go/build/syslist.go. | ||||
| // | ||||
| // We use switch statements because they are slightly faster than map lookups | ||||
| // and use a little less memory. | ||||
| @@ -38,7 +38,7 @@ func isLinuxOS(os string) bool { | ||||
| // The OS value should be normalized before calling this function. | ||||
| func isKnownOS(os string) bool { | ||||
| 	switch os { | ||||
| 	case "android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos": | ||||
| 	case "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos": | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| @@ -60,7 +60,7 @@ func isArmArch(arch string) bool { | ||||
| // The arch value should be normalized before being passed to this function. | ||||
| func isKnownArch(arch string) bool { | ||||
| 	switch arch { | ||||
| 	case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "s390", "s390x", "sparc", "sparc64": | ||||
| 	case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm": | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/platforms/platforms.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/platforms/platforms.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -130,7 +130,7 @@ type Matcher interface { | ||||
| // specification. The returned matcher only looks for equality based on os, | ||||
| // architecture and variant. | ||||
| // | ||||
| // One may implement their own matcher if this doesn't provide the the required | ||||
| // One may implement their own matcher if this doesn't provide the required | ||||
| // functionality. | ||||
| // | ||||
| // Applications should opt to use `Match` over directly parsing specifiers. | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/containerd/containerd/plugin/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/containerd/containerd/plugin/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -28,12 +28,13 @@ import ( | ||||
|  | ||||
| // InitContext is used for plugin inititalization | ||||
| type InitContext struct { | ||||
| 	Context context.Context | ||||
| 	Root    string | ||||
| 	State   string | ||||
| 	Config  interface{} | ||||
| 	Address string | ||||
| 	Events  *exchange.Exchange | ||||
| 	Context      context.Context | ||||
| 	Root         string | ||||
| 	State        string | ||||
| 	Config       interface{} | ||||
| 	Address      string | ||||
| 	TTRPCAddress string | ||||
| 	Events       *exchange.Exchange | ||||
|  | ||||
| 	Meta *Meta // plugins can fill in metadata at init. | ||||
|  | ||||
|   | ||||
							
								
								
									
										49
									
								
								vendor/github.com/containerd/containerd/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/containerd/containerd/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -30,7 +30,8 @@ var ( | ||||
| 	ErrNoType = errors.New("plugin: no type") | ||||
| 	// ErrNoPluginID is returned when no id is specified | ||||
| 	ErrNoPluginID = errors.New("plugin: no id") | ||||
|  | ||||
| 	// ErrIDRegistered is returned when a duplicate id is already registered | ||||
| 	ErrIDRegistered = errors.New("plugin: id already registered") | ||||
| 	// ErrSkipPlugin is used when a plugin is not initialized and should not be loaded, | ||||
| 	// this allows the plugin loader differentiate between a plugin which is configured | ||||
| 	// not to load and one that fails to load. | ||||
| @@ -100,6 +101,8 @@ type Registration struct { | ||||
| 	// context are passed in. The init function may modify the registration to | ||||
| 	// add exports, capabilities and platform support declarations. | ||||
| 	InitFn func(*InitContext) (interface{}, error) | ||||
| 	// Disable the plugin from loading | ||||
| 	Disable bool | ||||
| } | ||||
|  | ||||
| // Init the registered plugin | ||||
| @@ -157,12 +160,16 @@ func Load(path string) (err error) { | ||||
| func Register(r *Registration) { | ||||
| 	register.Lock() | ||||
| 	defer register.Unlock() | ||||
|  | ||||
| 	if r.Type == "" { | ||||
| 		panic(ErrNoType) | ||||
| 	} | ||||
| 	if r.ID == "" { | ||||
| 		panic(ErrNoPluginID) | ||||
| 	} | ||||
| 	if err := checkUnique(r); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	var last bool | ||||
| 	for _, requires := range r.Requires { | ||||
| @@ -177,24 +184,36 @@ func Register(r *Registration) { | ||||
| 	register.r = append(register.r, r) | ||||
| } | ||||
|  | ||||
| func checkUnique(r *Registration) error { | ||||
| 	for _, registered := range register.r { | ||||
| 		if r.URI() == registered.URI() { | ||||
| 			return errors.Wrap(ErrIDRegistered, r.URI()) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DisableFilter filters out disabled plugins | ||||
| type DisableFilter func(r *Registration) bool | ||||
|  | ||||
| // Graph returns an ordered list of registered plugins for initialization. | ||||
| // Plugins in disableList specified by id will be disabled. | ||||
| func Graph(disableList []string) (ordered []*Registration) { | ||||
| func Graph(filter DisableFilter) (ordered []*Registration) { | ||||
| 	register.RLock() | ||||
| 	defer register.RUnlock() | ||||
| 	for _, d := range disableList { | ||||
| 		for i, r := range register.r { | ||||
| 			if r.ID == d { | ||||
| 				register.r = append(register.r[:i], register.r[i+1:]...) | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 	for _, r := range register.r { | ||||
| 		if filter(r) { | ||||
| 			r.Disable = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	added := map[*Registration]bool{} | ||||
| 	for _, r := range register.r { | ||||
|  | ||||
| 		children(r.ID, r.Requires, added, &ordered) | ||||
| 		if r.Disable { | ||||
| 			continue | ||||
| 		} | ||||
| 		children(r, added, &ordered) | ||||
| 		if !added[r] { | ||||
| 			ordered = append(ordered, r) | ||||
| 			added[r] = true | ||||
| @@ -203,11 +222,13 @@ func Graph(disableList []string) (ordered []*Registration) { | ||||
| 	return ordered | ||||
| } | ||||
|  | ||||
| func children(id string, types []Type, added map[*Registration]bool, ordered *[]*Registration) { | ||||
| 	for _, t := range types { | ||||
| func children(reg *Registration, added map[*Registration]bool, ordered *[]*Registration) { | ||||
| 	for _, t := range reg.Requires { | ||||
| 		for _, r := range register.r { | ||||
| 			if r.ID != id && (t == "*" || r.Type == t) { | ||||
| 				children(r.ID, r.Requires, added, ordered) | ||||
| 			if !r.Disable && | ||||
| 				r.URI() != reg.URI() && | ||||
| 				(t == "*" || r.Type == t) { | ||||
| 				children(r, added, ordered) | ||||
| 				if !added[r] { | ||||
| 					*ordered = append(*ordered, r) | ||||
| 					added[r] = true | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/containerd/containerd/process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containerd/containerd/process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -44,7 +44,7 @@ type Process interface { | ||||
| 	Wait(context.Context) (<-chan ExitStatus, error) | ||||
| 	// CloseIO allows various pipes to be closed on the process | ||||
| 	CloseIO(context.Context, ...IOCloserOpts) error | ||||
| 	// Resize changes the width and heigh of the process's terminal | ||||
| 	// Resize changes the width and height of the process's terminal | ||||
| 	Resize(ctx context.Context, w, h uint32) error | ||||
| 	// IO returns the io set for the process | ||||
| 	IO() cio.IO | ||||
| @@ -61,7 +61,7 @@ func NewExitStatus(code uint32, t time.Time, err error) *ExitStatus { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ExitStatus encapsulates a process' exit status. | ||||
| // ExitStatus encapsulates a process's exit status. | ||||
| // It is used by `Wait()` to return either a process exit code or an error | ||||
| type ExitStatus struct { | ||||
| 	code     uint32 | ||||
|   | ||||
							
								
								
									
										63
									
								
								vendor/github.com/containerd/containerd/pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/containerd/containerd/pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,7 +32,7 @@ import ( | ||||
|  | ||||
| // Pull downloads the provided content into containerd's content store | ||||
| // and returns a platform specific image object | ||||
| func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) { | ||||
| func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Image, retErr error) { | ||||
| 	pullCtx := defaultRemoteContext() | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(c, pullCtx); err != nil { | ||||
| @@ -44,7 +44,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image | ||||
| 		if len(pullCtx.Platforms) > 1 { | ||||
| 			return nil, errors.New("cannot pull multiplatform image locally, try Fetch") | ||||
| 		} else if len(pullCtx.Platforms) == 0 { | ||||
| 			pullCtx.PlatformMatcher = platforms.Default() | ||||
| 			pullCtx.PlatformMatcher = c.platform | ||||
| 		} else { | ||||
| 			p, err := platforms.Parse(pullCtx.Platforms[0]) | ||||
| 			if err != nil { | ||||
| @@ -61,6 +61,30 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image | ||||
| 	} | ||||
| 	defer done(ctx) | ||||
|  | ||||
| 	var unpacks int32 | ||||
| 	if pullCtx.Unpack { | ||||
| 		// unpacker only supports schema 2 image, for schema 1 this is noop. | ||||
| 		u, err := c.newUnpacker(ctx, pullCtx) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "create unpacker") | ||||
| 		} | ||||
| 		unpackWrapper, eg := u.handlerWrapper(ctx, &unpacks) | ||||
| 		defer func() { | ||||
| 			if err := eg.Wait(); err != nil { | ||||
| 				if retErr == nil { | ||||
| 					retErr = errors.Wrap(err, "unpack") | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 		wrapper := pullCtx.HandlerWrapper | ||||
| 		pullCtx.HandlerWrapper = func(h images.Handler) images.Handler { | ||||
| 			if wrapper == nil { | ||||
| 				return unpackWrapper(h) | ||||
| 			} | ||||
| 			return wrapper(unpackWrapper(h)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	img, err := c.fetch(ctx, pullCtx, ref, 1) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -69,8 +93,12 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image | ||||
| 	i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher) | ||||
|  | ||||
| 	if pullCtx.Unpack { | ||||
| 		if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil { | ||||
| 			return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) | ||||
| 		if unpacks == 0 { | ||||
| 			// Try to unpack is none is done previously. | ||||
| 			// This is at least required for schema 1 image. | ||||
| 			if err := i.Unpack(ctx, pullCtx.Snapshotter, pullCtx.UnpackOpts...); err != nil { | ||||
| 				return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -112,9 +140,14 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim | ||||
| 		childrenHandler := images.ChildrenHandler(store) | ||||
| 		// Set any children labels for that content | ||||
| 		childrenHandler = images.SetChildrenLabels(store, childrenHandler) | ||||
| 		// Filter manifests by platforms but allow to handle manifest | ||||
| 		// and configuration for not-target platforms | ||||
| 		childrenHandler = remotes.FilterManifestByPlatformHandler(childrenHandler, rCtx.PlatformMatcher) | ||||
| 		if rCtx.AllMetadata { | ||||
| 			// Filter manifests by platforms but allow to handle manifest | ||||
| 			// and configuration for not-target platforms | ||||
| 			childrenHandler = remotes.FilterManifestByPlatformHandler(childrenHandler, rCtx.PlatformMatcher) | ||||
| 		} else { | ||||
| 			// Filter children by platforms if specified. | ||||
| 			childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher) | ||||
| 		} | ||||
| 		// Sort and limit manifests if a finite number is needed | ||||
| 		if limit > 0 { | ||||
| 			childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) | ||||
| @@ -131,22 +164,18 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim | ||||
| 			}, | ||||
| 		) | ||||
|  | ||||
| 		appendDistSrcLabelHandler, err := docker.AppendDistributionSourceLabel(store, ref) | ||||
| 		if err != nil { | ||||
| 			return images.Image{}, err | ||||
| 		} | ||||
|  | ||||
| 		handlers := append(rCtx.BaseHandlers, | ||||
| 			remotes.FetchHandler(store, fetcher), | ||||
| 			convertibleHandler, | ||||
| 			childrenHandler, | ||||
| 			appendDistSrcLabelHandler, | ||||
| 		) | ||||
|  | ||||
| 		// append distribution source label to blob data | ||||
| 		if rCtx.AppendDistributionSourceLabel { | ||||
| 			appendDistSrcLabelHandler, err := docker.AppendDistributionSourceLabel(store, ref) | ||||
| 			if err != nil { | ||||
| 				return images.Image{}, err | ||||
| 			} | ||||
|  | ||||
| 			handlers = append(handlers, appendDistSrcLabelHandler) | ||||
| 		} | ||||
|  | ||||
| 		handler = images.Handlers(handlers...) | ||||
|  | ||||
| 		converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) { | ||||
|   | ||||
							
								
								
									
										797
									
								
								vendor/github.com/containerd/containerd/reference/docker/reference.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										797
									
								
								vendor/github.com/containerd/containerd/reference/docker/reference.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,797 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package docker provides a general type to represent any way of referencing images within the registry. | ||||
| // Its main purpose is to abstract tags and digests (content-addressable hash). | ||||
| // | ||||
| // Grammar | ||||
| // | ||||
| // 	reference                       := name [ ":" tag ] [ "@" digest ] | ||||
| //	name                            := [domain '/'] path-component ['/' path-component]* | ||||
| //	domain                          := domain-component ['.' domain-component]* [':' port-number] | ||||
| //	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ | ||||
| //	port-number                     := /[0-9]+/ | ||||
| //	path-component                  := alpha-numeric [separator alpha-numeric]* | ||||
| // 	alpha-numeric                   := /[a-z0-9]+/ | ||||
| //	separator                       := /[_.]|__|[-]*/ | ||||
| // | ||||
| //	tag                             := /[\w][\w.-]{0,127}/ | ||||
| // | ||||
| //	digest                          := digest-algorithm ":" digest-hex | ||||
| //	digest-algorithm                := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* | ||||
| //	digest-algorithm-separator      := /[+.-_]/ | ||||
| //	digest-algorithm-component      := /[A-Za-z][A-Za-z0-9]*/ | ||||
| //	digest-hex                      := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value | ||||
| // | ||||
| //	identifier                      := /[a-f0-9]{64}/ | ||||
| //	short-identifier                := /[a-f0-9]{6,64}/ | ||||
| package docker | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"path" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/opencontainers/go-digest" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// NameTotalLengthMax is the maximum total number of characters in a repository name. | ||||
| 	NameTotalLengthMax = 255 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. | ||||
| 	ErrReferenceInvalidFormat = errors.New("invalid reference format") | ||||
|  | ||||
| 	// ErrTagInvalidFormat represents an error while trying to parse a string as a tag. | ||||
| 	ErrTagInvalidFormat = errors.New("invalid tag format") | ||||
|  | ||||
| 	// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. | ||||
| 	ErrDigestInvalidFormat = errors.New("invalid digest format") | ||||
|  | ||||
| 	// ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. | ||||
| 	ErrNameContainsUppercase = errors.New("repository name must be lowercase") | ||||
|  | ||||
| 	// ErrNameEmpty is returned for empty, invalid repository names. | ||||
| 	ErrNameEmpty = errors.New("repository name must have at least one component") | ||||
|  | ||||
| 	// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. | ||||
| 	ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) | ||||
|  | ||||
| 	// ErrNameNotCanonical is returned when a name is not canonical. | ||||
| 	ErrNameNotCanonical = errors.New("repository name must be canonical") | ||||
| ) | ||||
|  | ||||
| // Reference is an opaque object reference identifier that may include | ||||
| // modifiers such as a hostname, name, tag, and digest. | ||||
| type Reference interface { | ||||
| 	// String returns the full reference | ||||
| 	String() string | ||||
| } | ||||
|  | ||||
| // Field provides a wrapper type for resolving correct reference types when | ||||
| // working with encoding. | ||||
| type Field struct { | ||||
| 	reference Reference | ||||
| } | ||||
|  | ||||
| // AsField wraps a reference in a Field for encoding. | ||||
| func AsField(reference Reference) Field { | ||||
| 	return Field{reference} | ||||
| } | ||||
|  | ||||
| // Reference unwraps the reference type from the field to | ||||
| // return the Reference object. This object should be | ||||
| // of the appropriate type to further check for different | ||||
| // reference types. | ||||
| func (f Field) Reference() Reference { | ||||
| 	return f.reference | ||||
| } | ||||
|  | ||||
| // MarshalText serializes the field to byte text which | ||||
| // is the string of the reference. | ||||
| func (f Field) MarshalText() (p []byte, err error) { | ||||
| 	return []byte(f.reference.String()), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalText parses text bytes by invoking the | ||||
| // reference parser to ensure the appropriately | ||||
| // typed reference object is wrapped by field. | ||||
| func (f *Field) UnmarshalText(p []byte) error { | ||||
| 	r, err := Parse(string(p)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	f.reference = r | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Named is an object with a full name | ||||
| type Named interface { | ||||
| 	Reference | ||||
| 	Name() string | ||||
| } | ||||
|  | ||||
| // Tagged is an object which has a tag | ||||
| type Tagged interface { | ||||
| 	Reference | ||||
| 	Tag() string | ||||
| } | ||||
|  | ||||
| // NamedTagged is an object including a name and tag. | ||||
| type NamedTagged interface { | ||||
| 	Named | ||||
| 	Tag() string | ||||
| } | ||||
|  | ||||
| // Digested is an object which has a digest | ||||
| // in which it can be referenced by | ||||
| type Digested interface { | ||||
| 	Reference | ||||
| 	Digest() digest.Digest | ||||
| } | ||||
|  | ||||
| // Canonical reference is an object with a fully unique | ||||
| // name including a name with domain and digest | ||||
| type Canonical interface { | ||||
| 	Named | ||||
| 	Digest() digest.Digest | ||||
| } | ||||
|  | ||||
| // namedRepository is a reference to a repository with a name. | ||||
| // A namedRepository has both domain and path components. | ||||
| type namedRepository interface { | ||||
| 	Named | ||||
| 	Domain() string | ||||
| 	Path() string | ||||
| } | ||||
|  | ||||
| // Domain returns the domain part of the Named reference | ||||
| func Domain(named Named) string { | ||||
| 	if r, ok := named.(namedRepository); ok { | ||||
| 		return r.Domain() | ||||
| 	} | ||||
| 	domain, _ := splitDomain(named.Name()) | ||||
| 	return domain | ||||
| } | ||||
|  | ||||
| // Path returns the name without the domain part of the Named reference | ||||
| func Path(named Named) (name string) { | ||||
| 	if r, ok := named.(namedRepository); ok { | ||||
| 		return r.Path() | ||||
| 	} | ||||
| 	_, path := splitDomain(named.Name()) | ||||
| 	return path | ||||
| } | ||||
|  | ||||
| func splitDomain(name string) (string, string) { | ||||
| 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||
| 	if len(match) != 3 { | ||||
| 		return "", name | ||||
| 	} | ||||
| 	return match[1], match[2] | ||||
| } | ||||
|  | ||||
| // SplitHostname splits a named reference into a | ||||
| // hostname and name string. If no valid hostname is | ||||
| // found, the hostname is empty and the full value | ||||
| // is returned as name | ||||
| // DEPRECATED: Use Domain or Path | ||||
| func SplitHostname(named Named) (string, string) { | ||||
| 	if r, ok := named.(namedRepository); ok { | ||||
| 		return r.Domain(), r.Path() | ||||
| 	} | ||||
| 	return splitDomain(named.Name()) | ||||
| } | ||||
|  | ||||
| // Parse parses s and returns a syntactically valid Reference. | ||||
| // If an error was encountered it is returned, along with a nil Reference. | ||||
| // NOTE: Parse will not handle short digests. | ||||
| func Parse(s string) (Reference, error) { | ||||
| 	matches := ReferenceRegexp.FindStringSubmatch(s) | ||||
| 	if matches == nil { | ||||
| 		if s == "" { | ||||
| 			return nil, ErrNameEmpty | ||||
| 		} | ||||
| 		if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { | ||||
| 			return nil, ErrNameContainsUppercase | ||||
| 		} | ||||
| 		return nil, ErrReferenceInvalidFormat | ||||
| 	} | ||||
|  | ||||
| 	if len(matches[1]) > NameTotalLengthMax { | ||||
| 		return nil, ErrNameTooLong | ||||
| 	} | ||||
|  | ||||
| 	var repo repository | ||||
|  | ||||
| 	nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) | ||||
| 	if len(nameMatch) == 3 { | ||||
| 		repo.domain = nameMatch[1] | ||||
| 		repo.path = nameMatch[2] | ||||
| 	} else { | ||||
| 		repo.domain = "" | ||||
| 		repo.path = matches[1] | ||||
| 	} | ||||
|  | ||||
| 	ref := reference{ | ||||
| 		namedRepository: repo, | ||||
| 		tag:             matches[2], | ||||
| 	} | ||||
| 	if matches[3] != "" { | ||||
| 		var err error | ||||
| 		ref.digest, err = digest.Parse(matches[3]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	r := getBestReferenceType(ref) | ||||
| 	if r == nil { | ||||
| 		return nil, ErrNameEmpty | ||||
| 	} | ||||
|  | ||||
| 	return r, nil | ||||
| } | ||||
|  | ||||
| // ParseNamed parses s and returns a syntactically valid reference implementing | ||||
| // the Named interface. The reference must have a name and be in the canonical | ||||
| // form, otherwise an error is returned. | ||||
| // If an error was encountered it is returned, along with a nil Reference. | ||||
| // NOTE: ParseNamed will not handle short digests. | ||||
| func ParseNamed(s string) (Named, error) { | ||||
| 	named, err := ParseNormalizedNamed(s) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if named.String() != s { | ||||
| 		return nil, ErrNameNotCanonical | ||||
| 	} | ||||
| 	return named, nil | ||||
| } | ||||
|  | ||||
| // WithName returns a named object representing the given string. If the input | ||||
| // is invalid ErrReferenceInvalidFormat will be returned. | ||||
| func WithName(name string) (Named, error) { | ||||
| 	if len(name) > NameTotalLengthMax { | ||||
| 		return nil, ErrNameTooLong | ||||
| 	} | ||||
|  | ||||
| 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||
| 	if match == nil || len(match) != 3 { | ||||
| 		return nil, ErrReferenceInvalidFormat | ||||
| 	} | ||||
| 	return repository{ | ||||
| 		domain: match[1], | ||||
| 		path:   match[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // WithTag combines the name from "name" and the tag from "tag" to form a | ||||
| // reference incorporating both the name and the tag. | ||||
| func WithTag(name Named, tag string) (NamedTagged, error) { | ||||
| 	if !anchoredTagRegexp.MatchString(tag) { | ||||
| 		return nil, ErrTagInvalidFormat | ||||
| 	} | ||||
| 	var repo repository | ||||
| 	if r, ok := name.(namedRepository); ok { | ||||
| 		repo.domain = r.Domain() | ||||
| 		repo.path = r.Path() | ||||
| 	} else { | ||||
| 		repo.path = name.Name() | ||||
| 	} | ||||
| 	if canonical, ok := name.(Canonical); ok { | ||||
| 		return reference{ | ||||
| 			namedRepository: repo, | ||||
| 			tag:             tag, | ||||
| 			digest:          canonical.Digest(), | ||||
| 		}, nil | ||||
| 	} | ||||
| 	return taggedReference{ | ||||
| 		namedRepository: repo, | ||||
| 		tag:             tag, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // WithDigest combines the name from "name" and the digest from "digest" to form | ||||
| // a reference incorporating both the name and the digest. | ||||
| func WithDigest(name Named, digest digest.Digest) (Canonical, error) { | ||||
| 	if !anchoredDigestRegexp.MatchString(digest.String()) { | ||||
| 		return nil, ErrDigestInvalidFormat | ||||
| 	} | ||||
| 	var repo repository | ||||
| 	if r, ok := name.(namedRepository); ok { | ||||
| 		repo.domain = r.Domain() | ||||
| 		repo.path = r.Path() | ||||
| 	} else { | ||||
| 		repo.path = name.Name() | ||||
| 	} | ||||
| 	if tagged, ok := name.(Tagged); ok { | ||||
| 		return reference{ | ||||
| 			namedRepository: repo, | ||||
| 			tag:             tagged.Tag(), | ||||
| 			digest:          digest, | ||||
| 		}, nil | ||||
| 	} | ||||
| 	return canonicalReference{ | ||||
| 		namedRepository: repo, | ||||
| 		digest:          digest, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // TrimNamed removes any tag or digest from the named reference. | ||||
| func TrimNamed(ref Named) Named { | ||||
| 	domain, path := SplitHostname(ref) | ||||
| 	return repository{ | ||||
| 		domain: domain, | ||||
| 		path:   path, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getBestReferenceType(ref reference) Reference { | ||||
| 	if ref.Name() == "" { | ||||
| 		// Allow digest only references | ||||
| 		if ref.digest != "" { | ||||
| 			return digestReference(ref.digest) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	if ref.tag == "" { | ||||
| 		if ref.digest != "" { | ||||
| 			return canonicalReference{ | ||||
| 				namedRepository: ref.namedRepository, | ||||
| 				digest:          ref.digest, | ||||
| 			} | ||||
| 		} | ||||
| 		return ref.namedRepository | ||||
| 	} | ||||
| 	if ref.digest == "" { | ||||
| 		return taggedReference{ | ||||
| 			namedRepository: ref.namedRepository, | ||||
| 			tag:             ref.tag, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ref | ||||
| } | ||||
|  | ||||
| type reference struct { | ||||
| 	namedRepository | ||||
| 	tag    string | ||||
| 	digest digest.Digest | ||||
| } | ||||
|  | ||||
| func (r reference) String() string { | ||||
| 	return r.Name() + ":" + r.tag + "@" + r.digest.String() | ||||
| } | ||||
|  | ||||
| func (r reference) Tag() string { | ||||
| 	return r.tag | ||||
| } | ||||
|  | ||||
| func (r reference) Digest() digest.Digest { | ||||
| 	return r.digest | ||||
| } | ||||
|  | ||||
| type repository struct { | ||||
| 	domain string | ||||
| 	path   string | ||||
| } | ||||
|  | ||||
| func (r repository) String() string { | ||||
| 	return r.Name() | ||||
| } | ||||
|  | ||||
| func (r repository) Name() string { | ||||
| 	if r.domain == "" { | ||||
| 		return r.path | ||||
| 	} | ||||
| 	return r.domain + "/" + r.path | ||||
| } | ||||
|  | ||||
| func (r repository) Domain() string { | ||||
| 	return r.domain | ||||
| } | ||||
|  | ||||
| func (r repository) Path() string { | ||||
| 	return r.path | ||||
| } | ||||
|  | ||||
| type digestReference digest.Digest | ||||
|  | ||||
| func (d digestReference) String() string { | ||||
| 	return digest.Digest(d).String() | ||||
| } | ||||
|  | ||||
| func (d digestReference) Digest() digest.Digest { | ||||
| 	return digest.Digest(d) | ||||
| } | ||||
|  | ||||
| type taggedReference struct { | ||||
| 	namedRepository | ||||
| 	tag string | ||||
| } | ||||
|  | ||||
| func (t taggedReference) String() string { | ||||
| 	return t.Name() + ":" + t.tag | ||||
| } | ||||
|  | ||||
| func (t taggedReference) Tag() string { | ||||
| 	return t.tag | ||||
| } | ||||
|  | ||||
| type canonicalReference struct { | ||||
| 	namedRepository | ||||
| 	digest digest.Digest | ||||
| } | ||||
|  | ||||
| func (c canonicalReference) String() string { | ||||
| 	return c.Name() + "@" + c.digest.String() | ||||
| } | ||||
|  | ||||
| func (c canonicalReference) Digest() digest.Digest { | ||||
| 	return c.digest | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	// alphaNumericRegexp defines the alpha numeric atom, typically a | ||||
| 	// component of names. This only allows lower case characters and digits. | ||||
| 	alphaNumericRegexp = match(`[a-z0-9]+`) | ||||
|  | ||||
| 	// separatorRegexp defines the separators allowed to be embedded in name | ||||
| 	// components. This allow one period, one or two underscore and multiple | ||||
| 	// dashes. | ||||
| 	separatorRegexp = match(`(?:[._]|__|[-]*)`) | ||||
|  | ||||
| 	// nameComponentRegexp restricts registry path component names to start | ||||
| 	// with at least one letter or number, with following parts able to be | ||||
| 	// separated by one period, one or two underscore and multiple dashes. | ||||
| 	nameComponentRegexp = expression( | ||||
| 		alphaNumericRegexp, | ||||
| 		optional(repeated(separatorRegexp, alphaNumericRegexp))) | ||||
|  | ||||
| 	// domainComponentRegexp restricts the registry domain component of a | ||||
| 	// repository name to start with a component as defined by DomainRegexp | ||||
| 	// and followed by an optional port. | ||||
| 	domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) | ||||
|  | ||||
| 	// DomainRegexp defines the structure of potential domain components | ||||
| 	// that may be part of image names. This is purposely a subset of what is | ||||
| 	// allowed by DNS to ensure backwards compatibility with Docker image | ||||
| 	// names. | ||||
| 	DomainRegexp = expression( | ||||
| 		domainComponentRegexp, | ||||
| 		optional(repeated(literal(`.`), domainComponentRegexp)), | ||||
| 		optional(literal(`:`), match(`[0-9]+`))) | ||||
|  | ||||
| 	// TagRegexp matches valid tag names. From docker/docker:graph/tags.go. | ||||
| 	TagRegexp = match(`[\w][\w.-]{0,127}`) | ||||
|  | ||||
| 	// anchoredTagRegexp matches valid tag names, anchored at the start and | ||||
| 	// end of the matched string. | ||||
| 	anchoredTagRegexp = anchored(TagRegexp) | ||||
|  | ||||
| 	// DigestRegexp matches valid digests. | ||||
| 	DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) | ||||
|  | ||||
| 	// anchoredDigestRegexp matches valid digests, anchored at the start and | ||||
| 	// end of the matched string. | ||||
| 	anchoredDigestRegexp = anchored(DigestRegexp) | ||||
|  | ||||
| 	// NameRegexp is the format for the name component of references. The | ||||
| 	// regexp has capturing groups for the domain and name part omitting | ||||
| 	// the separating forward slash from either. | ||||
| 	NameRegexp = expression( | ||||
| 		optional(DomainRegexp, literal(`/`)), | ||||
| 		nameComponentRegexp, | ||||
| 		optional(repeated(literal(`/`), nameComponentRegexp))) | ||||
|  | ||||
| 	// anchoredNameRegexp is used to parse a name value, capturing the | ||||
| 	// domain and trailing components. | ||||
| 	anchoredNameRegexp = anchored( | ||||
| 		optional(capture(DomainRegexp), literal(`/`)), | ||||
| 		capture(nameComponentRegexp, | ||||
| 			optional(repeated(literal(`/`), nameComponentRegexp)))) | ||||
|  | ||||
| 	// ReferenceRegexp is the full supported format of a reference. The regexp | ||||
| 	// is anchored and has capturing groups for name, tag, and digest | ||||
| 	// components. | ||||
| 	ReferenceRegexp = anchored(capture(NameRegexp), | ||||
| 		optional(literal(":"), capture(TagRegexp)), | ||||
| 		optional(literal("@"), capture(DigestRegexp))) | ||||
|  | ||||
| 	// IdentifierRegexp is the format for string identifier used as a | ||||
| 	// content addressable identifier using sha256. These identifiers | ||||
| 	// are like digests without the algorithm, since sha256 is used. | ||||
| 	IdentifierRegexp = match(`([a-f0-9]{64})`) | ||||
|  | ||||
| 	// ShortIdentifierRegexp is the format used to represent a prefix | ||||
| 	// of an identifier. A prefix may be used to match a sha256 identifier | ||||
| 	// within a list of trusted identifiers. | ||||
| 	ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) | ||||
|  | ||||
| 	// anchoredIdentifierRegexp is used to check or match an | ||||
| 	// identifier value, anchored at start and end of string. | ||||
| 	anchoredIdentifierRegexp = anchored(IdentifierRegexp) | ||||
| ) | ||||
|  | ||||
| // match compiles the string to a regular expression. | ||||
| var match = regexp.MustCompile | ||||
|  | ||||
| // literal compiles s into a literal regular expression, escaping any regexp | ||||
| // reserved characters. | ||||
| func literal(s string) *regexp.Regexp { | ||||
| 	re := match(regexp.QuoteMeta(s)) | ||||
|  | ||||
| 	if _, complete := re.LiteralPrefix(); !complete { | ||||
| 		panic("must be a literal") | ||||
| 	} | ||||
|  | ||||
| 	return re | ||||
| } | ||||
|  | ||||
| // expression defines a full expression, where each regular expression must | ||||
| // follow the previous. | ||||
| func expression(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	var s string | ||||
| 	for _, re := range res { | ||||
| 		s += re.String() | ||||
| 	} | ||||
|  | ||||
| 	return match(s) | ||||
| } | ||||
|  | ||||
| // optional wraps the expression in a non-capturing group and makes the | ||||
| // production optional. | ||||
| func optional(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	return match(group(expression(res...)).String() + `?`) | ||||
| } | ||||
|  | ||||
| // repeated wraps the regexp in a non-capturing group to get one or more | ||||
| // matches. | ||||
| func repeated(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	return match(group(expression(res...)).String() + `+`) | ||||
| } | ||||
|  | ||||
| // group wraps the regexp in a non-capturing group. | ||||
| func group(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	return match(`(?:` + expression(res...).String() + `)`) | ||||
| } | ||||
|  | ||||
| // capture wraps the expression in a capturing group. | ||||
| func capture(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	return match(`(` + expression(res...).String() + `)`) | ||||
| } | ||||
|  | ||||
| // anchored anchors the regular expression by adding start and end delimiters. | ||||
| func anchored(res ...*regexp.Regexp) *regexp.Regexp { | ||||
| 	return match(`^` + expression(res...).String() + `$`) | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	legacyDefaultDomain = "index.docker.io" | ||||
| 	defaultDomain       = "docker.io" | ||||
| 	officialRepoName    = "library" | ||||
| 	defaultTag          = "latest" | ||||
| ) | ||||
|  | ||||
| // normalizedNamed represents a name which has been | ||||
| // normalized and has a familiar form. A familiar name | ||||
| // is what is used in Docker UI. An example normalized | ||||
| // name is "docker.io/library/ubuntu" and corresponding | ||||
| // familiar name of "ubuntu". | ||||
| type normalizedNamed interface { | ||||
| 	Named | ||||
| 	Familiar() Named | ||||
| } | ||||
|  | ||||
| // ParseNormalizedNamed parses a string into a named reference | ||||
| // transforming a familiar name from Docker UI to a fully | ||||
| // qualified reference. If the value may be an identifier | ||||
| // use ParseAnyReference. | ||||
| func ParseNormalizedNamed(s string) (Named, error) { | ||||
| 	if ok := anchoredIdentifierRegexp.MatchString(s); ok { | ||||
| 		return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) | ||||
| 	} | ||||
| 	domain, remainder := splitDockerDomain(s) | ||||
| 	var remoteName string | ||||
| 	if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { | ||||
| 		remoteName = remainder[:tagSep] | ||||
| 	} else { | ||||
| 		remoteName = remainder | ||||
| 	} | ||||
| 	if strings.ToLower(remoteName) != remoteName { | ||||
| 		return nil, errors.New("invalid reference format: repository name must be lowercase") | ||||
| 	} | ||||
|  | ||||
| 	ref, err := Parse(domain + "/" + remainder) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	named, isNamed := ref.(Named) | ||||
| 	if !isNamed { | ||||
| 		return nil, fmt.Errorf("reference %s has no name", ref.String()) | ||||
| 	} | ||||
| 	return named, nil | ||||
| } | ||||
|  | ||||
| // ParseDockerRef normalizes the image reference following the docker convention. This is added | ||||
| // mainly for backward compatibility. | ||||
| // The reference returned can only be either tagged or digested. For reference contains both tag | ||||
| // and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ | ||||
| // sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as | ||||
| // docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. | ||||
| func ParseDockerRef(ref string) (Named, error) { | ||||
| 	named, err := ParseNormalizedNamed(ref) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if _, ok := named.(NamedTagged); ok { | ||||
| 		if canonical, ok := named.(Canonical); ok { | ||||
| 			// The reference is both tagged and digested, only | ||||
| 			// return digested. | ||||
| 			newNamed, err := WithName(canonical.Name()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			newCanonical, err := WithDigest(newNamed, canonical.Digest()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			return newCanonical, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return TagNameOnly(named), nil | ||||
| } | ||||
|  | ||||
| // splitDockerDomain splits a repository name to domain and remotename string. | ||||
| // If no valid domain is found, the default domain is used. Repository name | ||||
| // needs to be already validated before. | ||||
| func splitDockerDomain(name string) (domain, remainder string) { | ||||
| 	i := strings.IndexRune(name, '/') | ||||
| 	if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { | ||||
| 		domain, remainder = defaultDomain, name | ||||
| 	} else { | ||||
| 		domain, remainder = name[:i], name[i+1:] | ||||
| 	} | ||||
| 	if domain == legacyDefaultDomain { | ||||
| 		domain = defaultDomain | ||||
| 	} | ||||
| 	if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { | ||||
| 		remainder = officialRepoName + "/" + remainder | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // familiarizeName returns a shortened version of the name familiar | ||||
| // to to the Docker UI. Familiar names have the default domain | ||||
| // "docker.io" and "library/" repository prefix removed. | ||||
| // For example, "docker.io/library/redis" will have the familiar | ||||
| // name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". | ||||
| // Returns a familiarized named only reference. | ||||
| func familiarizeName(named namedRepository) repository { | ||||
| 	repo := repository{ | ||||
| 		domain: named.Domain(), | ||||
| 		path:   named.Path(), | ||||
| 	} | ||||
|  | ||||
| 	if repo.domain == defaultDomain { | ||||
| 		repo.domain = "" | ||||
| 		// Handle official repositories which have the pattern "library/<official repo name>" | ||||
| 		if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { | ||||
| 			repo.path = split[1] | ||||
| 		} | ||||
| 	} | ||||
| 	return repo | ||||
| } | ||||
|  | ||||
| func (r reference) Familiar() Named { | ||||
| 	return reference{ | ||||
| 		namedRepository: familiarizeName(r.namedRepository), | ||||
| 		tag:             r.tag, | ||||
| 		digest:          r.digest, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r repository) Familiar() Named { | ||||
| 	return familiarizeName(r) | ||||
| } | ||||
|  | ||||
| func (t taggedReference) Familiar() Named { | ||||
| 	return taggedReference{ | ||||
| 		namedRepository: familiarizeName(t.namedRepository), | ||||
| 		tag:             t.tag, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c canonicalReference) Familiar() Named { | ||||
| 	return canonicalReference{ | ||||
| 		namedRepository: familiarizeName(c.namedRepository), | ||||
| 		digest:          c.digest, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TagNameOnly adds the default tag "latest" to a reference if it only has | ||||
| // a repo name. | ||||
| func TagNameOnly(ref Named) Named { | ||||
| 	if IsNameOnly(ref) { | ||||
| 		namedTagged, err := WithTag(ref, defaultTag) | ||||
| 		if err != nil { | ||||
| 			// Default tag must be valid, to create a NamedTagged | ||||
| 			// type with non-validated input the WithTag function | ||||
| 			// should be used instead | ||||
| 			panic(err) | ||||
| 		} | ||||
| 		return namedTagged | ||||
| 	} | ||||
| 	return ref | ||||
| } | ||||
|  | ||||
| // ParseAnyReference parses a reference string as a possible identifier, | ||||
| // full digest, or familiar name. | ||||
| func ParseAnyReference(ref string) (Reference, error) { | ||||
| 	if ok := anchoredIdentifierRegexp.MatchString(ref); ok { | ||||
| 		return digestReference("sha256:" + ref), nil | ||||
| 	} | ||||
| 	if dgst, err := digest.Parse(ref); err == nil { | ||||
| 		return digestReference(dgst), nil | ||||
| 	} | ||||
|  | ||||
| 	return ParseNormalizedNamed(ref) | ||||
| } | ||||
|  | ||||
| // IsNameOnly returns true if reference only contains a repo name. | ||||
| func IsNameOnly(ref Named) bool { | ||||
| 	if _, ok := ref.(NamedTagged); ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	if _, ok := ref.(Canonical); ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // FamiliarName returns the familiar name string | ||||
| // for the given named, familiarizing if needed. | ||||
| func FamiliarName(ref Named) string { | ||||
| 	if nn, ok := ref.(normalizedNamed); ok { | ||||
| 		return nn.Familiar().Name() | ||||
| 	} | ||||
| 	return ref.Name() | ||||
| } | ||||
|  | ||||
| // FamiliarString returns the familiar string representation | ||||
| // for the given reference, familiarizing if needed. | ||||
| func FamiliarString(ref Reference) string { | ||||
| 	if nn, ok := ref.(normalizedNamed); ok { | ||||
| 		return nn.Familiar().String() | ||||
| 	} | ||||
| 	return ref.String() | ||||
| } | ||||
|  | ||||
| // FamiliarMatch reports whether ref matches the specified pattern. | ||||
| // See https://godoc.org/path#Match for supported patterns. | ||||
| func FamiliarMatch(pattern string, ref Reference) (bool, error) { | ||||
| 	matched, err := path.Match(pattern, FamiliarString(ref)) | ||||
| 	if namedRef, isNamed := ref.(Named); isNamed && !matched { | ||||
| 		matched, _ = path.Match(pattern, FamiliarName(namedRef)) | ||||
| 	} | ||||
| 	return matched, err | ||||
| } | ||||
							
								
								
									
										305
									
								
								vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										305
									
								
								vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -40,126 +40,278 @@ type dockerAuthorizer struct { | ||||
| 	credentials func(string) (string, string, error) | ||||
|  | ||||
| 	client *http.Client | ||||
| 	header http.Header | ||||
| 	mu     sync.Mutex | ||||
|  | ||||
| 	auth map[string]string | ||||
| 	// indexed by host name | ||||
| 	handlers map[string]*authHandler | ||||
| } | ||||
|  | ||||
| // NewAuthorizer creates a Docker authorizer using the provided function to | ||||
| // get credentials for the token server or basic auth. | ||||
| // Deprecated: Use NewDockerAuthorizer | ||||
| func NewAuthorizer(client *http.Client, f func(string) (string, string, error)) Authorizer { | ||||
| 	if client == nil { | ||||
| 		client = http.DefaultClient | ||||
| 	} | ||||
| 	return &dockerAuthorizer{ | ||||
| 		credentials: f, | ||||
| 		client:      client, | ||||
| 		auth:        map[string]string{}, | ||||
| 	return NewDockerAuthorizer(WithAuthClient(client), WithAuthCreds(f)) | ||||
| } | ||||
|  | ||||
| type authorizerConfig struct { | ||||
| 	credentials func(string) (string, string, error) | ||||
| 	client      *http.Client | ||||
| 	header      http.Header | ||||
| } | ||||
|  | ||||
| // AuthorizerOpt configures an authorizer | ||||
| type AuthorizerOpt func(*authorizerConfig) | ||||
|  | ||||
| // WithAuthClient provides the HTTP client for the authorizer | ||||
| func WithAuthClient(client *http.Client) AuthorizerOpt { | ||||
| 	return func(opt *authorizerConfig) { | ||||
| 		opt.client = client | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Request) error { | ||||
| 	// TODO: Lookup matching challenge and scope rather than just host | ||||
| 	if auth := a.getAuth(req.URL.Host); auth != "" { | ||||
| 		req.Header.Set("Authorization", auth) | ||||
| // WithAuthCreds provides a credential function to the authorizer | ||||
| func WithAuthCreds(creds func(string) (string, string, error)) AuthorizerOpt { | ||||
| 	return func(opt *authorizerConfig) { | ||||
| 		opt.credentials = creds | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithAuthHeader provides HTTP headers for authorization | ||||
| func WithAuthHeader(hdr http.Header) AuthorizerOpt { | ||||
| 	return func(opt *authorizerConfig) { | ||||
| 		opt.header = hdr | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewDockerAuthorizer creates an authorizer using Docker's registry | ||||
| // authentication spec. | ||||
| // See https://docs.docker.com/registry/spec/auth/ | ||||
| func NewDockerAuthorizer(opts ...AuthorizerOpt) Authorizer { | ||||
| 	var ao authorizerConfig | ||||
| 	for _, opt := range opts { | ||||
| 		opt(&ao) | ||||
| 	} | ||||
|  | ||||
| 	if ao.client == nil { | ||||
| 		ao.client = http.DefaultClient | ||||
| 	} | ||||
|  | ||||
| 	return &dockerAuthorizer{ | ||||
| 		credentials: ao.credentials, | ||||
| 		client:      ao.client, | ||||
| 		header:      ao.header, | ||||
| 		handlers:    make(map[string]*authHandler), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Authorize handles auth request. | ||||
| func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Request) error { | ||||
| 	// skip if there is no auth handler | ||||
| 	ah := a.getAuthHandler(req.URL.Host) | ||||
| 	if ah == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	auth, err := ah.authorize(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("Authorization", auth) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) getAuthHandler(host string) *authHandler { | ||||
| 	a.mu.Lock() | ||||
| 	defer a.mu.Unlock() | ||||
|  | ||||
| 	return a.handlers[host] | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.Response) error { | ||||
| 	last := responses[len(responses)-1] | ||||
| 	host := last.Request.URL.Host | ||||
|  | ||||
| 	a.mu.Lock() | ||||
| 	defer a.mu.Unlock() | ||||
| 	for _, c := range parseAuthHeader(last.Header) { | ||||
| 		if c.scheme == bearerAuth { | ||||
| 			if err := invalidAuthorization(c, responses); err != nil { | ||||
| 				// TODO: Clear token | ||||
| 				a.setAuth(host, "") | ||||
| 				delete(a.handlers, host) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			// TODO(dmcg): Store challenge, not token | ||||
| 			// Move token fetching to authorize | ||||
| 			return a.setTokenAuth(ctx, host, c.parameters) | ||||
| 			// reuse existing handler | ||||
| 			// | ||||
| 			// assume that one registry will return the common | ||||
| 			// challenge information, including realm and service. | ||||
| 			// and the resource scope is only different part | ||||
| 			// which can be provided by each request. | ||||
| 			if _, ok := a.handlers[host]; ok { | ||||
| 				return nil | ||||
| 			} | ||||
|  | ||||
| 			common, err := a.generateTokenOptions(ctx, host, c) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			a.handlers[host] = newAuthHandler(a.client, a.header, c.scheme, common) | ||||
| 			return nil | ||||
| 		} else if c.scheme == basicAuth && a.credentials != nil { | ||||
| 			// TODO: Resolve credentials on authorize | ||||
| 			username, secret, err := a.credentials(host) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			if username != "" && secret != "" { | ||||
| 				auth := username + ":" + secret | ||||
| 				a.setAuth(host, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth)))) | ||||
| 				common := tokenOptions{ | ||||
| 					username: username, | ||||
| 					secret:   secret, | ||||
| 				} | ||||
|  | ||||
| 				a.handlers[host] = newAuthHandler(a.client, a.header, c.scheme, common) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return errors.Wrap(errdefs.ErrNotImplemented, "failed to find supported auth scheme") | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) getAuth(host string) string { | ||||
| 	a.mu.Lock() | ||||
| 	defer a.mu.Unlock() | ||||
|  | ||||
| 	return a.auth[host] | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) setAuth(host string, auth string) bool { | ||||
| 	a.mu.Lock() | ||||
| 	defer a.mu.Unlock() | ||||
|  | ||||
| 	changed := a.auth[host] != auth | ||||
| 	a.auth[host] = auth | ||||
|  | ||||
| 	return changed | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) setTokenAuth(ctx context.Context, host string, params map[string]string) error { | ||||
| 	realm, ok := params["realm"] | ||||
| func (a *dockerAuthorizer) generateTokenOptions(ctx context.Context, host string, c challenge) (tokenOptions, error) { | ||||
| 	realm, ok := c.parameters["realm"] | ||||
| 	if !ok { | ||||
| 		return errors.New("no realm specified for token auth challenge") | ||||
| 		return tokenOptions{}, errors.New("no realm specified for token auth challenge") | ||||
| 	} | ||||
|  | ||||
| 	realmURL, err := url.Parse(realm) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "invalid token auth challenge realm") | ||||
| 		return tokenOptions{}, errors.Wrap(err, "invalid token auth challenge realm") | ||||
| 	} | ||||
|  | ||||
| 	to := tokenOptions{ | ||||
| 		realm:   realmURL.String(), | ||||
| 		service: params["service"], | ||||
| 		service: c.parameters["service"], | ||||
| 	} | ||||
|  | ||||
| 	to.scopes = getTokenScopes(ctx, params) | ||||
| 	if len(to.scopes) == 0 { | ||||
| 		return errors.Errorf("no scope specified for token auth challenge") | ||||
| 	scope, ok := c.parameters["scope"] | ||||
| 	if !ok { | ||||
| 		return tokenOptions{}, errors.Errorf("no scope specified for token auth challenge") | ||||
| 	} | ||||
| 	to.scopes = append(to.scopes, scope) | ||||
|  | ||||
| 	if a.credentials != nil { | ||||
| 		to.username, to.secret, err = a.credentials(host) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 			return tokenOptions{}, err | ||||
| 		} | ||||
| 	} | ||||
| 	return to, nil | ||||
| } | ||||
|  | ||||
| 	var token string | ||||
| // authResult is used to control limit rate. | ||||
| type authResult struct { | ||||
| 	sync.WaitGroup | ||||
| 	token string | ||||
| 	err   error | ||||
| } | ||||
|  | ||||
| // authHandler is used to handle auth request per registry server. | ||||
| type authHandler struct { | ||||
| 	sync.Mutex | ||||
|  | ||||
| 	header http.Header | ||||
|  | ||||
| 	client *http.Client | ||||
|  | ||||
| 	// only support basic and bearer schemes | ||||
| 	scheme authenticationScheme | ||||
|  | ||||
| 	// common contains common challenge answer | ||||
| 	common tokenOptions | ||||
|  | ||||
| 	// scopedTokens caches token indexed by scopes, which used in | ||||
| 	// bearer auth case | ||||
| 	scopedTokens map[string]*authResult | ||||
| } | ||||
|  | ||||
| func newAuthHandler(client *http.Client, hdr http.Header, scheme authenticationScheme, opts tokenOptions) *authHandler { | ||||
| 	return &authHandler{ | ||||
| 		header:       hdr, | ||||
| 		client:       client, | ||||
| 		scheme:       scheme, | ||||
| 		common:       opts, | ||||
| 		scopedTokens: map[string]*authResult{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ah *authHandler) authorize(ctx context.Context) (string, error) { | ||||
| 	switch ah.scheme { | ||||
| 	case basicAuth: | ||||
| 		return ah.doBasicAuth(ctx) | ||||
| 	case bearerAuth: | ||||
| 		return ah.doBearerAuth(ctx) | ||||
| 	default: | ||||
| 		return "", errors.Wrap(errdefs.ErrNotImplemented, "failed to find supported auth scheme") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) { | ||||
| 	username, secret := ah.common.username, ah.common.secret | ||||
|  | ||||
| 	if username == "" || secret == "" { | ||||
| 		return "", fmt.Errorf("failed to handle basic auth because missing username or secret") | ||||
| 	} | ||||
|  | ||||
| 	auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + secret)) | ||||
| 	return fmt.Sprintf("Basic %s", auth), nil | ||||
| } | ||||
|  | ||||
| func (ah *authHandler) doBearerAuth(ctx context.Context) (string, error) { | ||||
| 	// copy common tokenOptions | ||||
| 	to := ah.common | ||||
|  | ||||
| 	to.scopes = getTokenScopes(ctx, to.scopes) | ||||
| 	if len(to.scopes) == 0 { | ||||
| 		return "", errors.Errorf("no scope specified for token auth challenge") | ||||
| 	} | ||||
|  | ||||
| 	// Docs: https://docs.docker.com/registry/spec/auth/scope | ||||
| 	scoped := strings.Join(to.scopes, " ") | ||||
|  | ||||
| 	ah.Lock() | ||||
| 	if r, exist := ah.scopedTokens[scoped]; exist { | ||||
| 		ah.Unlock() | ||||
| 		r.Wait() | ||||
| 		return r.token, r.err | ||||
| 	} | ||||
|  | ||||
| 	// only one fetch token job | ||||
| 	r := new(authResult) | ||||
| 	r.Add(1) | ||||
| 	ah.scopedTokens[scoped] = r | ||||
| 	ah.Unlock() | ||||
|  | ||||
| 	// fetch token for the resource scope | ||||
| 	var ( | ||||
| 		token string | ||||
| 		err   error | ||||
| 	) | ||||
| 	if to.secret != "" { | ||||
| 		// Credential information is provided, use oauth POST endpoint | ||||
| 		token, err = a.fetchTokenWithOAuth(ctx, to) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "failed to fetch oauth token") | ||||
| 		} | ||||
| 		// credential information is provided, use oauth POST endpoint | ||||
| 		token, err = ah.fetchTokenWithOAuth(ctx, to) | ||||
| 		err = errors.Wrap(err, "failed to fetch oauth token") | ||||
| 	} else { | ||||
| 		// Do request anonymously | ||||
| 		token, err = a.fetchToken(ctx, to) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "failed to fetch anonymous token") | ||||
| 		} | ||||
| 		// do request anonymously | ||||
| 		token, err = ah.fetchToken(ctx, to) | ||||
| 		err = errors.Wrap(err, "failed to fetch anonymous token") | ||||
| 	} | ||||
| 	a.setAuth(host, fmt.Sprintf("Bearer %s", token)) | ||||
| 	token = fmt.Sprintf("Bearer %s", token) | ||||
|  | ||||
| 	return nil | ||||
| 	r.token, r.err = token, err | ||||
| 	r.Done() | ||||
| 	return r.token, r.err | ||||
| } | ||||
|  | ||||
| type tokenOptions struct { | ||||
| @@ -178,7 +330,7 @@ type postTokenResponse struct { | ||||
| 	Scope        string    `json:"scope"` | ||||
| } | ||||
|  | ||||
| func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) (string, error) { | ||||
| func (ah *authHandler) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) (string, error) { | ||||
| 	form := url.Values{} | ||||
| 	form.Set("scope", strings.Join(to.scopes, " ")) | ||||
| 	form.Set("service", to.service) | ||||
| @@ -194,11 +346,18 @@ func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOpti | ||||
| 		form.Set("password", to.secret) | ||||
| 	} | ||||
|  | ||||
| 	resp, err := ctxhttp.Post( | ||||
| 		ctx, a.client, to.realm, | ||||
| 		"application/x-www-form-urlencoded; charset=utf-8", | ||||
| 		strings.NewReader(form.Encode()), | ||||
| 	) | ||||
| 	req, err := http.NewRequest("POST", to.realm, strings.NewReader(form.Encode())) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") | ||||
| 	if ah.header != nil { | ||||
| 		for k, v := range ah.header { | ||||
| 			req.Header[k] = append(req.Header[k], v...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	resp, err := ctxhttp.Do(ctx, ah.client, req) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| @@ -208,7 +367,7 @@ func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOpti | ||||
| 	// As of September 2017, GCR is known to return 404. | ||||
| 	// As of February 2018, JFrog Artifactory is known to return 401. | ||||
| 	if (resp.StatusCode == 405 && to.username != "") || resp.StatusCode == 404 || resp.StatusCode == 401 { | ||||
| 		return a.fetchToken(ctx, to) | ||||
| 		return ah.fetchToken(ctx, to) | ||||
| 	} else if resp.StatusCode < 200 || resp.StatusCode >= 400 { | ||||
| 		b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB | ||||
| 		log.G(ctx).WithFields(logrus.Fields{ | ||||
| @@ -237,13 +396,19 @@ type getTokenResponse struct { | ||||
| 	RefreshToken string    `json:"refresh_token"` | ||||
| } | ||||
|  | ||||
| // getToken fetches a token using a GET request | ||||
| func (a *dockerAuthorizer) fetchToken(ctx context.Context, to tokenOptions) (string, error) { | ||||
| // fetchToken fetches a token using a GET request | ||||
| func (ah *authHandler) fetchToken(ctx context.Context, to tokenOptions) (string, error) { | ||||
| 	req, err := http.NewRequest("GET", to.realm, nil) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if ah.header != nil { | ||||
| 		for k, v := range ah.header { | ||||
| 			req.Header[k] = append(req.Header[k], v...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	reqParams := req.URL.Query() | ||||
|  | ||||
| 	if to.service != "" { | ||||
| @@ -260,7 +425,7 @@ func (a *dockerAuthorizer) fetchToken(ctx context.Context, to tokenOptions) (str | ||||
|  | ||||
| 	req.URL.RawQuery = reqParams.Encode() | ||||
|  | ||||
| 	resp, err := ctxhttp.Do(ctx, a.client, req) | ||||
| 	resp, err := ctxhttp.Do(ctx, ah.client, req) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										283
									
								
								vendor/github.com/containerd/containerd/remotes/docker/errcode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								vendor/github.com/containerd/containerd/remotes/docker/errcode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package docker | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ErrorCoder is the base interface for ErrorCode and Error allowing | ||||
| // users of each to just call ErrorCode to get the real ID of each | ||||
| type ErrorCoder interface { | ||||
| 	ErrorCode() ErrorCode | ||||
| } | ||||
|  | ||||
| // ErrorCode represents the error type. The errors are serialized via strings | ||||
| // and the integer format may change and should *never* be exported. | ||||
| type ErrorCode int | ||||
|  | ||||
| var _ error = ErrorCode(0) | ||||
|  | ||||
| // ErrorCode just returns itself | ||||
| func (ec ErrorCode) ErrorCode() ErrorCode { | ||||
| 	return ec | ||||
| } | ||||
|  | ||||
| // Error returns the ID/Value | ||||
| func (ec ErrorCode) Error() string { | ||||
| 	// NOTE(stevvooe): Cannot use message here since it may have unpopulated args. | ||||
| 	return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1)) | ||||
| } | ||||
|  | ||||
| // Descriptor returns the descriptor for the error code. | ||||
| func (ec ErrorCode) Descriptor() ErrorDescriptor { | ||||
| 	d, ok := errorCodeToDescriptors[ec] | ||||
|  | ||||
| 	if !ok { | ||||
| 		return ErrorCodeUnknown.Descriptor() | ||||
| 	} | ||||
|  | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| // String returns the canonical identifier for this error code. | ||||
| func (ec ErrorCode) String() string { | ||||
| 	return ec.Descriptor().Value | ||||
| } | ||||
|  | ||||
| // Message returned the human-readable error message for this error code. | ||||
| func (ec ErrorCode) Message() string { | ||||
| 	return ec.Descriptor().Message | ||||
| } | ||||
|  | ||||
| // MarshalText encodes the receiver into UTF-8-encoded text and returns the | ||||
| // result. | ||||
| func (ec ErrorCode) MarshalText() (text []byte, err error) { | ||||
| 	return []byte(ec.String()), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalText decodes the form generated by MarshalText. | ||||
| func (ec *ErrorCode) UnmarshalText(text []byte) error { | ||||
| 	desc, ok := idToDescriptors[string(text)] | ||||
|  | ||||
| 	if !ok { | ||||
| 		desc = ErrorCodeUnknown.Descriptor() | ||||
| 	} | ||||
|  | ||||
| 	*ec = desc.Code | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // WithMessage creates a new Error struct based on the passed-in info and | ||||
| // overrides the Message property. | ||||
| func (ec ErrorCode) WithMessage(message string) Error { | ||||
| 	return Error{ | ||||
| 		Code:    ec, | ||||
| 		Message: message, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDetail creates a new Error struct based on the passed-in info and | ||||
| // set the Detail property appropriately | ||||
| func (ec ErrorCode) WithDetail(detail interface{}) Error { | ||||
| 	return Error{ | ||||
| 		Code:    ec, | ||||
| 		Message: ec.Message(), | ||||
| 	}.WithDetail(detail) | ||||
| } | ||||
|  | ||||
| // WithArgs creates a new Error struct and sets the Args slice | ||||
| func (ec ErrorCode) WithArgs(args ...interface{}) Error { | ||||
| 	return Error{ | ||||
| 		Code:    ec, | ||||
| 		Message: ec.Message(), | ||||
| 	}.WithArgs(args...) | ||||
| } | ||||
|  | ||||
| // Error provides a wrapper around ErrorCode with extra Details provided. | ||||
| type Error struct { | ||||
| 	Code    ErrorCode   `json:"code"` | ||||
| 	Message string      `json:"message"` | ||||
| 	Detail  interface{} `json:"detail,omitempty"` | ||||
|  | ||||
| 	// TODO(duglin): See if we need an "args" property so we can do the | ||||
| 	// variable substitution right before showing the message to the user | ||||
| } | ||||
|  | ||||
| var _ error = Error{} | ||||
|  | ||||
| // ErrorCode returns the ID/Value of this Error | ||||
| func (e Error) ErrorCode() ErrorCode { | ||||
| 	return e.Code | ||||
| } | ||||
|  | ||||
| // Error returns a human readable representation of the error. | ||||
| func (e Error) Error() string { | ||||
| 	return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message) | ||||
| } | ||||
|  | ||||
| // WithDetail will return a new Error, based on the current one, but with | ||||
| // some Detail info added | ||||
| func (e Error) WithDetail(detail interface{}) Error { | ||||
| 	return Error{ | ||||
| 		Code:    e.Code, | ||||
| 		Message: e.Message, | ||||
| 		Detail:  detail, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithArgs uses the passed-in list of interface{} as the substitution | ||||
| // variables in the Error's Message string, but returns a new Error | ||||
| func (e Error) WithArgs(args ...interface{}) Error { | ||||
| 	return Error{ | ||||
| 		Code:    e.Code, | ||||
| 		Message: fmt.Sprintf(e.Code.Message(), args...), | ||||
| 		Detail:  e.Detail, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ErrorDescriptor provides relevant information about a given error code. | ||||
| type ErrorDescriptor struct { | ||||
| 	// Code is the error code that this descriptor describes. | ||||
| 	Code ErrorCode | ||||
|  | ||||
| 	// Value provides a unique, string key, often captilized with | ||||
| 	// underscores, to identify the error code. This value is used as the | ||||
| 	// keyed value when serializing api errors. | ||||
| 	Value string | ||||
|  | ||||
| 	// Message is a short, human readable decription of the error condition | ||||
| 	// included in API responses. | ||||
| 	Message string | ||||
|  | ||||
| 	// Description provides a complete account of the errors purpose, suitable | ||||
| 	// for use in documentation. | ||||
| 	Description string | ||||
|  | ||||
| 	// HTTPStatusCode provides the http status code that is associated with | ||||
| 	// this error condition. | ||||
| 	HTTPStatusCode int | ||||
| } | ||||
|  | ||||
| // ParseErrorCode returns the value by the string error code. | ||||
| // `ErrorCodeUnknown` will be returned if the error is not known. | ||||
| func ParseErrorCode(value string) ErrorCode { | ||||
| 	ed, ok := idToDescriptors[value] | ||||
| 	if ok { | ||||
| 		return ed.Code | ||||
| 	} | ||||
|  | ||||
| 	return ErrorCodeUnknown | ||||
| } | ||||
|  | ||||
| // Errors provides the envelope for multiple errors and a few sugar methods | ||||
| // for use within the application. | ||||
| type Errors []error | ||||
|  | ||||
| var _ error = Errors{} | ||||
|  | ||||
| func (errs Errors) Error() string { | ||||
| 	switch len(errs) { | ||||
| 	case 0: | ||||
| 		return "<nil>" | ||||
| 	case 1: | ||||
| 		return errs[0].Error() | ||||
| 	default: | ||||
| 		msg := "errors:\n" | ||||
| 		for _, err := range errs { | ||||
| 			msg += err.Error() + "\n" | ||||
| 		} | ||||
| 		return msg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Len returns the current number of errors. | ||||
| func (errs Errors) Len() int { | ||||
| 	return len(errs) | ||||
| } | ||||
|  | ||||
| // MarshalJSON converts slice of error, ErrorCode or Error into a | ||||
| // slice of Error - then serializes | ||||
| func (errs Errors) MarshalJSON() ([]byte, error) { | ||||
| 	var tmpErrs struct { | ||||
| 		Errors []Error `json:"errors,omitempty"` | ||||
| 	} | ||||
|  | ||||
| 	for _, daErr := range errs { | ||||
| 		var err Error | ||||
|  | ||||
| 		switch daErr := daErr.(type) { | ||||
| 		case ErrorCode: | ||||
| 			err = daErr.WithDetail(nil) | ||||
| 		case Error: | ||||
| 			err = daErr | ||||
| 		default: | ||||
| 			err = ErrorCodeUnknown.WithDetail(daErr) | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		// If the Error struct was setup and they forgot to set the | ||||
| 		// Message field (meaning its "") then grab it from the ErrCode | ||||
| 		msg := err.Message | ||||
| 		if msg == "" { | ||||
| 			msg = err.Code.Message() | ||||
| 		} | ||||
|  | ||||
| 		tmpErrs.Errors = append(tmpErrs.Errors, Error{ | ||||
| 			Code:    err.Code, | ||||
| 			Message: msg, | ||||
| 			Detail:  err.Detail, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(tmpErrs) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON deserializes []Error and then converts it into slice of | ||||
| // Error or ErrorCode | ||||
| func (errs *Errors) UnmarshalJSON(data []byte) error { | ||||
| 	var tmpErrs struct { | ||||
| 		Errors []Error | ||||
| 	} | ||||
|  | ||||
| 	if err := json.Unmarshal(data, &tmpErrs); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var newErrs Errors | ||||
| 	for _, daErr := range tmpErrs.Errors { | ||||
| 		// If Message is empty or exactly matches the Code's message string | ||||
| 		// then just use the Code, no need for a full Error struct | ||||
| 		if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) { | ||||
| 			// Error's w/o details get converted to ErrorCode | ||||
| 			newErrs = append(newErrs, daErr.Code) | ||||
| 		} else { | ||||
| 			// Error's w/ details are untouched | ||||
| 			newErrs = append(newErrs, Error{ | ||||
| 				Code:    daErr.Code, | ||||
| 				Message: daErr.Message, | ||||
| 				Detail:  daErr.Detail, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	*errs = newErrs | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										154
									
								
								vendor/github.com/containerd/containerd/remotes/docker/errdesc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								vendor/github.com/containerd/containerd/remotes/docker/errdesc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package docker | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{} | ||||
| 	idToDescriptors        = map[string]ErrorDescriptor{} | ||||
| 	groupToDescriptors     = map[string][]ErrorDescriptor{} | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ErrorCodeUnknown is a generic error that can be used as a last | ||||
| 	// resort if there is no situation-specific error message that can be used | ||||
| 	ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:   "UNKNOWN", | ||||
| 		Message: "unknown error", | ||||
| 		Description: `Generic error returned when the error does not have an | ||||
| 			                                            API classification.`, | ||||
| 		HTTPStatusCode: http.StatusInternalServerError, | ||||
| 	}) | ||||
|  | ||||
| 	// ErrorCodeUnsupported is returned when an operation is not supported. | ||||
| 	ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:   "UNSUPPORTED", | ||||
| 		Message: "The operation is unsupported.", | ||||
| 		Description: `The operation was unsupported due to a missing | ||||
| 		implementation or invalid set of parameters.`, | ||||
| 		HTTPStatusCode: http.StatusMethodNotAllowed, | ||||
| 	}) | ||||
|  | ||||
| 	// ErrorCodeUnauthorized is returned if a request requires | ||||
| 	// authentication. | ||||
| 	ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:   "UNAUTHORIZED", | ||||
| 		Message: "authentication required", | ||||
| 		Description: `The access controller was unable to authenticate | ||||
| 		the client. Often this will be accompanied by a | ||||
| 		Www-Authenticate HTTP response header indicating how to | ||||
| 		authenticate.`, | ||||
| 		HTTPStatusCode: http.StatusUnauthorized, | ||||
| 	}) | ||||
|  | ||||
| 	// ErrorCodeDenied is returned if a client does not have sufficient | ||||
| 	// permission to perform an action. | ||||
| 	ErrorCodeDenied = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:   "DENIED", | ||||
| 		Message: "requested access to the resource is denied", | ||||
| 		Description: `The access controller denied access for the | ||||
| 		operation on a resource.`, | ||||
| 		HTTPStatusCode: http.StatusForbidden, | ||||
| 	}) | ||||
|  | ||||
| 	// ErrorCodeUnavailable provides a common error to report unavailability | ||||
| 	// of a service or endpoint. | ||||
| 	ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:          "UNAVAILABLE", | ||||
| 		Message:        "service unavailable", | ||||
| 		Description:    "Returned when a service is not available", | ||||
| 		HTTPStatusCode: http.StatusServiceUnavailable, | ||||
| 	}) | ||||
|  | ||||
| 	// ErrorCodeTooManyRequests is returned if a client attempts too many | ||||
| 	// times to contact a service endpoint. | ||||
| 	ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{ | ||||
| 		Value:   "TOOMANYREQUESTS", | ||||
| 		Message: "too many requests", | ||||
| 		Description: `Returned when a client attempts to contact a | ||||
| 		service too many times`, | ||||
| 		HTTPStatusCode: http.StatusTooManyRequests, | ||||
| 	}) | ||||
| ) | ||||
|  | ||||
| var nextCode = 1000 | ||||
| var registerLock sync.Mutex | ||||
|  | ||||
| // Register will make the passed-in error known to the environment and | ||||
| // return a new ErrorCode | ||||
| func Register(group string, descriptor ErrorDescriptor) ErrorCode { | ||||
| 	registerLock.Lock() | ||||
| 	defer registerLock.Unlock() | ||||
|  | ||||
| 	descriptor.Code = ErrorCode(nextCode) | ||||
|  | ||||
| 	if _, ok := idToDescriptors[descriptor.Value]; ok { | ||||
| 		panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value)) | ||||
| 	} | ||||
| 	if _, ok := errorCodeToDescriptors[descriptor.Code]; ok { | ||||
| 		panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code)) | ||||
| 	} | ||||
|  | ||||
| 	groupToDescriptors[group] = append(groupToDescriptors[group], descriptor) | ||||
| 	errorCodeToDescriptors[descriptor.Code] = descriptor | ||||
| 	idToDescriptors[descriptor.Value] = descriptor | ||||
|  | ||||
| 	nextCode++ | ||||
| 	return descriptor.Code | ||||
| } | ||||
|  | ||||
| type byValue []ErrorDescriptor | ||||
|  | ||||
| func (a byValue) Len() int           { return len(a) } | ||||
| func (a byValue) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||
| func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value } | ||||
|  | ||||
| // GetGroupNames returns the list of Error group names that are registered | ||||
| func GetGroupNames() []string { | ||||
| 	keys := []string{} | ||||
|  | ||||
| 	for k := range groupToDescriptors { | ||||
| 		keys = append(keys, k) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 	return keys | ||||
| } | ||||
|  | ||||
| // GetErrorCodeGroup returns the named group of error descriptors | ||||
| func GetErrorCodeGroup(name string) []ErrorDescriptor { | ||||
| 	desc := groupToDescriptors[name] | ||||
| 	sort.Sort(byValue(desc)) | ||||
| 	return desc | ||||
| } | ||||
|  | ||||
| // GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are | ||||
| // registered, irrespective of what group they're in | ||||
| func GetErrorAllDescriptors() []ErrorDescriptor { | ||||
| 	result := []ErrorDescriptor{} | ||||
|  | ||||
| 	for _, group := range GetGroupNames() { | ||||
| 		result = append(result, GetErrorCodeGroup(group)...) | ||||
| 	} | ||||
| 	sort.Sort(byValue(result)) | ||||
| 	return result | ||||
| } | ||||
							
								
								
									
										134
									
								
								vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										134
									
								
								vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,16 +23,14 @@ import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/containerd/containerd/errdefs" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/log" | ||||
| 	"github.com/docker/distribution/registry/api/errcode" | ||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| type dockerFetcher struct { | ||||
| @@ -40,26 +38,46 @@ type dockerFetcher struct { | ||||
| } | ||||
|  | ||||
| func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { | ||||
| 	ctx = log.WithLogger(ctx, log.G(ctx).WithFields( | ||||
| 		logrus.Fields{ | ||||
| 			"base":   r.base.String(), | ||||
| 			"digest": desc.Digest, | ||||
| 		}, | ||||
| 	)) | ||||
| 	ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest)) | ||||
|  | ||||
| 	urls, err := r.getV2URLPaths(ctx, desc) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	hosts := r.filterHosts(HostCapabilityPull) | ||||
| 	if len(hosts) == 0 { | ||||
| 		return nil, errors.Wrap(errdefs.ErrNotFound, "no pull hosts") | ||||
| 	} | ||||
|  | ||||
| 	ctx, err = contextWithRepositoryScope(ctx, r.refspec, false) | ||||
| 	ctx, err := contextWithRepositoryScope(ctx, r.refspec, false) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) { | ||||
| 		for _, u := range urls { | ||||
| 			rc, err := r.open(ctx, u, desc.MediaType, offset) | ||||
| 		// firstly try fetch via external urls | ||||
| 		for _, us := range desc.URLs { | ||||
| 			ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", us)) | ||||
|  | ||||
| 			u, err := url.Parse(us) | ||||
| 			if err != nil { | ||||
| 				log.G(ctx).WithError(err).Debug("failed to parse") | ||||
| 				continue | ||||
| 			} | ||||
| 			log.G(ctx).Debug("trying alternative url") | ||||
|  | ||||
| 			// Try this first, parse it | ||||
| 			host := RegistryHost{ | ||||
| 				Client:       http.DefaultClient, | ||||
| 				Host:         u.Host, | ||||
| 				Scheme:       u.Scheme, | ||||
| 				Path:         u.Path, | ||||
| 				Capabilities: HostCapabilityPull, | ||||
| 			} | ||||
| 			req := r.request(host, http.MethodGet) | ||||
| 			// Strip namespace from base | ||||
| 			req.path = u.Path | ||||
| 			if u.RawQuery != "" { | ||||
| 				req.path = req.path + "?" + u.RawQuery | ||||
| 			} | ||||
|  | ||||
| 			rc, err := r.open(ctx, req, desc.MediaType, offset) | ||||
| 			if err != nil { | ||||
| 				if errdefs.IsNotFound(err) { | ||||
| 					continue // try one of the other urls. | ||||
| @@ -71,6 +89,44 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R | ||||
| 			return rc, nil | ||||
| 		} | ||||
|  | ||||
| 		// Try manifests endpoints for manifests types | ||||
| 		switch desc.MediaType { | ||||
| 		case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, | ||||
| 			images.MediaTypeDockerSchema1Manifest, | ||||
| 			ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: | ||||
|  | ||||
| 			for _, host := range r.hosts { | ||||
| 				req := r.request(host, http.MethodGet, "manifests", desc.Digest.String()) | ||||
|  | ||||
| 				rc, err := r.open(ctx, req, desc.MediaType, offset) | ||||
| 				if err != nil { | ||||
| 					if errdefs.IsNotFound(err) { | ||||
| 						continue // try another host | ||||
| 					} | ||||
|  | ||||
| 					return nil, err | ||||
| 				} | ||||
|  | ||||
| 				return rc, nil | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Finally use blobs endpoints | ||||
| 		for _, host := range r.hosts { | ||||
| 			req := r.request(host, http.MethodGet, "blobs", desc.Digest.String()) | ||||
|  | ||||
| 			rc, err := r.open(ctx, req, desc.MediaType, offset) | ||||
| 			if err != nil { | ||||
| 				if errdefs.IsNotFound(err) { | ||||
| 					continue // try another host | ||||
| 				} | ||||
|  | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			return rc, nil | ||||
| 		} | ||||
|  | ||||
| 		return nil, errors.Wrapf(errdefs.ErrNotFound, | ||||
| 			"could not fetch content descriptor %v (%v) from remote", | ||||
| 			desc.Digest, desc.MediaType) | ||||
| @@ -78,22 +134,17 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (r dockerFetcher) open(ctx context.Context, u, mediatype string, offset int64) (io.ReadCloser, error) { | ||||
| 	req, err := http.NewRequest(http.MethodGet, u, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("Accept", strings.Join([]string{mediatype, `*`}, ", ")) | ||||
| func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (io.ReadCloser, error) { | ||||
| 	req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", ")) | ||||
|  | ||||
| 	if offset > 0 { | ||||
| 		// Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints | ||||
| 		// will return the header without supporting the range. The content | ||||
| 		// range must always be checked. | ||||
| 		req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) | ||||
| 		req.header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) | ||||
| 	} | ||||
|  | ||||
| 	resp, err := r.doRequestWithRetries(ctx, req, nil) | ||||
| 	resp, err := req.doWithRetries(ctx, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -106,13 +157,13 @@ func (r dockerFetcher) open(ctx context.Context, u, mediatype string, offset int | ||||
| 		defer resp.Body.Close() | ||||
|  | ||||
| 		if resp.StatusCode == http.StatusNotFound { | ||||
| 			return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", u) | ||||
| 			return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String()) | ||||
| 		} | ||||
| 		var registryErr errcode.Errors | ||||
| 		var registryErr Errors | ||||
| 		if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 { | ||||
| 			return nil, errors.Errorf("unexpected status code %v: %v", u, resp.Status) | ||||
| 			return nil, errors.Errorf("unexpected status code %v: %v", req.String(), resp.Status) | ||||
| 		} | ||||
| 		return nil, errors.Errorf("unexpected status code %v: %s - Server message: %s", u, resp.Status, registryErr.Error()) | ||||
| 		return nil, errors.Errorf("unexpected status code %v: %s - Server message: %s", req.String(), resp.Status, registryErr.Error()) | ||||
| 	} | ||||
| 	if offset > 0 { | ||||
| 		cr := resp.Header.Get("content-range") | ||||
| @@ -141,30 +192,3 @@ func (r dockerFetcher) open(ctx context.Context, u, mediatype string, offset int | ||||
|  | ||||
| 	return resp.Body, nil | ||||
| } | ||||
|  | ||||
| // getV2URLPaths generates the candidate urls paths for the object based on the | ||||
| // set of hints and the provided object id. URLs are returned in the order of | ||||
| // most to least likely succeed. | ||||
| func (r *dockerFetcher) getV2URLPaths(ctx context.Context, desc ocispec.Descriptor) ([]string, error) { | ||||
| 	var urls []string | ||||
|  | ||||
| 	if len(desc.URLs) > 0 { | ||||
| 		// handle fetch via external urls. | ||||
| 		for _, u := range desc.URLs { | ||||
| 			log.G(ctx).WithField("url", u).Debug("adding alternative url") | ||||
| 			urls = append(urls, u) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch desc.MediaType { | ||||
| 	case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, | ||||
| 		images.MediaTypeDockerSchema1Manifest, | ||||
| 		ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: | ||||
| 		urls = append(urls, r.url(path.Join("manifests", desc.Digest.String()))) | ||||
| 	} | ||||
|  | ||||
| 	// always fallback to attempting to get the object out of the blobs store. | ||||
| 	urls = append(urls, r.url(path.Join("blobs", desc.Digest.String()))) | ||||
|  | ||||
| 	return urls, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										42
									
								
								vendor/github.com/containerd/containerd/remotes/docker/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/containerd/containerd/remotes/docker/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -110,3 +110,45 @@ func appendDistributionSourceLabel(originLabel, repo string) string { | ||||
| func distributionSourceLabelKey(source string) string { | ||||
| 	return fmt.Sprintf("%s.%s", labelDistributionSource, source) | ||||
| } | ||||
|  | ||||
| // selectRepositoryMountCandidate will select the repo which has longest | ||||
| // common prefix components as the candidate. | ||||
| func selectRepositoryMountCandidate(refspec reference.Spec, sources map[string]string) string { | ||||
| 	u, err := url.Parse("dummy://" + refspec.Locator) | ||||
| 	if err != nil { | ||||
| 		// NOTE: basically, it won't be error here | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	source, target := u.Hostname(), strings.TrimPrefix(u.Path, "/") | ||||
| 	repoLabel, ok := sources[distributionSourceLabelKey(source)] | ||||
| 	if !ok || repoLabel == "" { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	n, match := 0, "" | ||||
| 	components := strings.Split(target, "/") | ||||
| 	for _, repo := range strings.Split(repoLabel, ",") { | ||||
| 		// the target repo is not a candidate | ||||
| 		if repo == target { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if l := commonPrefixComponents(components, repo); l >= n { | ||||
| 			n, match = l, repo | ||||
| 		} | ||||
| 	} | ||||
| 	return match | ||||
| } | ||||
|  | ||||
| func commonPrefixComponents(components []string, target string) int { | ||||
| 	targetComponents := strings.Split(target, "/") | ||||
|  | ||||
| 	i := 0 | ||||
| 	for ; i < len(components) && i < len(targetComponents); i++ { | ||||
| 		if components[i] != targetComponents[i] { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return i | ||||
| } | ||||
|   | ||||
							
								
								
									
										191
									
								
								vendor/github.com/containerd/containerd/remotes/docker/pusher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/containerd/containerd/remotes/docker/pusher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"path" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| @@ -37,7 +37,7 @@ import ( | ||||
|  | ||||
| type dockerPusher struct { | ||||
| 	*dockerBase | ||||
| 	tag string | ||||
| 	object string | ||||
|  | ||||
| 	// TODO: namespace tracker | ||||
| 	tracker StatusTracker | ||||
| @@ -59,31 +59,32 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten | ||||
| 		return nil, errors.Wrap(err, "failed to get status") | ||||
| 	} | ||||
|  | ||||
| 	hosts := p.filterHosts(HostCapabilityPush) | ||||
| 	if len(hosts) == 0 { | ||||
| 		return nil, errors.Wrap(errdefs.ErrNotFound, "no push hosts") | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		isManifest bool | ||||
| 		existCheck string | ||||
| 		existCheck []string | ||||
| 		host       = hosts[0] | ||||
| 	) | ||||
|  | ||||
| 	switch desc.MediaType { | ||||
| 	case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, | ||||
| 		ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: | ||||
| 		isManifest = true | ||||
| 		if p.tag == "" { | ||||
| 			existCheck = path.Join("manifests", desc.Digest.String()) | ||||
| 		} else { | ||||
| 			existCheck = path.Join("manifests", p.tag) | ||||
| 		} | ||||
| 		existCheck = getManifestPath(p.object, desc.Digest) | ||||
| 	default: | ||||
| 		existCheck = path.Join("blobs", desc.Digest.String()) | ||||
| 		existCheck = []string{"blobs", desc.Digest.String()} | ||||
| 	} | ||||
|  | ||||
| 	req, err := http.NewRequest(http.MethodHead, p.url(existCheck), nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	req := p.request(host, http.MethodHead, existCheck...) | ||||
| 	req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", ")) | ||||
|  | ||||
| 	req.Header.Set("Accept", strings.Join([]string{desc.MediaType, `*`}, ", ")) | ||||
| 	resp, err := p.doRequestWithRetries(ctx, req, nil) | ||||
| 	log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to") | ||||
|  | ||||
| 	resp, err := req.doWithRetries(ctx, nil) | ||||
| 	if err != nil { | ||||
| 		if errors.Cause(err) != ErrInvalidAuthorization { | ||||
| 			return nil, err | ||||
| @@ -92,7 +93,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten | ||||
| 	} else { | ||||
| 		if resp.StatusCode == http.StatusOK { | ||||
| 			var exists bool | ||||
| 			if isManifest && p.tag != "" { | ||||
| 			if isManifest && existCheck[1] != desc.Digest.String() { | ||||
| 				dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) | ||||
| 				if dgstHeader == desc.Digest { | ||||
| 					exists = true | ||||
| @@ -116,67 +117,94 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Lookup related objects for cross repository push | ||||
|  | ||||
| 	if isManifest { | ||||
| 		var putPath string | ||||
| 		if p.tag != "" { | ||||
| 			putPath = path.Join("manifests", p.tag) | ||||
| 		} else { | ||||
| 			putPath = path.Join("manifests", desc.Digest.String()) | ||||
| 		} | ||||
|  | ||||
| 		req, err = http.NewRequest(http.MethodPut, p.url(putPath), nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		req.Header.Add("Content-Type", desc.MediaType) | ||||
| 		putPath := getManifestPath(p.object, desc.Digest) | ||||
| 		req = p.request(host, http.MethodPut, putPath...) | ||||
| 		req.header.Add("Content-Type", desc.MediaType) | ||||
| 	} else { | ||||
| 		// TODO: Do monolithic upload if size is small | ||||
|  | ||||
| 		// Start upload request | ||||
| 		req, err = http.NewRequest(http.MethodPost, p.url("blobs", "uploads")+"/", nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		req = p.request(host, http.MethodPost, "blobs", "uploads/") | ||||
|  | ||||
| 		var resp *http.Response | ||||
| 		if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" { | ||||
| 			preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo) | ||||
| 			pctx := contextWithAppendPullRepositoryScope(ctx, fromRepo) | ||||
|  | ||||
| 			// NOTE: the fromRepo might be private repo and | ||||
| 			// auth service still can grant token without error. | ||||
| 			// but the post request will fail because of 401. | ||||
| 			// | ||||
| 			// for the private repo, we should remove mount-from | ||||
| 			// query and send the request again. | ||||
| 			resp, err = preq.do(pctx) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			if resp.StatusCode == http.StatusUnauthorized { | ||||
| 				log.G(ctx).Debugf("failed to mount from repository %s", fromRepo) | ||||
|  | ||||
| 				resp.Body.Close() | ||||
| 				resp = nil | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		resp, err := p.doRequestWithRetries(ctx, req, nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		if resp == nil { | ||||
| 			resp, err = req.doWithRetries(ctx, nil) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		switch resp.StatusCode { | ||||
| 		case http.StatusOK, http.StatusAccepted, http.StatusNoContent: | ||||
| 		case http.StatusCreated: | ||||
| 			p.tracker.SetStatus(ref, Status{ | ||||
| 				Status: content.Status{ | ||||
| 					Ref: ref, | ||||
| 				}, | ||||
| 			}) | ||||
| 			return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) | ||||
| 		default: | ||||
| 			// TODO: log error | ||||
| 			return nil, errors.Errorf("unexpected response: %s", resp.Status) | ||||
| 		} | ||||
|  | ||||
| 		location := resp.Header.Get("Location") | ||||
| 		var ( | ||||
| 			location = resp.Header.Get("Location") | ||||
| 			lurl     *url.URL | ||||
| 			lhost    = host | ||||
| 		) | ||||
| 		// Support paths without host in location | ||||
| 		if strings.HasPrefix(location, "/") { | ||||
| 			// Support location string containing path and query | ||||
| 			qmIndex := strings.Index(location, "?") | ||||
| 			if qmIndex > 0 { | ||||
| 				u := p.base | ||||
| 				u.Path = location[:qmIndex] | ||||
| 				u.RawQuery = location[qmIndex+1:] | ||||
| 				location = u.String() | ||||
| 			} else { | ||||
| 				u := p.base | ||||
| 				u.Path = location | ||||
| 				location = u.String() | ||||
| 			lurl, err = url.Parse(lhost.Scheme + "://" + lhost.Host + location) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(err, "unable to parse location %v", location) | ||||
| 			} | ||||
| 		} else { | ||||
| 			if !strings.Contains(location, "://") { | ||||
| 				location = lhost.Scheme + "://" + location | ||||
| 			} | ||||
| 			lurl, err = url.Parse(location) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(err, "unable to parse location %v", location) | ||||
| 			} | ||||
|  | ||||
| 			if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme { | ||||
|  | ||||
| 				lhost.Scheme = lurl.Scheme | ||||
| 				lhost.Host = lurl.Host | ||||
| 				log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination") | ||||
|  | ||||
| 				// Strip authorizer if change to host or scheme | ||||
| 				lhost.Authorizer = nil | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		req, err = http.NewRequest(http.MethodPut, location, nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		q := req.URL.Query() | ||||
| 		q := lurl.Query() | ||||
| 		q.Add("digest", desc.Digest.String()) | ||||
| 		req.URL.RawQuery = q.Encode() | ||||
|  | ||||
| 		req = p.request(lhost, http.MethodPut) | ||||
| 		req.path = lurl.Path + "?" + q.Encode() | ||||
| 	} | ||||
| 	p.tracker.SetStatus(ref, Status{ | ||||
| 		Status: content.Status{ | ||||
| @@ -191,13 +219,22 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten | ||||
|  | ||||
| 	pr, pw := io.Pipe() | ||||
| 	respC := make(chan *http.Response, 1) | ||||
| 	body := ioutil.NopCloser(pr) | ||||
|  | ||||
| 	req.Body = ioutil.NopCloser(pr) | ||||
| 	req.ContentLength = desc.Size | ||||
| 	req.body = func() (io.ReadCloser, error) { | ||||
| 		if body == nil { | ||||
| 			return nil, errors.New("cannot reuse body, request must be retried") | ||||
| 		} | ||||
| 		// Only use the body once since pipe cannot be seeked | ||||
| 		ob := body | ||||
| 		body = nil | ||||
| 		return ob, nil | ||||
| 	} | ||||
| 	req.size = desc.Size | ||||
|  | ||||
| 	go func() { | ||||
| 		defer close(respC) | ||||
| 		resp, err = p.doRequest(ctx, req) | ||||
| 		resp, err = req.do(ctx) | ||||
| 		if err != nil { | ||||
| 			pr.CloseWithError(err) | ||||
| 			return | ||||
| @@ -223,6 +260,25 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func getManifestPath(object string, dgst digest.Digest) []string { | ||||
| 	if i := strings.IndexByte(object, '@'); i >= 0 { | ||||
| 		if object[i+1:] != dgst.String() { | ||||
| 			// use digest, not tag | ||||
| 			object = "" | ||||
| 		} else { | ||||
| 			// strip @<digest> for registry path to make tag | ||||
| 			object = object[:i] | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	if object == "" { | ||||
| 		return []string{"manifests", dgst.String()} | ||||
| 	} | ||||
|  | ||||
| 	return []string{"manifests", object} | ||||
| } | ||||
|  | ||||
| type pushWriter struct { | ||||
| 	base *dockerBase | ||||
| 	ref  string | ||||
| @@ -296,7 +352,7 @@ func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Di | ||||
| 	} | ||||
|  | ||||
| 	if size > 0 && size != status.Offset { | ||||
| 		return errors.Errorf("unxpected size %d, expected %d", status.Offset, size) | ||||
| 		return errors.Errorf("unexpected size %d, expected %d", status.Offset, size) | ||||
| 	} | ||||
|  | ||||
| 	if expected == "" { | ||||
| @@ -320,3 +376,16 @@ func (pw *pushWriter) Truncate(size int64) error { | ||||
| 	// TODO: always error on manifest | ||||
| 	return errors.New("cannot truncate remote upload") | ||||
| } | ||||
|  | ||||
| func requestWithMountFrom(req *request, mount, from string) *request { | ||||
| 	creq := *req | ||||
|  | ||||
| 	sep := "?" | ||||
| 	if strings.Contains(creq.path, sep) { | ||||
| 		sep = "&" | ||||
| 	} | ||||
|  | ||||
| 	creq.path = creq.path + sep + "mount=" + mount + "&from=" + from | ||||
|  | ||||
| 	return &creq | ||||
| } | ||||
|   | ||||
							
								
								
									
										202
									
								
								vendor/github.com/containerd/containerd/remotes/docker/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/containerd/containerd/remotes/docker/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package docker | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // HostCapabilities represent the capabilities of the registry | ||||
| // host. This also represents the set of operations for which | ||||
| // the registry host may be trusted to perform. | ||||
| // | ||||
| // For example pushing is a capability which should only be | ||||
| // performed on an upstream source, not a mirror. | ||||
| // Resolving (the process of converting a name into a digest) | ||||
| // must be considered a trusted operation and only done by | ||||
| // a host which is trusted (or more preferably by secure process | ||||
| // which can prove the provenance of the mapping). A public | ||||
| // mirror should never be trusted to do a resolve action. | ||||
| // | ||||
| // | Registry Type    | Pull | Resolve | Push | | ||||
| // |------------------|------|---------|------| | ||||
| // | Public Registry  | yes  | yes     | yes  | | ||||
| // | Private Registry | yes  | yes     | yes  | | ||||
| // | Public Mirror    | yes  | no      | no   | | ||||
| // | Private Mirror   | yes  | yes     | no   | | ||||
| type HostCapabilities uint8 | ||||
|  | ||||
| const ( | ||||
| 	// HostCapabilityPull represents the capability to fetch manifests | ||||
| 	// and blobs by digest | ||||
| 	HostCapabilityPull HostCapabilities = 1 << iota | ||||
|  | ||||
| 	// HostCapabilityResolve represents the capability to fetch manifests | ||||
| 	// by name | ||||
| 	HostCapabilityResolve | ||||
|  | ||||
| 	// HostCapabilityPush represents the capability to push blobs and | ||||
| 	// manifests | ||||
| 	HostCapabilityPush | ||||
|  | ||||
| 	// Reserved for future capabilities (i.e. search, catalog, remove) | ||||
| ) | ||||
|  | ||||
| func (c HostCapabilities) Has(t HostCapabilities) bool { | ||||
| 	return c&t == t | ||||
| } | ||||
|  | ||||
| // RegistryHost represents a complete configuration for a registry | ||||
| // host, representing the capabilities, authorizations, connection | ||||
| // configuration, and location. | ||||
| type RegistryHost struct { | ||||
| 	Client       *http.Client | ||||
| 	Authorizer   Authorizer | ||||
| 	Host         string | ||||
| 	Scheme       string | ||||
| 	Path         string | ||||
| 	Capabilities HostCapabilities | ||||
| } | ||||
|  | ||||
| // RegistryHosts fetches the registry hosts for a given namespace, | ||||
| // provided by the host component of an distribution image reference. | ||||
| type RegistryHosts func(string) ([]RegistryHost, error) | ||||
|  | ||||
| // Registries joins multiple registry configuration functions, using the same | ||||
| // order as provided within the arguments. When an empty registry configuration | ||||
| // is returned with a nil error, the next function will be called. | ||||
| // NOTE: This function will not join configurations, as soon as a non-empty | ||||
| // configuration is returned from a configuration function, it will be returned | ||||
| // to the caller. | ||||
| func Registries(registries ...RegistryHosts) RegistryHosts { | ||||
| 	return func(host string) ([]RegistryHost, error) { | ||||
| 		for _, registry := range registries { | ||||
| 			config, err := registry(host) | ||||
| 			if err != nil { | ||||
| 				return config, err | ||||
| 			} | ||||
| 			if len(config) > 0 { | ||||
| 				return config, nil | ||||
| 			} | ||||
| 		} | ||||
| 		return nil, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type registryOpts struct { | ||||
| 	authorizer Authorizer | ||||
| 	plainHTTP  func(string) (bool, error) | ||||
| 	host       func(string) (string, error) | ||||
| 	client     *http.Client | ||||
| } | ||||
|  | ||||
| // RegistryOpt defines a registry default option | ||||
| type RegistryOpt func(*registryOpts) | ||||
|  | ||||
| // WithPlainHTTP configures registries to use plaintext http scheme | ||||
| // for the provided host match function. | ||||
| func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { | ||||
| 	return func(opts *registryOpts) { | ||||
| 		opts.plainHTTP = f | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithAuthorizer configures the default authorizer for a registry | ||||
| func WithAuthorizer(a Authorizer) RegistryOpt { | ||||
| 	return func(opts *registryOpts) { | ||||
| 		opts.authorizer = a | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithHostTranslator defines the default translator to use for registry hosts | ||||
| func WithHostTranslator(h func(string) (string, error)) RegistryOpt { | ||||
| 	return func(opts *registryOpts) { | ||||
| 		opts.host = h | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithClient configures the default http client for a registry | ||||
| func WithClient(c *http.Client) RegistryOpt { | ||||
| 	return func(opts *registryOpts) { | ||||
| 		opts.client = c | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ConfigureDefaultRegistries is used to create a default configuration for | ||||
| // registries. For more advanced configurations or per-domain setups, | ||||
| // the RegistryHosts interface should be used directly. | ||||
| // NOTE: This function will always return a non-empty value or error | ||||
| func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { | ||||
| 	var opts registryOpts | ||||
| 	for _, opt := range ropts { | ||||
| 		opt(&opts) | ||||
| 	} | ||||
|  | ||||
| 	return func(host string) ([]RegistryHost, error) { | ||||
| 		config := RegistryHost{ | ||||
| 			Client:       opts.client, | ||||
| 			Authorizer:   opts.authorizer, | ||||
| 			Host:         host, | ||||
| 			Scheme:       "https", | ||||
| 			Path:         "/v2", | ||||
| 			Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, | ||||
| 		} | ||||
|  | ||||
| 		if config.Client == nil { | ||||
| 			config.Client = http.DefaultClient | ||||
| 		} | ||||
|  | ||||
| 		if opts.plainHTTP != nil { | ||||
| 			match, err := opts.plainHTTP(host) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if match { | ||||
| 				config.Scheme = "http" | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if opts.host != nil { | ||||
| 			var err error | ||||
| 			config.Host, err = opts.host(config.Host) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} else if host == "docker.io" { | ||||
| 			config.Host = "registry-1.docker.io" | ||||
| 		} | ||||
|  | ||||
| 		return []RegistryHost{config}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MatchAllHosts is a host match function which is always true. | ||||
| func MatchAllHosts(string) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| // MatchLocalhost is a host match function which returns true for | ||||
| // localhost. | ||||
| func MatchLocalhost(host string) (bool, error) { | ||||
| 	for _, s := range []string{"localhost", "127.0.0.1", "[::1]"} { | ||||
| 		if len(host) >= len(s) && host[0:len(s)] == s && (len(host) == len(s) || host[len(s)] == ':') { | ||||
| 			return true, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return host == "::1", nil | ||||
|  | ||||
| } | ||||
							
								
								
									
										532
									
								
								vendor/github.com/containerd/containerd/remotes/docker/resolver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										532
									
								
								vendor/github.com/containerd/containerd/remotes/docker/resolver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,9 +18,10 @@ package docker | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"path" | ||||
| 	"strings" | ||||
|  | ||||
| @@ -46,6 +47,19 @@ var ( | ||||
| 	// ErrInvalidAuthorization is used when credentials are passed to a server but | ||||
| 	// those credentials are rejected. | ||||
| 	ErrInvalidAuthorization = errors.New("authorization failed") | ||||
|  | ||||
| 	// MaxManifestSize represents the largest size accepted from a registry | ||||
| 	// during resolution. Larger manifests may be accepted using a | ||||
| 	// resolution method other than the registry. | ||||
| 	// | ||||
| 	// NOTE: The max supported layers by some runtimes is 128 and individual | ||||
| 	// layers will not contribute more than 256 bytes, making a | ||||
| 	// reasonable limit for a large image manifests of 32K bytes. | ||||
| 	// 4M bytes represents a much larger upper bound for images which may | ||||
| 	// contain large annotations or be non-images. A proper manifest | ||||
| 	// design puts large metadata in subobjects, as is consistent the | ||||
| 	// intent of the manifest design. | ||||
| 	MaxManifestSize int64 = 4 * 1048 * 1048 | ||||
| ) | ||||
|  | ||||
| // Authorizer is used to authorize HTTP requests based on 401 HTTP responses. | ||||
| @@ -72,31 +86,38 @@ type Authorizer interface { | ||||
|  | ||||
| // ResolverOptions are used to configured a new Docker register resolver | ||||
| type ResolverOptions struct { | ||||
| 	// Authorizer is used to authorize registry requests | ||||
| 	Authorizer Authorizer | ||||
|  | ||||
| 	// Credentials provides username and secret given a host. | ||||
| 	// If username is empty but a secret is given, that secret | ||||
| 	// is interpreted as a long lived token. | ||||
| 	// Deprecated: use Authorizer | ||||
| 	Credentials func(string) (string, string, error) | ||||
|  | ||||
| 	// Host provides the hostname given a namespace. | ||||
| 	Host func(string) (string, error) | ||||
| 	// Hosts returns registry host configurations for a namespace. | ||||
| 	Hosts RegistryHosts | ||||
|  | ||||
| 	// Headers are the HTTP request header fields sent by the resolver | ||||
| 	Headers http.Header | ||||
|  | ||||
| 	// PlainHTTP specifies to use plain http and not https | ||||
| 	PlainHTTP bool | ||||
|  | ||||
| 	// Client is the http client to used when making registry requests | ||||
| 	Client *http.Client | ||||
|  | ||||
| 	// Tracker is used to track uploads to the registry. This is used | ||||
| 	// since the registry does not have upload tracking and the existing | ||||
| 	// mechanism for getting blob upload status is expensive. | ||||
| 	Tracker StatusTracker | ||||
|  | ||||
| 	// Authorizer is used to authorize registry requests | ||||
| 	// Deprecated: use Hosts | ||||
| 	Authorizer Authorizer | ||||
|  | ||||
| 	// Credentials provides username and secret given a host. | ||||
| 	// If username is empty but a secret is given, that secret | ||||
| 	// is interpreted as a long lived token. | ||||
| 	// Deprecated: use Hosts | ||||
| 	Credentials func(string) (string, string, error) | ||||
|  | ||||
| 	// Host provides the hostname given a namespace. | ||||
| 	// Deprecated: use Hosts | ||||
| 	Host func(string) (string, error) | ||||
|  | ||||
| 	// PlainHTTP specifies to use plain http and not https | ||||
| 	// Deprecated: use Hosts | ||||
| 	PlainHTTP bool | ||||
|  | ||||
| 	// Client is the http client to used when making registry requests | ||||
| 	// Deprecated: use Hosts | ||||
| 	Client *http.Client | ||||
| } | ||||
|  | ||||
| // DefaultHost is the default host function. | ||||
| @@ -108,12 +129,10 @@ func DefaultHost(ns string) (string, error) { | ||||
| } | ||||
|  | ||||
| type dockerResolver struct { | ||||
| 	auth      Authorizer | ||||
| 	host      func(string) (string, error) | ||||
| 	headers   http.Header | ||||
| 	plainHTTP bool | ||||
| 	client    *http.Client | ||||
| 	tracker   StatusTracker | ||||
| 	hosts         RegistryHosts | ||||
| 	header        http.Header | ||||
| 	resolveHeader http.Header | ||||
| 	tracker       StatusTracker | ||||
| } | ||||
|  | ||||
| // NewResolver returns a new resolver to a Docker registry | ||||
| @@ -121,33 +140,56 @@ func NewResolver(options ResolverOptions) remotes.Resolver { | ||||
| 	if options.Tracker == nil { | ||||
| 		options.Tracker = NewInMemoryTracker() | ||||
| 	} | ||||
| 	if options.Host == nil { | ||||
| 		options.Host = DefaultHost | ||||
| 	} | ||||
|  | ||||
| 	if options.Headers == nil { | ||||
| 		options.Headers = make(http.Header) | ||||
| 	} | ||||
| 	if _, ok := options.Headers["Accept"]; !ok { | ||||
| 		// set headers for all the types we support for resolution. | ||||
| 		options.Headers.Set("Accept", strings.Join([]string{ | ||||
| 			images.MediaTypeDockerSchema2Manifest, | ||||
| 			images.MediaTypeDockerSchema2ManifestList, | ||||
| 			ocispec.MediaTypeImageManifest, | ||||
| 			ocispec.MediaTypeImageIndex, "*"}, ", ")) | ||||
| 	} | ||||
| 	if _, ok := options.Headers["User-Agent"]; !ok { | ||||
| 		options.Headers.Set("User-Agent", "containerd/"+version.Version) | ||||
| 	} | ||||
| 	if options.Authorizer == nil { | ||||
| 		options.Authorizer = NewAuthorizer(options.Client, options.Credentials) | ||||
|  | ||||
| 	resolveHeader := http.Header{} | ||||
| 	if _, ok := options.Headers["Accept"]; !ok { | ||||
| 		// set headers for all the types we support for resolution. | ||||
| 		resolveHeader.Set("Accept", strings.Join([]string{ | ||||
| 			images.MediaTypeDockerSchema2Manifest, | ||||
| 			images.MediaTypeDockerSchema2ManifestList, | ||||
| 			ocispec.MediaTypeImageManifest, | ||||
| 			ocispec.MediaTypeImageIndex, "*/*"}, ", ")) | ||||
| 	} else { | ||||
| 		resolveHeader["Accept"] = options.Headers["Accept"] | ||||
| 		delete(options.Headers, "Accept") | ||||
| 	} | ||||
|  | ||||
| 	if options.Hosts == nil { | ||||
| 		opts := []RegistryOpt{} | ||||
| 		if options.Host != nil { | ||||
| 			opts = append(opts, WithHostTranslator(options.Host)) | ||||
| 		} | ||||
|  | ||||
| 		if options.Authorizer == nil { | ||||
| 			options.Authorizer = NewDockerAuthorizer( | ||||
| 				WithAuthClient(options.Client), | ||||
| 				WithAuthHeader(options.Headers), | ||||
| 				WithAuthCreds(options.Credentials)) | ||||
| 		} | ||||
| 		opts = append(opts, WithAuthorizer(options.Authorizer)) | ||||
|  | ||||
| 		if options.Client != nil { | ||||
| 			opts = append(opts, WithClient(options.Client)) | ||||
| 		} | ||||
| 		if options.PlainHTTP { | ||||
| 			opts = append(opts, WithPlainHTTP(MatchAllHosts)) | ||||
| 		} else { | ||||
| 			opts = append(opts, WithPlainHTTP(MatchLocalhost)) | ||||
| 		} | ||||
| 		options.Hosts = ConfigureDefaultRegistries(opts...) | ||||
| 	} | ||||
| 	return &dockerResolver{ | ||||
| 		auth:      options.Authorizer, | ||||
| 		host:      options.Host, | ||||
| 		headers:   options.Headers, | ||||
| 		plainHTTP: options.PlainHTTP, | ||||
| 		client:    options.Client, | ||||
| 		tracker:   options.Tracker, | ||||
| 		hosts:         options.Hosts, | ||||
| 		header:        options.Headers, | ||||
| 		resolveHeader: resolveHeader, | ||||
| 		tracker:       options.Tracker, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -194,13 +236,11 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp | ||||
| 		return "", ocispec.Descriptor{}, err | ||||
| 	} | ||||
|  | ||||
| 	fetcher := dockerFetcher{ | ||||
| 		dockerBase: base, | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		urls []string | ||||
| 		dgst = refspec.Digest() | ||||
| 		lastErr error | ||||
| 		paths   [][]string | ||||
| 		dgst    = refspec.Digest() | ||||
| 		caps    = HostCapabilityPull | ||||
| 	) | ||||
|  | ||||
| 	if dgst != "" { | ||||
| @@ -211,100 +251,130 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp | ||||
| 		} | ||||
|  | ||||
| 		// turns out, we have a valid digest, make a url. | ||||
| 		urls = append(urls, fetcher.url("manifests", dgst.String())) | ||||
| 		paths = append(paths, []string{"manifests", dgst.String()}) | ||||
|  | ||||
| 		// fallback to blobs on not found. | ||||
| 		urls = append(urls, fetcher.url("blobs", dgst.String())) | ||||
| 		paths = append(paths, []string{"blobs", dgst.String()}) | ||||
| 	} else { | ||||
| 		urls = append(urls, fetcher.url("manifests", refspec.Object)) | ||||
| 		// Add | ||||
| 		paths = append(paths, []string{"manifests", refspec.Object}) | ||||
| 		caps |= HostCapabilityResolve | ||||
| 	} | ||||
|  | ||||
| 	hosts := base.filterHosts(caps) | ||||
| 	if len(hosts) == 0 { | ||||
| 		return "", ocispec.Descriptor{}, errors.Wrap(errdefs.ErrNotFound, "no resolve hosts") | ||||
| 	} | ||||
|  | ||||
| 	ctx, err = contextWithRepositoryScope(ctx, refspec, false) | ||||
| 	if err != nil { | ||||
| 		return "", ocispec.Descriptor{}, err | ||||
| 	} | ||||
| 	for _, u := range urls { | ||||
| 		req, err := http.NewRequest(http.MethodHead, u, nil) | ||||
| 		if err != nil { | ||||
| 			return "", ocispec.Descriptor{}, err | ||||
| 		} | ||||
|  | ||||
| 		req.Header = r.headers | ||||
| 	for _, u := range paths { | ||||
| 		for _, host := range hosts { | ||||
| 			ctx := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host)) | ||||
|  | ||||
| 		log.G(ctx).Debug("resolving") | ||||
| 		resp, err := fetcher.doRequestWithRetries(ctx, req, nil) | ||||
| 		if err != nil { | ||||
| 			if errors.Cause(err) == ErrInvalidAuthorization { | ||||
| 				err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") | ||||
| 			req := base.request(host, http.MethodHead, u...) | ||||
| 			for key, value := range r.resolveHeader { | ||||
| 				req.header[key] = append(req.header[key], value...) | ||||
| 			} | ||||
| 			return "", ocispec.Descriptor{}, err | ||||
| 		} | ||||
| 		resp.Body.Close() // don't care about body contents. | ||||
|  | ||||
| 		if resp.StatusCode > 299 { | ||||
| 			if resp.StatusCode == http.StatusNotFound { | ||||
| 			log.G(ctx).Debug("resolving") | ||||
| 			resp, err := req.doWithRetries(ctx, nil) | ||||
| 			if err != nil { | ||||
| 				if errors.Cause(err) == ErrInvalidAuthorization { | ||||
| 					err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") | ||||
| 				} | ||||
| 				return "", ocispec.Descriptor{}, err | ||||
| 			} | ||||
| 			resp.Body.Close() // don't care about body contents. | ||||
|  | ||||
| 			if resp.StatusCode > 299 { | ||||
| 				if resp.StatusCode == http.StatusNotFound { | ||||
| 					continue | ||||
| 				} | ||||
| 				return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status) | ||||
| 			} | ||||
| 			size := resp.ContentLength | ||||
| 			contentType := getManifestMediaType(resp) | ||||
|  | ||||
| 			// if no digest was provided, then only a resolve | ||||
| 			// trusted registry was contacted, in this case use | ||||
| 			// the digest header (or content from GET) | ||||
| 			if dgst == "" { | ||||
| 				// this is the only point at which we trust the registry. we use the | ||||
| 				// content headers to assemble a descriptor for the name. when this becomes | ||||
| 				// more robust, we mostly get this information from a secure trust store. | ||||
| 				dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) | ||||
|  | ||||
| 				if dgstHeader != "" && size != -1 { | ||||
| 					if err := dgstHeader.Validate(); err != nil { | ||||
| 						return "", ocispec.Descriptor{}, errors.Wrapf(err, "%q in header not a valid digest", dgstHeader) | ||||
| 					} | ||||
| 					dgst = dgstHeader | ||||
| 				} | ||||
| 			} | ||||
| 			if dgst == "" || size == -1 { | ||||
| 				log.G(ctx).Debug("no Docker-Content-Digest header, fetching manifest instead") | ||||
|  | ||||
| 				req = base.request(host, http.MethodGet, u...) | ||||
| 				for key, value := range r.resolveHeader { | ||||
| 					req.header[key] = append(req.header[key], value...) | ||||
| 				} | ||||
|  | ||||
| 				resp, err := req.doWithRetries(ctx, nil) | ||||
| 				if err != nil { | ||||
| 					return "", ocispec.Descriptor{}, err | ||||
| 				} | ||||
| 				defer resp.Body.Close() | ||||
|  | ||||
| 				bodyReader := countingReader{reader: resp.Body} | ||||
|  | ||||
| 				contentType = getManifestMediaType(resp) | ||||
| 				if dgst == "" { | ||||
| 					if contentType == images.MediaTypeDockerSchema1Manifest { | ||||
| 						b, err := schema1.ReadStripSignature(&bodyReader) | ||||
| 						if err != nil { | ||||
| 							return "", ocispec.Descriptor{}, err | ||||
| 						} | ||||
|  | ||||
| 						dgst = digest.FromBytes(b) | ||||
| 					} else { | ||||
| 						dgst, err = digest.FromReader(&bodyReader) | ||||
| 						if err != nil { | ||||
| 							return "", ocispec.Descriptor{}, err | ||||
| 						} | ||||
| 					} | ||||
| 				} else if _, err := io.Copy(ioutil.Discard, &bodyReader); err != nil { | ||||
| 					return "", ocispec.Descriptor{}, err | ||||
| 				} | ||||
| 				size = bodyReader.bytesRead | ||||
| 			} | ||||
| 			// Prevent resolving to excessively large manifests | ||||
| 			if size > MaxManifestSize { | ||||
| 				if lastErr == nil { | ||||
| 					lastErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref) | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status) | ||||
|  | ||||
| 			desc := ocispec.Descriptor{ | ||||
| 				Digest:    dgst, | ||||
| 				MediaType: contentType, | ||||
| 				Size:      size, | ||||
| 			} | ||||
|  | ||||
| 			log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved") | ||||
| 			return ref, desc, nil | ||||
| 		} | ||||
| 		size := resp.ContentLength | ||||
|  | ||||
| 		// this is the only point at which we trust the registry. we use the | ||||
| 		// content headers to assemble a descriptor for the name. when this becomes | ||||
| 		// more robust, we mostly get this information from a secure trust store. | ||||
| 		dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) | ||||
| 		contentType := getManifestMediaType(resp) | ||||
|  | ||||
| 		if dgstHeader != "" && size != -1 { | ||||
| 			if err := dgstHeader.Validate(); err != nil { | ||||
| 				return "", ocispec.Descriptor{}, errors.Wrapf(err, "%q in header not a valid digest", dgstHeader) | ||||
| 			} | ||||
| 			dgst = dgstHeader | ||||
| 		} else { | ||||
| 			log.G(ctx).Debug("no Docker-Content-Digest header, fetching manifest instead") | ||||
|  | ||||
| 			req, err := http.NewRequest(http.MethodGet, u, nil) | ||||
| 			if err != nil { | ||||
| 				return "", ocispec.Descriptor{}, err | ||||
| 			} | ||||
| 			req.Header = r.headers | ||||
|  | ||||
| 			resp, err := fetcher.doRequestWithRetries(ctx, req, nil) | ||||
| 			if err != nil { | ||||
| 				return "", ocispec.Descriptor{}, err | ||||
| 			} | ||||
| 			defer resp.Body.Close() | ||||
|  | ||||
| 			bodyReader := countingReader{reader: resp.Body} | ||||
|  | ||||
| 			contentType = getManifestMediaType(resp) | ||||
| 			if contentType == images.MediaTypeDockerSchema1Manifest { | ||||
| 				b, err := schema1.ReadStripSignature(&bodyReader) | ||||
| 				if err != nil { | ||||
| 					return "", ocispec.Descriptor{}, err | ||||
| 				} | ||||
|  | ||||
| 				dgst = digest.FromBytes(b) | ||||
| 			} else { | ||||
| 				dgst, err = digest.FromReader(&bodyReader) | ||||
| 				if err != nil { | ||||
| 					return "", ocispec.Descriptor{}, err | ||||
| 				} | ||||
| 			} | ||||
| 			size = bodyReader.bytesRead | ||||
| 		} | ||||
|  | ||||
| 		desc := ocispec.Descriptor{ | ||||
| 			Digest:    dgst, | ||||
| 			MediaType: contentType, | ||||
| 			Size:      size, | ||||
| 		} | ||||
|  | ||||
| 		log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved") | ||||
| 		return ref, desc, nil | ||||
| 	} | ||||
|  | ||||
| 	return "", ocispec.Descriptor{}, errors.Errorf("%v not found", ref) | ||||
| 	if lastErr == nil { | ||||
| 		lastErr = errors.Wrap(errdefs.ErrNotFound, ref) | ||||
| 	} | ||||
|  | ||||
| 	return "", ocispec.Descriptor{}, lastErr | ||||
| } | ||||
|  | ||||
| func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { | ||||
| @@ -329,13 +399,6 @@ func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Manifests can be pushed by digest like any other object, but the passed in | ||||
| 	// reference cannot take a digest without the associated content. A tag is allowed | ||||
| 	// and will be used to tag pushed manifests. | ||||
| 	if refspec.Object != "" && strings.Contains(refspec.Object, "@") { | ||||
| 		return nil, errors.New("cannot use digest reference for push locator") | ||||
| 	} | ||||
|  | ||||
| 	base, err := r.base(refspec) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -343,60 +406,64 @@ func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher | ||||
|  | ||||
| 	return dockerPusher{ | ||||
| 		dockerBase: base, | ||||
| 		tag:        refspec.Object, | ||||
| 		object:     refspec.Object, | ||||
| 		tracker:    r.tracker, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type dockerBase struct { | ||||
| 	refspec reference.Spec | ||||
| 	base    url.URL | ||||
|  | ||||
| 	client *http.Client | ||||
| 	auth   Authorizer | ||||
| 	refspec   reference.Spec | ||||
| 	namespace string | ||||
| 	hosts     []RegistryHost | ||||
| 	header    http.Header | ||||
| } | ||||
|  | ||||
| func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) { | ||||
| 	var ( | ||||
| 		err  error | ||||
| 		base url.URL | ||||
| 	) | ||||
|  | ||||
| 	host := refspec.Hostname() | ||||
| 	base.Host = host | ||||
| 	if r.host != nil { | ||||
| 		base.Host, err = r.host(host) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	hosts, err := r.hosts(host) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	base.Scheme = "https" | ||||
| 	if r.plainHTTP || strings.HasPrefix(base.Host, "localhost:") { | ||||
| 		base.Scheme = "http" | ||||
| 	} | ||||
|  | ||||
| 	prefix := strings.TrimPrefix(refspec.Locator, host+"/") | ||||
| 	base.Path = path.Join("/v2", prefix) | ||||
|  | ||||
| 	return &dockerBase{ | ||||
| 		refspec: refspec, | ||||
| 		base:    base, | ||||
| 		client:  r.client, | ||||
| 		auth:    r.auth, | ||||
| 		refspec:   refspec, | ||||
| 		namespace: strings.TrimPrefix(refspec.Locator, host+"/"), | ||||
| 		hosts:     hosts, | ||||
| 		header:    r.header, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (r *dockerBase) url(ps ...string) string { | ||||
| 	url := r.base | ||||
| 	url.Path = path.Join(url.Path, path.Join(ps...)) | ||||
| 	return url.String() | ||||
| func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) { | ||||
| 	for _, host := range r.hosts { | ||||
| 		if host.Capabilities.Has(caps) { | ||||
| 			hosts = append(hosts, host) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *dockerBase) authorize(ctx context.Context, req *http.Request) error { | ||||
| func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request { | ||||
| 	header := http.Header{} | ||||
| 	for key, value := range r.header { | ||||
| 		header[key] = append(header[key], value...) | ||||
| 	} | ||||
| 	parts := append([]string{"/", host.Path, r.namespace}, ps...) | ||||
| 	p := path.Join(parts...) | ||||
| 	// Join strips trailing slash, re-add ending "/" if included | ||||
| 	if len(parts) > 0 && strings.HasSuffix(parts[len(parts)-1], "/") { | ||||
| 		p = p + "/" | ||||
| 	} | ||||
| 	return &request{ | ||||
| 		method: method, | ||||
| 		path:   p, | ||||
| 		header: header, | ||||
| 		host:   host, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *request) authorize(ctx context.Context, req *http.Request) error { | ||||
| 	// Check if has header for host | ||||
| 	if r.auth != nil { | ||||
| 		if err := r.auth.Authorize(ctx, req); err != nil { | ||||
| 	if r.host.Authorizer != nil { | ||||
| 		if err := r.host.Authorizer.Authorize(ctx, req); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| @@ -404,80 +471,137 @@ func (r *dockerBase) authorize(ctx context.Context, req *http.Request) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *dockerBase) doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { | ||||
| 	ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", req.URL.String())) | ||||
| 	log.G(ctx).WithField("request.headers", req.Header).WithField("request.method", req.Method).Debug("do request") | ||||
| type request struct { | ||||
| 	method string | ||||
| 	path   string | ||||
| 	header http.Header | ||||
| 	host   RegistryHost | ||||
| 	body   func() (io.ReadCloser, error) | ||||
| 	size   int64 | ||||
| } | ||||
|  | ||||
| func (r *request) do(ctx context.Context) (*http.Response, error) { | ||||
| 	u := r.host.Scheme + "://" + r.host.Host + r.path | ||||
| 	req, err := http.NewRequest(r.method, u, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	req.Header = r.header | ||||
| 	if r.body != nil { | ||||
| 		body, err := r.body() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		req.Body = body | ||||
| 		req.GetBody = r.body | ||||
| 		if r.size > 0 { | ||||
| 			req.ContentLength = r.size | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u)) | ||||
| 	log.G(ctx).WithFields(requestFields(req)).Debug("do request") | ||||
| 	if err := r.authorize(ctx, req); err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to authorize") | ||||
| 	} | ||||
| 	resp, err := ctxhttp.Do(ctx, r.client, req) | ||||
| 	resp, err := ctxhttp.Do(ctx, r.host.Client, req) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to do request") | ||||
| 	} | ||||
| 	log.G(ctx).WithFields(logrus.Fields{ | ||||
| 		"status":           resp.Status, | ||||
| 		"response.headers": resp.Header, | ||||
| 	}).Debug("fetch response received") | ||||
| 	log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received") | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| func (r *dockerBase) doRequestWithRetries(ctx context.Context, req *http.Request, responses []*http.Response) (*http.Response, error) { | ||||
| 	resp, err := r.doRequest(ctx, req) | ||||
| func (r *request) doWithRetries(ctx context.Context, responses []*http.Response) (*http.Response, error) { | ||||
| 	resp, err := r.do(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	responses = append(responses, resp) | ||||
| 	req, err = r.retryRequest(ctx, req, responses) | ||||
| 	retry, err := r.retryRequest(ctx, responses) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if req != nil { | ||||
| 	if retry { | ||||
| 		resp.Body.Close() | ||||
| 		return r.doRequestWithRetries(ctx, req, responses) | ||||
| 		return r.doWithRetries(ctx, responses) | ||||
| 	} | ||||
| 	return resp, err | ||||
| } | ||||
|  | ||||
| func (r *dockerBase) retryRequest(ctx context.Context, req *http.Request, responses []*http.Response) (*http.Request, error) { | ||||
| func (r *request) retryRequest(ctx context.Context, responses []*http.Response) (bool, error) { | ||||
| 	if len(responses) > 5 { | ||||
| 		return nil, nil | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	last := responses[len(responses)-1] | ||||
| 	if last.StatusCode == http.StatusUnauthorized { | ||||
| 	switch last.StatusCode { | ||||
| 	case http.StatusUnauthorized: | ||||
| 		log.G(ctx).WithField("header", last.Header.Get("WWW-Authenticate")).Debug("Unauthorized") | ||||
| 		if r.auth != nil { | ||||
| 			if err := r.auth.AddResponses(ctx, responses); err == nil { | ||||
| 				return copyRequest(req) | ||||
| 		if r.host.Authorizer != nil { | ||||
| 			if err := r.host.Authorizer.AddResponses(ctx, responses); err == nil { | ||||
| 				return true, nil | ||||
| 			} else if !errdefs.IsNotImplemented(err) { | ||||
| 				return nil, err | ||||
| 				return false, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return nil, nil | ||||
| 	} else if last.StatusCode == http.StatusMethodNotAllowed && req.Method == http.MethodHead { | ||||
| 		return false, nil | ||||
| 	case http.StatusMethodNotAllowed: | ||||
| 		// Support registries which have not properly implemented the HEAD method for | ||||
| 		// manifests endpoint | ||||
| 		if strings.Contains(req.URL.Path, "/manifests/") { | ||||
| 			// TODO: copy request? | ||||
| 			req.Method = http.MethodGet | ||||
| 			return copyRequest(req) | ||||
| 		if r.method == http.MethodHead && strings.Contains(r.path, "/manifests/") { | ||||
| 			r.method = http.MethodGet | ||||
| 			return true, nil | ||||
| 		} | ||||
| 	case http.StatusRequestTimeout, http.StatusTooManyRequests: | ||||
| 		return true, nil | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Handle 50x errors accounting for attempt history | ||||
| 	return nil, nil | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func copyRequest(req *http.Request) (*http.Request, error) { | ||||
| 	ireq := *req | ||||
| 	if ireq.GetBody != nil { | ||||
| 		var err error | ||||
| 		ireq.Body, err = ireq.GetBody() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| func (r *request) String() string { | ||||
| 	return r.host.Scheme + "://" + r.host.Host + r.path | ||||
| } | ||||
|  | ||||
| func requestFields(req *http.Request) logrus.Fields { | ||||
| 	fields := map[string]interface{}{ | ||||
| 		"request.method": req.Method, | ||||
| 	} | ||||
| 	for k, vals := range req.Header { | ||||
| 		k = strings.ToLower(k) | ||||
| 		if k == "authorization" { | ||||
| 			continue | ||||
| 		} | ||||
| 		for i, v := range vals { | ||||
| 			field := "request.header." + k | ||||
| 			if i > 0 { | ||||
| 				field = fmt.Sprintf("%s.%d", field, i) | ||||
| 			} | ||||
| 			fields[field] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return &ireq, nil | ||||
|  | ||||
| 	return logrus.Fields(fields) | ||||
| } | ||||
|  | ||||
| func responseFields(resp *http.Response) logrus.Fields { | ||||
| 	fields := map[string]interface{}{ | ||||
| 		"response.status": resp.Status, | ||||
| 	} | ||||
| 	for k, vals := range resp.Header { | ||||
| 		k = strings.ToLower(k) | ||||
| 		for i, v := range vals { | ||||
| 			field := "response.header." + k | ||||
| 			if i > 0 { | ||||
| 				field = fmt.Sprintf("%s.%d", field, i) | ||||
| 			} | ||||
| 			fields[field] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return logrus.Fields(fields) | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containerd/containerd/remotes/docker/schema1/converter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -216,12 +216,12 @@ func (c *Converter) Convert(ctx context.Context, opts ...ConvertOpt) (ocispec.De | ||||
|  | ||||
| 	ref := remotes.MakeRefKey(ctx, desc) | ||||
| 	if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc, content.WithLabels(labels)); err != nil { | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config") | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to write image manifest") | ||||
| 	} | ||||
|  | ||||
| 	ref = remotes.MakeRefKey(ctx, config) | ||||
| 	if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config); err != nil { | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config") | ||||
| 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to write image config") | ||||
| 	} | ||||
|  | ||||
| 	return desc, nil | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 ulyssessouza
					ulyssessouza