init commit for coverting to podman

This commit is contained in:
zerodoctor
2023-10-04 23:19:30 -05:00
parent 7e9969423c
commit 04332e5527
96 changed files with 2034 additions and 534 deletions

View File

@@ -0,0 +1,29 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package errors
import (
"errors"
"strings"
)
// TrimExtraInfo is a helper function that trims extra information
// from a Docker error. Specifically, on Windows, this can expose
// environment variables and other sensitive data.
func TrimExtraInfo(err error) error {
if err == nil {
return nil
}
s := err.Error()
i := strings.Index(s, "extra info:")
if i > 0 {
s = s[:i]
s = strings.TrimSpace(s)
s = strings.TrimSuffix(s, "(0x2)")
s = strings.TrimSpace(s)
return errors.New(s)
}
return err
}

View File

@@ -0,0 +1,22 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package errors
import (
"errors"
"testing"
)
func TestTrimExtraInfo(t *testing.T) {
const (
before = `Error response from daemon: container encountered an error during CreateProcess: failure in a Windows system call: The system cannot find the file specified. (0x2) extra info: { "User":"ContainerUser" }`
after = `Error response from daemon: container encountered an error during CreateProcess: failure in a Windows system call: The system cannot find the file specified.`
)
errBefore := errors.New(before)
errAfter := TrimExtraInfo(errBefore)
if errAfter.Error() != after {
t.Errorf("Expect trimmed image")
}
}

View File

@@ -0,0 +1,92 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package image
import (
"net/url"
"strings"
"github.com/docker/distribution/reference"
)
// Trim returns the short image name without tag.
func Trim(name string) string {
ref, err := reference.ParseAnyReference(name)
if err != nil {
return name
}
named, err := reference.ParseNamed(ref.String())
if err != nil {
return name
}
named = reference.TrimNamed(named)
return reference.FamiliarName(named)
}
// Expand returns the fully qualified image name.
func Expand(name string) string {
ref, err := reference.ParseAnyReference(name)
if err != nil {
return name
}
named, err := reference.ParseNamed(ref.String())
if err != nil {
return name
}
named = reference.TagNameOnly(named)
return named.String()
}
// Match returns true if the image name matches
// an image in the list. Note the image tag is not used
// in the matching logic.
func Match(from string, to ...string) bool {
from = Trim(from)
for _, match := range to {
if from == Trim(match) {
return true
}
}
return false
}
// MatchTag returns true if the image name matches
// an image in the list, including the tag.
func MatchTag(a, b string) bool {
return Expand(a) == Expand(b)
}
// MatchHostname returns true if the image hostname
// matches the specified hostname.
func MatchHostname(image, hostname string) bool {
ref, err := reference.ParseAnyReference(image)
if err != nil {
return false
}
named, err := reference.ParseNamed(ref.String())
if err != nil {
return false
}
if hostname == "index.docker.io" {
hostname = "docker.io"
}
// the auth address could be a fully qualified
// url in which case, we should parse so we can
// extract the domain name.
if strings.HasPrefix(hostname, "http://") ||
strings.HasPrefix(hostname, "https://") {
parsed, err := url.Parse(hostname)
if err == nil {
hostname = parsed.Host
}
}
return reference.Domain(named) == hostname
}
// IsLatest parses the image and returns true if
// the image uses the :latest tag.
func IsLatest(s string) bool {
return strings.HasSuffix(Expand(s), ":latest")
}

View File

