gitee.com/bomy/docker.git@v1.13.1/integration-cli/registry.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  
    11  	"github.com/docker/distribution/digest"
    12  	"github.com/go-check/check"
    13  )
    14  
    15  const (
    16  	v2binary        = "registry-v2"
    17  	v2binarySchema1 = "registry-v2-schema1"
    18  )
    19  
    20  type testRegistryV2 struct {
    21  	cmd      *exec.Cmd
    22  	dir      string
    23  	auth     string
    24  	username string
    25  	password string
    26  	email    string
    27  }
    28  
    29  func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) {
    30  	tmp, err := ioutil.TempDir("", "registry-test-")
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	template := `version: 0.1
    35  loglevel: debug
    36  storage:
    37      filesystem:
    38          rootdirectory: %s
    39  http:
    40      addr: %s
    41  %s`
    42  	var (
    43  		authTemplate string
    44  		username     string
    45  		password     string
    46  		email        string
    47  	)
    48  	switch auth {
    49  	case "htpasswd":
    50  		htpasswdPath := filepath.Join(tmp, "htpasswd")
    51  		// generated with: htpasswd -Bbn testuser testpassword
    52  		userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m"
    53  		username = "testuser"
    54  		password = "testpassword"
    55  		email = "test@test.org"
    56  		if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil {
    57  			return nil, err
    58  		}
    59  		authTemplate = fmt.Sprintf(`auth:
    60      htpasswd:
    61          realm: basic-realm
    62          path: %s
    63  `, htpasswdPath)
    64  	case "token":
    65  		authTemplate = fmt.Sprintf(`auth:
    66      token:
    67          realm: %s
    68          service: "registry"
    69          issuer: "auth-registry"
    70          rootcertbundle: "fixtures/registry/cert.pem"
    71  `, tokenURL)
    72  	}
    73  
    74  	confPath := filepath.Join(tmp, "config.yaml")
    75  	config, err := os.Create(confPath)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	defer config.Close()
    80  
    81  	if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil {
    82  		os.RemoveAll(tmp)
    83  		return nil, err
    84  	}
    85  
    86  	binary := v2binary
    87  	if schema1 {
    88  		binary = v2binarySchema1
    89  	}
    90  	cmd := exec.Command(binary, confPath)
    91  	if err := cmd.Start(); err != nil {
    92  		os.RemoveAll(tmp)
    93  		if os.IsNotExist(err) {
    94  			c.Skip(err.Error())
    95  		}
    96  		return nil, err
    97  	}
    98  	return &testRegistryV2{
    99  		cmd:      cmd,
   100  		dir:      tmp,
   101  		auth:     auth,
   102  		username: username,
   103  		password: password,
   104  		email:    email,
   105  	}, nil
   106  }
   107  
   108  func (t *testRegistryV2) Ping() error {
   109  	// We always ping through HTTP for our test registry.
   110  	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL))
   111  	if err != nil {
   112  		return err
   113  	}
   114  	resp.Body.Close()
   115  
   116  	fail := resp.StatusCode != http.StatusOK
   117  	if t.auth != "" {
   118  		// unauthorized is a _good_ status when pinging v2/ and it needs auth
   119  		fail = fail && resp.StatusCode != http.StatusUnauthorized
   120  	}
   121  	if fail {
   122  		return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode)
   123  	}
   124  	return nil
   125  }
   126  
   127  func (t *testRegistryV2) Close() {
   128  	t.cmd.Process.Kill()
   129  	os.RemoveAll(t.dir)
   130  }
   131  
   132  func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string {
   133  	// Split the digest into its algorithm and hex components.
   134  	dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex()
   135  
   136  	// The path to the target blob data looks something like:
   137  	//   baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data"
   138  	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex)
   139  }
   140  
   141  func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte {
   142  	// Load the target manifest blob.
   143  	manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest))
   144  	if err != nil {
   145  		c.Fatalf("unable to read blob: %s", err)
   146  	}
   147  
   148  	return manifestBlob
   149  }
   150  
   151  func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) {
   152  	if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil {
   153  		c.Fatalf("unable to write malicious data blob: %s", err)
   154  	}
   155  }
   156  
   157  func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) {
   158  	tempFile, err := ioutil.TempFile("", "registry-temp-blob-")
   159  	if err != nil {
   160  		c.Fatalf("unable to get temporary blob file: %s", err)
   161  	}
   162  	tempFile.Close()
   163  
   164  	blobFilename := t.getBlobFilename(blobDigest)
   165  
   166  	// Move the existing data file aside, so that we can replace it with a
   167  	// another blob of data.
   168  	if err := os.Rename(blobFilename, tempFile.Name()); err != nil {
   169  		os.Remove(tempFile.Name())
   170  		c.Fatalf("unable to move data blob: %s", err)
   171  	}
   172  
   173  	return func() {
   174  		os.Rename(tempFile.Name(), blobFilename)
   175  		os.Remove(tempFile.Name())
   176  	}
   177  }