add better generate

Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
Jess Frazelle 2018-03-20 01:33:56 -04:00
parent 3fc6abf56b
commit cdd93563f5
5655 changed files with 1187011 additions and 392 deletions

View file

@ -0,0 +1,23 @@
version: 0.1
log:
level: debug
formatter: text
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: 0.0.0.0:5000
headers:
X-Content-Type-Options: [nosniff]
host: https://localhost:5000
tls:
certificate: /etc/docker/registry/ssl/cert.pem
key: /etc/docker/registry/ssl/key.pem
auth:
htpasswd:
realm: basic-realm
path: /etc/docker/registry/htpasswd

View file

@ -0,0 +1 @@
admin:$2y$05$TpcLzA8b5hMLptNGRIRWXuOI7KmAOqIuRhHAv15qHNrJaxuyIhCg6

View file

@ -0,0 +1,19 @@
version: 0.1
log:
level: debug
formatter: text
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: 0.0.0.0:5000
headers:
X-Content-Type-Options: [nosniff]
host: https://localhost:5000
tls:
certificate: /etc/docker/registry/ssl/cert.pem
key: /etc/docker/registry/ssl/key.pem

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDAjCCAeqgAwIBAgIQC+Tw335jnu9Z46unSVFfeTANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMB4XDTE3MDYwNjAwMDAyNFoXDTE4MDYwNjAwMDAy
NFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAN8/Xqef2iozUMXLRCvHnGc+SMaEDuW/iM9n/IL68F11esAR6tXhaiRQ
RdEsM9MyfyDYt9juE+XLaMyqhTAXwK9YzULE4BTVbAr9uOgxLtyWspA4uWfxhcrq
CqQTRc0U95ZEnAVSjytDAXtLQyP+UlnMzmMhDpzRuH1YXqm6qB07G5yOJyPKkDrq
EyqUsjqBJmBkUJiYfSx95Jen+4ZzlSR7wOsoxei09QYyvo3DMfcJO8Wb8IQFjOT0
ohhBFBR3v1HOOT6bKuhUHif3K+STguMEhHrgAFmcFW3NPQ3It2SyKfGBZ8nbmSA9
2tjojQEFUHqRKp0UWyObuUmNAo1U1w8CAwEAAaNUMFIwDgYDVR0PAQH/BAQDAgKk
MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0RBBMw
EYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCl+yJgekN3dMbR
mxs7B8VSFv5a7zElDvTnagX3pSBHq7fLf45qVHOmZK/esgD3K8H5Kvft6u100b1j
4TLn2oFYVMME8BV0qNl5wgynNrJs131G3jgxcrgqu9NdlFpWZm8S+DCHo+h1ZH4Z
LmlUt2uvwCbmZK/e6U0ZDICDKRwMaC6LdUCfLfn9F+ACpPTpAZBVbi0rpAYimBDf
j2QZJBWD9tV5xUVSLEmqFvi42g2khK43HFu9N35vPIqyrl4Gh5x3erZR7t8pGEu0
kOiqfCmV1GHL8egxYew4wJ1P6TzhYNk/7vpiJxrwPs3vW+WXaSBFdvoV1qQ6onjm
CxG31l+z
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3z9ep5/aKjNQxctEK8ecZz5IxoQO5b+Iz2f8gvrwXXV6wBHq
1eFqJFBF0Swz0zJ/INi32O4T5ctozKqFMBfAr1jNQsTgFNVsCv246DEu3JaykDi5
Z/GFyuoKpBNFzRT3lkScBVKPK0MBe0tDI/5SWczOYyEOnNG4fVheqbqoHTsbnI4n
I8qQOuoTKpSyOoEmYGRQmJh9LH3kl6f7hnOVJHvA6yjF6LT1BjK+jcMx9wk7xZvw
hAWM5PSiGEEUFHe/Uc45Ppsq6FQeJ/cr5JOC4wSEeuAAWZwVbc09Dci3ZLIp8YFn
yduZID3a2OiNAQVQepEqnRRbI5u5SY0CjVTXDwIDAQABAoIBACw3LNQeQONiznie
TZ4uJrf8CgXnWdv/F2WcvtJiSQD5p5oq8kvyHUeb7ngDPTBzK+KhiagZXy+AHf2L
OF3SFoOkHuM+gvMdYgy7O8ghFZry7eLKmU4Q8+LAf+MHPifkIzVL2Wrkcx6qYry8
p0uVr1HB0o6nmXFNyDBrNDSBl5JSJ+IyvtPr7ow5iO2iZLh0nV5CfM65vX2ESkvD
+uil1uFfLdmNkfItK/0oTLngiXzJBCgPzTwBnKGlmoYzWvO/CMMIEkv0tdy/b1l9
BTXiuRQEBy+CzSmoPyNnBCE/SOhZLH8+eGzsnlaty66AKWA1EwSjq7lDO1MOAL5Y
dPqwk8ECgYEA51T895d707Hl2/ggpEP1Wg8p96nz2iCt903WIOLn2X/9su2mNu5r
+Xtkd39ZYUuJIIja8hyx3q9E761jSI/F3lr4jwhTYO15aNvyD9S0supqASVodT33
VKYxrFH2PbRfb7RyuTUjlusJeP0QFz7hZ81eooYcgqkv8Gim14Y6XgkCgYEA9w2w
P5bTEPHweGCJ8I9AgCGUsg39x23qwN8xkxKb6jQcj6wHBpSw/yAPpAZ/1o+GFWDO
xiiNfqc+pLHAgPwEY2iUFKKJtKaS1kFIljTK353HVrDcqviCa4GCpSlBRi4xBkfi
vxS81eKaf8ChoiqfOuz3g6dHl6n3RGoQ8KpgUlcCgYBzbJh8AX2rdww14WyICdCW
CxLpnEcsAzpKNvAsoIsGnzI64REaP4RoiwTqCwTR4xqcvSxhuaeWcOV4oY70Wahk
9gcndwQDTPpTM8tn0r4Gt6gEwmGIfk62UeZfENZIm4My/Vpwxu7nEoc7cylgL+PQ
I0yg00HOgBSHY/A7gaIF4QKBgQDwjfaQZEaOGFYCkFWf04yFdq03lmIF/qP3Oxwl
TZhdOnKY/nM02DFjqY8xMlblz4hKZqHP1wq3SRe4+48qyLlpJhoR4ZXePdd6IcUQ
5MSpahL/+WRUYXd0QH26Xeo98JoxuGszjXi1dljjjeiUY5X5pWT4XzhZl9i5V+G4
xNzXLwKBgHtH/cPeR5O5gSHG+Fi5Sb/Ip6YYg00N8vtGwYYyc2i/uqz1N20igHJY
df7D5eYRIqrhBUVxqaqqs43oa1fi7CIFITYmof+qpxzRWKq9PPFc8D9mV0/03lba
0+i0kAvJB76WBiX48z8h+Rbc0IrZRDrVz9fk4Yfh+gHT4KDPmuII
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,241 @@
package testutils
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/term"
)
// StartRegistry starts a new registry container.
func StartRegistry(dcli *client.Client, config, username, password string) (string, string, error) {
_, filename, _, ok := runtime.Caller(0)
if !ok {
return "", "", errors.New("No caller information")
}
image := "registry:2"
if err := pullDockerImage(dcli, image); err != nil {
return "", "", err
}
r, err := dcli.ContainerCreate(
context.Background(),
&container.Config{
Image: image,
},
&container.HostConfig{
NetworkMode: "host",
Binds: []string{
filepath.Join(filepath.Dir(filename), "configs", config) + ":" + "/etc/docker/registry/config.yml" + ":ro",
filepath.Join(filepath.Dir(filename), "configs", "htpasswd") + ":" + "/etc/docker/registry/htpasswd" + ":ro",
filepath.Join(filepath.Dir(filename), "snakeoil") + ":" + "/etc/docker/registry/ssl" + ":ro",
},
},
nil, "")
if err != nil {
return "", "", err
}
// start the container
if err := dcli.ContainerStart(context.Background(), r.ID, types.ContainerStartOptions{}); err != nil {
return r.ID, "", err
}
port := ":5000"
addr := "https://localhost" + port
if err := waitForConn(addr, filepath.Join(filepath.Dir(filename), "snakeoil", "cert.pem"), filepath.Join(filepath.Dir(filename), "snakeoil", "key.pem")); err != nil {
return r.ID, addr, err
}
if err := dockerLogin("localhost"+port, username, password); err != nil {
return r.ID, addr, err
}
// Prefill the images.
images := []string{"alpine:latest", "busybox:latest", "busybox:musl", "busybox:glibc"}
for _, image := range images {
if err := prefillRegistry(image, dcli, "localhost"+port, username, password); err != nil {
return r.ID, addr, err
}
}
return r.ID, addr, nil
}
// RemoveContainer removes with force a container by it's container ID.
func RemoveContainer(dcli *client.Client, ctrID string) error {
return dcli.ContainerRemove(context.Background(), ctrID,
types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
})
}
// dockerLogin logins via the command line to a docker registry
func dockerLogin(addr, username, password string) error {
cmd := exec.Command("docker", "login", "--username", username, "--password", password, addr)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("docker login [%s] failed with output %q and error: %v", strings.Join(cmd.Args, " "), string(out), err)
}
return nil
}
// prefillRegistry adds images to a registry.
func prefillRegistry(image string, dcli *client.Client, addr, username, password string) error {
if err := pullDockerImage(dcli, image); err != nil {
return err
}
if err := dcli.ImageTag(context.Background(), image, addr+"/"+image); err != nil {
return err
}
auth, err := constructRegistryAuth(username, password)
if err != nil {
return err
}
resp, err := dcli.ImagePush(context.Background(), addr+"/"+image, types.ImagePushOptions{
RegistryAuth: auth,
})
if err != nil {
return err
}
defer resp.Close()
fd, isTerm := term.GetFdInfo(os.Stdout)
return jsonmessage.DisplayJSONMessagesStream(resp, os.Stdout, fd, isTerm, nil)
}
func pullDockerImage(dcli *client.Client, image string) error {
exists, err := imageExists(dcli, image)
if err != nil {
return err
}
if exists {
return nil
}
resp, err := dcli.ImagePull(context.Background(), image, types.ImagePullOptions{})
if err != nil {
return err
}
defer resp.Close()
fd, isTerm := term.GetFdInfo(os.Stdout)
return jsonmessage.DisplayJSONMessagesStream(resp, os.Stdout, fd, isTerm, nil)
}
func imageExists(dcli *client.Client, image string) (bool, error) {
_, _, err := dcli.ImageInspectWithRaw(context.Background(), image)
if err == nil {
return true, nil
}
if client.IsErrNotFound(err) {
return false, nil
}
return false, err
}
// waitForConn takes a tcp addr and waits until it is reachable
func waitForConn(addr, cert, key string) error {
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
}
certPool, err := x509.SystemCertPool()
if err != nil {
return fmt.Errorf("failed to read system certificates: %v", err)
}
pem, err := ioutil.ReadFile(cert)
if err != nil {
return fmt.Errorf("could not read CA certificate %s: %v", cert, err)
}
if !certPool.AppendCertsFromPEM(pem) {
return fmt.Errorf("failed to append certificates from PEM file: %s", cert)
}
c := http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{tlsCert},
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
},
RootCAs: certPool,
},
},
}
n := 0
max := 10
for n < max {
if _, err := c.Get(addr + "/v2/"); err != nil {
fmt.Printf("try number %d to %s: %v\n", n, addr, err)
n++
if n != max {
fmt.Println("sleeping for 1 second then will try again...")
time.Sleep(time.Second)
} else {
return fmt.Errorf("[WHOOPS]: maximum retries for %s exceeded", addr)
}
continue
} else {
break
}
}
return nil
}
// constructRegistryAuth serializes the auth configuration as JSON base64 payload.
func constructRegistryAuth(identity, secret string) (string, error) {
buf, err := json.Marshal(types.AuthConfig{Username: identity, Password: secret})
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buf), nil
}