github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/internal/test/registry/registry.go (about)

     1  package registry // import "github.com/docker/docker/internal/test/registry"
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"time"
    11  
    12  	"github.com/gotestyourself/gotestyourself/assert"
    13  	"github.com/opencontainers/go-digest"
    14  )
    15  
    16  const (
    17  	// V2binary is the name of the registry v2 binary
    18  	V2binary = "registry-v2"
    19  	// V2binarySchema1 is the name of the registry that serve schema1
    20  	V2binarySchema1 = "registry-v2-schema1"
    21  	// DefaultURL is the default url that will be used by the registry (if not specified otherwise)
    22  	DefaultURL = "127.0.0.1:5000"
    23  )
    24  
    25  type testingT interface {
    26  	assert.TestingT
    27  	logT
    28  	Fatal(...interface{})
    29  	Fatalf(string, ...interface{})
    30  }
    31  
    32  type logT interface {
    33  	Logf(string, ...interface{})
    34  }
    35  
    36  // V2 represent a registry version 2
    37  type V2 struct {
    38  	cmd         *exec.Cmd
    39  	registryURL string
    40  	dir         string
    41  	auth        string
    42  	username    string
    43  	password    string
    44  	email       string
    45  }
    46  
    47  // Config contains the test registry configuration
    48  type Config struct {
    49  	schema1     bool
    50  	auth        string
    51  	tokenURL    string
    52  	registryURL string
    53  }
    54  
    55  // NewV2 creates a v2 registry server
    56  func NewV2(t testingT, ops ...func(*Config)) *V2 {
    57  	c := &Config{
    58  		registryURL: DefaultURL,
    59  	}
    60  	for _, op := range ops {
    61  		op(c)
    62  	}
    63  	tmp, err := ioutil.TempDir("", "registry-test-")
    64  	assert.NilError(t, err)
    65  	template := `version: 0.1
    66  loglevel: debug
    67  storage:
    68      filesystem:
    69          rootdirectory: %s
    70  http:
    71      addr: %s
    72  %s`
    73  	var (
    74  		authTemplate string
    75  		username     string
    76  		password     string
    77  		email        string
    78  	)
    79  	switch c.auth {
    80  	case "htpasswd":
    81  		htpasswdPath := filepath.Join(tmp, "htpasswd")
    82  		// generated with: htpasswd -Bbn testuser testpassword
    83  		userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m"
    84  		username = "testuser"
    85  		password = "testpassword"
    86  		email = "test@test.org"
    87  		err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644))
    88  		assert.NilError(t, err)
    89  		authTemplate = fmt.Sprintf(`auth:
    90      htpasswd:
    91          realm: basic-realm
    92          path: %s
    93  `, htpasswdPath)
    94  	case "token":
    95  		authTemplate = fmt.Sprintf(`auth:
    96      token:
    97          realm: %s
    98          service: "registry"
    99          issuer: "auth-registry"
   100          rootcertbundle: "fixtures/registry/cert.pem"
   101  `, c.tokenURL)
   102  	}
   103  
   104  	confPath := filepath.Join(tmp, "config.yaml")
   105  	config, err := os.Create(confPath)
   106  	assert.NilError(t, err)
   107  	defer config.Close()
   108  
   109  	if _, err := fmt.Fprintf(config, template, tmp, c.registryURL, authTemplate); err != nil {
   110  		// FIXME(vdemeester) use a defer/clean func
   111  		os.RemoveAll(tmp)
   112  		t.Fatal(err)
   113  	}
   114  
   115  	binary := V2binary
   116  	if c.schema1 {
   117  		binary = V2binarySchema1
   118  	}
   119  	cmd := exec.Command(binary, confPath)
   120  	if err := cmd.Start(); err != nil {
   121  		// FIXME(vdemeester) use a defer/clean func
   122  		os.RemoveAll(tmp)
   123  		t.Fatal(err)
   124  	}
   125  	return &V2{
   126  		cmd:         cmd,
   127  		dir:         tmp,
   128  		auth:        c.auth,
   129  		username:    username,
   130  		password:    password,
   131  		email:       email,
   132  		registryURL: c.registryURL,
   133  	}
   134  }
   135  
   136  // WaitReady waits for the registry to be ready to serve requests (or fail after a while)
   137  func (r *V2) WaitReady(t testingT) {
   138  	var err error
   139  	for i := 0; i != 50; i++ {
   140  		if err = r.Ping(); err == nil {
   141  			return
   142  		}
   143  		time.Sleep(100 * time.Millisecond)
   144  	}
   145  	t.Fatalf("timeout waiting for test registry to become available: %v", err)
   146  }
   147  
   148  // Ping sends an http request to the current registry, and fail if it doesn't respond correctly
   149  func (r *V2) Ping() error {
   150  	// We always ping through HTTP for our test registry.
   151  	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", r.registryURL))
   152  	if err != nil {
   153  		return err
   154  	}
   155  	resp.Body.Close()
   156  
   157  	fail := resp.StatusCode != http.StatusOK
   158  	if r.auth != "" {
   159  		// unauthorized is a _good_ status when pinging v2/ and it needs auth
   160  		fail = fail && resp.StatusCode != http.StatusUnauthorized
   161  	}
   162  	if fail {
   163  		return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode)
   164  	}
   165  	return nil
   166  }
   167  
   168  // Close kills the registry server
   169  func (r *V2) Close() {
   170  	r.cmd.Process.Kill()
   171  	r.cmd.Process.Wait()
   172  	os.RemoveAll(r.dir)
   173  }
   174  
   175  func (r *V2) getBlobFilename(blobDigest digest.Digest) string {
   176  	// Split the digest into its algorithm and hex components.
   177  	dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex()
   178  
   179  	// The path to the target blob data looks something like:
   180  	//   baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data"
   181  	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", r.dir, dgstAlg, dgstHex[:2], dgstHex)
   182  }
   183  
   184  // ReadBlobContents read the file corresponding to the specified digest
   185  func (r *V2) ReadBlobContents(t assert.TestingT, blobDigest digest.Digest) []byte {
   186  	// Load the target manifest blob.
   187  	manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest))
   188  	assert.NilError(t, err, "unable to read blob")
   189  	return manifestBlob
   190  }
   191  
   192  // WriteBlobContents write the file corresponding to the specified digest with the given content
   193  func (r *V2) WriteBlobContents(t assert.TestingT, blobDigest digest.Digest, data []byte) {
   194  	err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644))
   195  	assert.NilError(t, err, "unable to write malicious data blob")
   196  }
   197  
   198  // TempMoveBlobData moves the existing data file aside, so that we can replace it with a
   199  // malicious blob of data for example.
   200  func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func()) {
   201  	tempFile, err := ioutil.TempFile("", "registry-temp-blob-")
   202  	assert.NilError(t, err, "unable to get temporary blob file")
   203  	tempFile.Close()
   204  
   205  	blobFilename := r.getBlobFilename(blobDigest)
   206  
   207  	// Move the existing data file aside, so that we can replace it with a
   208  	// another blob of data.
   209  	if err := os.Rename(blobFilename, tempFile.Name()); err != nil {
   210  		// FIXME(vdemeester) use a defer/clean func
   211  		os.Remove(tempFile.Name())
   212  		t.Fatalf("unable to move data blob: %s", err)
   213  	}
   214  
   215  	return func() {
   216  		os.Rename(tempFile.Name(), blobFilename)
   217  		os.Remove(tempFile.Name())
   218  	}
   219  }
   220  
   221  // Username returns the configured user name of the server
   222  func (r *V2) Username() string {
   223  	return r.username
   224  }
   225  
   226  // Password returns the configured password of the server
   227  func (r *V2) Password() string {
   228  	return r.password
   229  }
   230  
   231  // Email returns the configured email of the server
   232  func (r *V2) Email() string {
   233  	return r.email
   234  }
   235  
   236  // Path returns the path where the registry write data
   237  func (r *V2) Path() string {
   238  	return filepath.Join(r.dir, "docker", "registry", "v2")
   239  }