@@ -0,0 +1,347 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package image
import "testing"
func Test_trimImage(t *testing.T) {
testdata := []struct {
from string
want string
}{
{
from: "golang",
want: "golang",
},
{
from: "golang:latest",
want: "golang",
},
{
from: "golang:1.0.0",
want: "golang",
},
{
from: "library/golang",
want: "golang",
},
{
from: "library/golang:latest",
want: "golang",
},
{
from: "library/golang:1.0.0",
want: "golang",
},
{
from: "index.docker.io/library/golang:1.0.0",
want: "golang",
},
{
from: "docker.io/library/golang:1.0.0",
want: "golang",
},
{
from: "gcr.io/library/golang:1.0.0",
want: "gcr.io/library/golang",
},
// error cases, return input unmodified
{
from: "foo/bar?baz:boo",
want: "foo/bar?baz:boo",
},
}
for _, test := range testdata {
got, want := Trim(test.from), test.want
if got != want {
t.Errorf("Want image %q trimmed to %q, got %q", test.from, want, got)
}
}
}
func Test_expandImage(t *testing.T) {
testdata := []struct {
from string
want string
}{
{
from: "golang",
want: "docker.io/library/golang:latest",
},
{
from: "golang:latest",
want: "docker.io/library/golang:latest",
},
{
from: "golang:1.0.0",
want: "docker.io/library/golang:1.0.0",
},
{
from: "library/golang",
want: "docker.io/library/golang:latest",
},
{
from: "library/golang:latest",
want: "docker.io/library/golang:latest",
},
{
from: "library/golang:1.0.0",
want: "docker.io/library/golang:1.0.0",
},
{
from: "index.docker.io/library/golang:1.0.0",
want: "docker.io/library/golang:1.0.0",
},
{
from: "gcr.io/golang",
want: "gcr.io/golang:latest",
},
{
from: "gcr.io/golang:1.0.0",
want: "gcr.io/golang:1.0.0",
},
// error cases, return input unmodified
{
from: "foo/bar?baz:boo",
want: "foo/bar?baz:boo",
},
}
for _, test := range testdata {
got, want := Expand(test.from), test.want
if got != want {
t.Errorf("Want image %q expanded to %q, got %q", test.from, want, got)
}
}
}
func Test_matchImage(t *testing.T) {
testdata := []struct {
from, to string
want bool
}{
{
from: "golang",
to: "golang",
want: true,
},
{
from: "golang:latest",
to: "golang",
want: true,
},
{
from: "library/golang:latest",
to: "golang",
want: true,
},
{
from: "index.docker.io/library/golang:1.0.0",
to: "golang",
want: true,
},
{
from: "golang",
to: "golang:latest",
want: true,
},
{
from: "library/golang:latest",
to: "library/golang",
want: true,
},
{
from: "gcr.io/golang",
to: "gcr.io/golang",
want: true,
},
{
from: "gcr.io/golang:1.0.0",
to: "gcr.io/golang",
want: true,
},
{
from: "gcr.io/golang:latest",
to: "gcr.io/golang",
want: true,
},
{
from: "gcr.io/golang",
to: "gcr.io/golang:latest",
want: true,
},
{
from: "golang",
to: "library/golang",
want: true,
},
{
from: "golang",
to: "gcr.io/project/golang",
want: false,
},
{
from: "golang",
to: "gcr.io/library/golang",
want: false,
},
{
from: "golang",
to: "gcr.io/golang",
want: false,
},
}
for _, test := range testdata {
got, want := Match(test.from, test.to), test.want
if got != want {
t.Errorf("Want image %q matching %q is %v", test.from, test.to, want)
}
}
}
func Test_matchHostname(t *testing.T) {
testdata := []struct {
image, hostname string
want bool
}{
{
image: "golang",
hostname: "docker.io",
want: true,
},
{
image: "golang:latest",
hostname: "docker.io",
want: true,
},
{
image: "golang:latest",
hostname: "index.docker.io",
want: true,
},
{
image: "library/golang:latest",
hostname: "docker.io",
want: true,
},
{
image: "docker.io/library/golang:1.0.0",
hostname: "docker.io",
want: true,
},
{
image: "gcr.io/golang",
hostname: "docker.io",
want: false,
},
{
image: "gcr.io/golang:1.0.0",
hostname: "gcr.io",
want: true,
},
{
image: "gcr.io/golang:1.0.0",
hostname: "gcr.io",
want: true,
},
{
image: "012345678910.dkr.ecr.us-east-1.amazonaws.com/foo:latest",
hostname: "012345678910.dkr.ecr.us-east-1.amazonaws.com",
want: true,
},
{
image: "012345678910.dkr.ecr.us-east-1.amazonaws.com/foo:latest",
hostname: "https://012345678910.dkr.ecr.us-east-1.amazonaws.com",
want: true,
},
{
image: "*&^%",
hostname: "1.2.3.4:8000",
want: false,
},
}
for _, test := range testdata {
got, want := MatchHostname(test.image, test.hostname), test.want
if got != want {
t.Errorf("Want image %q matching hostname %q is %v", test.image, test.hostname, want)
}
}
}
func Test_matchTag(t *testing.T) {
testdata := []struct {
a, b string
want bool
}{
{
a: "golang:1.0",
b: "golang:1.0",
want: true,
},
{
a: "golang",
b: "golang:latest",
want: true,
},
{
a: "docker.io/library/golang",
b: "golang:latest",
want: true,
},
{
a: "golang",
b: "golang:1.0",
want: false,
},
{
a: "golang:1.0",
b: "golang:2.0",
want: false,
},
}
for _, test := range testdata {
got, want := MatchTag(test.a, test.b), test.want
if got != want {
t.Errorf("Want image %q matching image tag %q is %v", test.a, test.b, want)
}
}
}
func Test_isLatest(t *testing.T) {
testdata := []struct {
name string
want bool
}{
{
name: "golang:1",
want: false,
},
{
name: "golang",
want: true,
},
{
name: "golang:latest",
want: true,
},
{
name: "docker.io/library/golang",
want: true,
},
{
name: "docker.io/library/golang:latest",
want: true,
},
{
name: "docker.io/library/golang:1",
want: false,
},
}
for _, test := range testdata {
got, want := IsLatest(test.name), test.want
if got != want {
t.Errorf("Want image %q isLatest %v", test.name, want)
}
}
}

