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 }