github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/graph/manifest_test.go (about) 1 package graph 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "testing" 8 9 "github.com/docker/distribution/digest" 10 "github.com/docker/docker/image" 11 "github.com/docker/docker/registry" 12 "github.com/docker/docker/runconfig" 13 "github.com/docker/docker/utils" 14 "github.com/docker/libtrust" 15 ) 16 17 const ( 18 testManifestImageName = "testapp" 19 testManifestImageID = "d821b739e8834ec89ac4469266c3d11515da88fdcbcbdddcbcddb636f54fdde9" 20 testManifestImageIDShort = "d821b739e883" 21 testManifestTag = "manifesttest" 22 ) 23 24 func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error) { 25 manifest := ®istry.ManifestData{ 26 Name: remoteName, 27 Tag: tag, 28 SchemaVersion: 1, 29 } 30 localRepo, err := s.Get(localName) 31 if err != nil { 32 return nil, err 33 } 34 if localRepo == nil { 35 return nil, fmt.Errorf("Repo does not exist: %s", localName) 36 } 37 38 // Get the top-most layer id which the tag points to 39 layerId, exists := localRepo[tag] 40 if !exists { 41 return nil, fmt.Errorf("Tag does not exist for %s: %s", localName, tag) 42 } 43 layersSeen := make(map[string]bool) 44 45 layer, err := s.graph.Get(layerId) 46 if err != nil { 47 return nil, err 48 } 49 manifest.Architecture = layer.Architecture 50 manifest.FSLayers = make([]*registry.FSLayer, 0, 4) 51 manifest.History = make([]*registry.ManifestHistory, 0, 4) 52 var metadata runconfig.Config 53 if layer.Config != nil { 54 metadata = *layer.Config 55 } 56 57 for ; layer != nil; layer, err = s.graph.GetParent(layer) { 58 if err != nil { 59 return nil, err 60 } 61 62 if layersSeen[layer.ID] { 63 break 64 } 65 if layer.Config != nil && metadata.Image != layer.ID { 66 err = runconfig.Merge(&metadata, layer.Config) 67 if err != nil { 68 return nil, err 69 } 70 } 71 72 dgst, err := s.graph.GetDigest(layer.ID) 73 if err == ErrDigestNotSet { 74 archive, err := s.graph.TarLayer(layer) 75 if err != nil { 76 return nil, err 77 } 78 79 defer archive.Close() 80 81 dgst, err = digest.FromReader(archive) 82 if err != nil { 83 return nil, err 84 } 85 86 // Save checksum value 87 if err := s.graph.SetDigest(layer.ID, dgst); err != nil { 88 return nil, err 89 } 90 } else if err != nil { 91 return nil, fmt.Errorf("Error getting image checksum: %s", err) 92 } 93 94 jsonData, err := s.graph.RawJSON(layer.ID) 95 if err != nil { 96 return nil, fmt.Errorf("Cannot retrieve the path for {%s}: %s", layer.ID, err) 97 } 98 99 manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: dgst.String()}) 100 101 layersSeen[layer.ID] = true 102 103 manifest.History = append(manifest.History, ®istry.ManifestHistory{V1Compatibility: string(jsonData)}) 104 } 105 106 manifestBytes, err := json.MarshalIndent(manifest, "", " ") 107 if err != nil { 108 return nil, err 109 } 110 111 return manifestBytes, nil 112 } 113 114 func TestManifestTarsumCache(t *testing.T) { 115 tmp, err := utils.TestDirectory("") 116 if err != nil { 117 t.Fatal(err) 118 } 119 defer os.RemoveAll(tmp) 120 store := mkTestTagStore(tmp, t) 121 defer store.graph.driver.Cleanup() 122 123 archive, err := fakeTar() 124 if err != nil { 125 t.Fatal(err) 126 } 127 img := &image.Image{ID: testManifestImageID} 128 if err := store.graph.Register(img, archive); err != nil { 129 t.Fatal(err) 130 } 131 if err := store.Tag(testManifestImageName, testManifestTag, testManifestImageID, false); err != nil { 132 t.Fatal(err) 133 } 134 135 if _, err := store.graph.GetDigest(testManifestImageID); err == nil { 136 t.Fatalf("Non-empty checksum file after register") 137 } else if err != ErrDigestNotSet { 138 t.Fatal(err) 139 } 140 141 // Generate manifest 142 payload, err := store.newManifest(testManifestImageName, testManifestImageName, testManifestTag) 143 if err != nil { 144 t.Fatal(err) 145 } 146 147 manifestChecksum, err := store.graph.GetDigest(testManifestImageID) 148 if err != nil { 149 t.Fatal(err) 150 } 151 152 var manifest registry.ManifestData 153 if err := json.Unmarshal(payload, &manifest); err != nil { 154 t.Fatalf("error unmarshalling manifest: %s", err) 155 } 156 157 if len(manifest.FSLayers) != 1 { 158 t.Fatalf("Unexpected number of layers, expecting 1: %d", len(manifest.FSLayers)) 159 } 160 161 if manifest.FSLayers[0].BlobSum != manifestChecksum.String() { 162 t.Fatalf("Unexpected blob sum, expecting %q, got %q", manifestChecksum, manifest.FSLayers[0].BlobSum) 163 } 164 165 if len(manifest.History) != 1 { 166 t.Fatalf("Unexpected number of layer history, expecting 1: %d", len(manifest.History)) 167 } 168 169 v1compat, err := store.graph.RawJSON(img.ID) 170 if err != nil { 171 t.Fatal(err) 172 } 173 if manifest.History[0].V1Compatibility != string(v1compat) { 174 t.Fatalf("Unexpected json value\nExpected:\n%s\nActual:\n%s", v1compat, manifest.History[0].V1Compatibility) 175 } 176 } 177 178 // TestManifestDigestCheck ensures that loadManifest properly verifies the 179 // remote and local digest. 180 func TestManifestDigestCheck(t *testing.T) { 181 tmp, err := utils.TestDirectory("") 182 if err != nil { 183 t.Fatal(err) 184 } 185 defer os.RemoveAll(tmp) 186 store := mkTestTagStore(tmp, t) 187 defer store.graph.driver.Cleanup() 188 189 archive, err := fakeTar() 190 if err != nil { 191 t.Fatal(err) 192 } 193 img := &image.Image{ID: testManifestImageID} 194 if err := store.graph.Register(img, archive); err != nil { 195 t.Fatal(err) 196 } 197 if err := store.Tag(testManifestImageName, testManifestTag, testManifestImageID, false); err != nil { 198 t.Fatal(err) 199 } 200 201 if _, err := store.graph.GetDigest(testManifestImageID); err == nil { 202 t.Fatalf("Non-empty checksum file after register") 203 } else if err != ErrDigestNotSet { 204 t.Fatal(err) 205 } 206 207 // Generate manifest 208 payload, err := store.newManifest(testManifestImageName, testManifestImageName, testManifestTag) 209 if err != nil { 210 t.Fatalf("unexpected error generating test manifest: %v", err) 211 } 212 213 pk, err := libtrust.GenerateECP256PrivateKey() 214 if err != nil { 215 t.Fatalf("unexpected error generating private key: %v", err) 216 } 217 218 sig, err := libtrust.NewJSONSignature(payload) 219 if err != nil { 220 t.Fatalf("error creating signature: %v", err) 221 } 222 223 if err := sig.Sign(pk); err != nil { 224 t.Fatalf("error signing manifest bytes: %v", err) 225 } 226 227 signedBytes, err := sig.PrettySignature("signatures") 228 if err != nil { 229 t.Fatalf("error getting signed bytes: %v", err) 230 } 231 232 dgst, err := digest.FromBytes(payload) 233 if err != nil { 234 t.Fatalf("error getting digest of manifest: %v", err) 235 } 236 237 // use this as the "bad" digest 238 zeroDigest, err := digest.FromBytes([]byte{}) 239 if err != nil { 240 t.Fatalf("error making zero digest: %v", err) 241 } 242 243 // Remote and local match, everything should look good 244 local, _, _, err := store.loadManifest(signedBytes, dgst.String(), dgst) 245 if err != nil { 246 t.Fatalf("unexpected error verifying local and remote digest: %v", err) 247 } 248 249 if local != dgst { 250 t.Fatalf("local digest not correctly calculated: %v", err) 251 } 252 253 // remote and no local, since pulling by tag 254 local, _, _, err = store.loadManifest(signedBytes, "tag", dgst) 255 if err != nil { 256 t.Fatalf("unexpected error verifying tag pull and remote digest: %v", err) 257 } 258 259 if local != dgst { 260 t.Fatalf("local digest not correctly calculated: %v", err) 261 } 262 263 // remote and differing local, this is the most important to fail 264 local, _, _, err = store.loadManifest(signedBytes, zeroDigest.String(), dgst) 265 if err == nil { 266 t.Fatalf("error expected when verifying with differing local digest") 267 } 268 269 // no remote, no local (by tag) 270 local, _, _, err = store.loadManifest(signedBytes, "tag", "") 271 if err != nil { 272 t.Fatalf("unexpected error verifying manifest without remote digest: %v", err) 273 } 274 275 if local != dgst { 276 t.Fatalf("local digest not correctly calculated: %v", err) 277 } 278 279 // no remote, with local 280 local, _, _, err = store.loadManifest(signedBytes, dgst.String(), "") 281 if err != nil { 282 t.Fatalf("unexpected error verifying manifest without remote digest: %v", err) 283 } 284 285 if local != dgst { 286 t.Fatalf("local digest not correctly calculated: %v", err) 287 } 288 289 // bad remote, we fail the check. 290 local, _, _, err = store.loadManifest(signedBytes, dgst.String(), zeroDigest) 291 if err == nil { 292 t.Fatalf("error expected when verifying with differing remote digest") 293 } 294 }