View File

@@ -0,0 +1,61 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package jsonmessage
import (
"encoding/json"
"fmt"
"io"
)
type jsonError struct {
Code int `json:"code"`
Message string `json:"message"`
}
func (e *jsonError) Error() string {
return e.Message
}
type jsonMessage struct {
ID string `json:"id"`
Status string `json:"status"`
Error *jsonError `json:"errorDetail"`
Progress *jsonProgress `json:"progressDetail"`
}
type jsonProgress struct {
}
// Copy copies a json message string to the io.Writer.
func Copy(in io.Reader, out io.Writer) error {
dec := json.NewDecoder(in)
for {
var jm jsonMessage
if err := dec.Decode(&jm); err != nil {
if err == io.EOF {
break
}
return err
}
if jm.Error != nil {
if jm.Error.Code == 401 {
return fmt.Errorf("authentication is required")
}
return jm.Error
}
if jm.Progress != nil {
continue
}
if jm.ID == "" {
fmt.Fprintf(out, "%s\n", jm.Status)
} else {
fmt.Fprintf(out, "%s: %s\n", jm.ID, jm.Status)
}
}
return nil
}

View File

@@ -0,0 +1,12 @@
{"status":"Pulling from library/alpine","id":"3.6"}
{"status":"Pulling fs layer","progressDetail":{},"id":"5a3ea8efae5d"}
{"status":"Downloading","progressDetail":{"current":21019,"total":2017774},"progress":"[\u003e ] 21.02kB/2.018MB","id":"5a3ea8efae5d"}
{"status":"Downloading","progressDetail":{"current":1194721,"total":2017774},"progress":"[=============================\u003e ] 1.195MB/2.018MB","id":"5a3ea8efae5d"}
{"status":"Verifying Checksum","progressDetail":{},"id":"5a3ea8efae5d"}
{"status":"Download complete","progressDetail":{},"id":"5a3ea8efae5d"}
{"status":"Extracting","progressDetail":{"current":32768,"total":2017774},"progress":"[\u003e ] 32.77kB/2.018MB","id":"5a3ea8efae5d"}
{"status":"Extracting","progressDetail":{"current":786432,"total":2017774},"progress":"[===================\u003e ] 786.4kB/2.018MB","id":"5a3ea8efae5d"}
{"status":"Extracting","progressDetail":{"current":2017774,"total":2017774},"progress":"[==================================================\u003e] 2.018MB/2.018MB","id":"5a3ea8efae5d"}
{"status":"Pull complete","progressDetail":{},"id":"5a3ea8efae5d"}
{"status":"Digest: sha256:66790a2b79e1ea3e1dabac43990c54aca5d1ddf268d9a5a0285e4167c8b24475"}
{"status":"Status: Downloaded newer image for alpine:3.6"}

View File

@@ -0,0 +1,5 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package podman

View File

