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