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 := &registry.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, &registry.FSLayer{BlobSum: dgst.String()})
   100  
   101  		layersSeen[layer.ID] = true
   102  
   103  		manifest.History = append(manifest.History, &registry.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  }