@@ -0,0 +1,188 @@
// Copyright 2018 Docker, Inc.
//
// 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 stdcopy
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"sync"
)
// StdType is the type of standard stream
// a writer can multiplex to.
type StdType byte
const (
// Stdin represents standard input stream type.
Stdin StdType = iota
// Stdout represents standard output stream type.
Stdout
// Stderr represents standard error steam type.
Stderr
stdWriterPrefixLen = 8
stdWriterFdIndex = 0
stdWriterSizeIndex = 4
startingBufLen = 32*1024 + stdWriterPrefixLen + 1
)
var bufPool = &sync.Pool{New: func() interface{} { return bytes.NewBuffer(nil) }}
// stdWriter is wrapper of io.Writer with extra customized info.
type stdWriter struct {
io.Writer
prefix byte
}
// Write sends the buffer to the underneath writer.
// It inserts the prefix header before the buffer,
// so stdcopy.StdCopy knows where to multiplex the output.
// It makes stdWriter to implement io.Writer.
func (w *stdWriter) Write(p []byte) (n int, err error) {
if w == nil || w.Writer == nil {
return 0, errors.New("Writer not instantiated")
}
if p == nil {
return 0, nil
}
header := [stdWriterPrefixLen]byte{stdWriterFdIndex: w.prefix}
binary.BigEndian.PutUint32(header[stdWriterSizeIndex:], uint32(len(p)))
buf := bufPool.Get().(*bytes.Buffer)
buf.Write(header[:])
buf.Write(p)
n, err = w.Writer.Write(buf.Bytes())
n -= stdWriterPrefixLen
if n < 0 {
n = 0
}
buf.Reset()
bufPool.Put(buf)
return
}
// NewStdWriter instantiates a new Writer.
// Everything written to it will be encapsulated using a custom format,
// and written to the underlying `w` stream.
// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection.
// `t` indicates the id of the stream to encapsulate.
// It can be stdcopy.Stdin, stdcopy.Stdout, stdcopy.Stderr.
func NewStdWriter(w io.Writer, t StdType) io.Writer {
return &stdWriter{
Writer: w,
prefix: byte(t),
}
}
// StdCopy is a modified version of io.Copy.
//
// StdCopy will demultiplex `src`, assuming that it contains two streams,
// previously multiplexed together using a StdWriter instance.
// As it reads from `src`, StdCopy will write to `dstout` and `dsterr`.
//
// StdCopy will read until it hits EOF on `src`. It will then return a nil error.
// In other words: if `err` is non nil, it indicates a real underlying error.
//
// `written` will hold the total number of bytes written to `dstout` and `dsterr`.
func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) {
var (
buf = make([]byte, startingBufLen)
bufLen = len(buf)
nr, nw int
er, ew error
out io.Writer
frameSize int
)
for {
// Make sure we have at least a full header
for nr < stdWriterPrefixLen {
var nr2 int
nr2, er = src.Read(buf[nr:])
nr += nr2
if er == io.EOF {
if nr < stdWriterPrefixLen {
return written, nil
}
break
}
if er != nil {
return 0, er
}
}
// Check the first byte to know where to write
switch StdType(buf[stdWriterFdIndex]) {
case Stdin:
fallthrough
case Stdout:
// Write on stdout
out = dstout
case Stderr:
// Write on stderr
out = dsterr
default:
return 0, fmt.Errorf("Unrecognized input header: %d", buf[stdWriterFdIndex])
}
// Retrieve the size of the frame
frameSize = int(binary.BigEndian.Uint32(buf[stdWriterSizeIndex : stdWriterSizeIndex+4]))
// Check if the buffer is big enough to read the frame.
// Extend it if necessary.
if frameSize+stdWriterPrefixLen > bufLen {
buf = append(buf, make([]byte, frameSize+stdWriterPrefixLen-bufLen+1)...)
bufLen = len(buf)
}
// While the amount of bytes read is less than the size of the frame + header, we keep reading
for nr < frameSize+stdWriterPrefixLen {
var nr2 int
nr2, er = src.Read(buf[nr:])
nr += nr2
if er == io.EOF {
if nr < frameSize+stdWriterPrefixLen {
return written, nil
}
break
}
if er != nil {
return 0, er
}
}
// Write the retrieved frame (without header)
nw, ew = out.Write(buf[stdWriterPrefixLen : frameSize+stdWriterPrefixLen])
if ew != nil {
return 0, ew
}
// If the frame has not been fully written: error
if nw != frameSize {
return 0, io.ErrShortWrite
}
written += int64(nw)
// Move the rest of the buffer to the beginning
copy(buf, buf[frameSize+stdWriterPrefixLen:])
// Move the index
nr -= frameSize + stdWriterPrefixLen
}
}