func checkMinimalContainer(t *testing.T, acipath string, expectedManifest schema.ImageManifest) { // Check that there are no files in the rootfs files, err := ioutil.ReadDir(path.Join(acipath, aci.RootfsDir)) if err != nil { t.Errorf("%v", err) } if len(files) != 0 { t.Errorf("rootfs in aci contains files, should be empty") } // Check that the manifest is no bigger than it needs to be manblob, err := ioutil.ReadFile(path.Join(acipath, aci.ManifestFile)) if err != nil { t.Errorf("%v", err) } var man schema.ImageManifest err = man.UnmarshalJSON(manblob) if err != nil { t.Errorf("invalid manifest schema: %v", err) } if str := pretty.Compare(man, expectedManifest); str != "" { t.Errorf("unexpected manifest:\n%s", str) } }
// ManifestFromImage extracts a new schema.ImageManifest from the given ACI image. func ManifestFromImage(rs io.ReadSeeker) (*schema.ImageManifest, error) { var im schema.ImageManifest tr, err := NewCompressedTarReader(rs) if err != nil { return nil, err } defer tr.Close() for { hdr, err := tr.Next() switch err { case io.EOF: return nil, errors.New("missing manifest") case nil: if filepath.Clean(hdr.Name) == ManifestFile { data, err := ioutil.ReadAll(tr) if err != nil { return nil, err } if err := im.UnmarshalJSON(data); err != nil { return nil, err } return &im, nil } default: return nil, fmt.Errorf("error extracting tarball: %v", err) } } }
func validate(imOK bool, im io.Reader, rfsOK bool, files []string) error { defer func() { if rc, ok := im.(io.Closer); ok { rc.Close() } }() if !imOK { return ErrNoManifest } if !rfsOK { return ErrNoRootFS } b, err := ioutil.ReadAll(im) if err != nil { return fmt.Errorf("error reading image manifest: %v", err) } var a schema.ImageManifest if err := a.UnmarshalJSON(b); err != nil { return fmt.Errorf("image manifest validation failed: %v", err) } if a.ACVersion.LessThanMajor(schema.AppContainerVersion) { return ErrOldVersion{ version: a.ACVersion, } } for _, f := range files { if !strings.HasPrefix(f, "rootfs") { return fmt.Errorf("unrecognized file path in layout: %q", f) } } return nil }
func createImageManifest(imj string) (*schema.ImageManifest, error) { var im schema.ImageManifest err := im.UnmarshalJSON([]byte(imj)) if err != nil { return nil, err } return &im, nil }
func prettyPrintMan(manblob []byte) []byte { var man schema.ImageManifest err := man.UnmarshalJSON(manblob) if err != nil { panic(err) } manblob2, err := json.MarshalIndent(man, "", " ") if err != nil { panic(err) } return manblob2 }
// CatManifest will print to stdout the manifest from the ACI stored at // aciPath, optionally inserting whitespace to make it more human readable. func CatManifest(aciPath string, prettyPrint bool) (err error) { finfo, err := os.Stat(aciPath) switch { case os.IsNotExist(err): return fmt.Errorf("no such file or directory: %s", aciPath) case err != nil: return err case finfo.IsDir(): return fmt.Errorf("%s is a directory, not an ACI", aciPath) default: break } file, err := os.Open(aciPath) if err != nil { return err } defer file.Close() tr, err := aci.NewCompressedTarReader(file) if err != nil { return fmt.Errorf("error decompressing image: %v", err) } defer tr.Close() for { hdr, err := tr.Next() switch { case err == io.EOF: return fmt.Errorf("manifest not found in ACI %s", aciPath) case err != nil: return err case hdr.Name == "manifest": manblob, err := ioutil.ReadAll(tr) if err != nil { return err } var man schema.ImageManifest err = man.UnmarshalJSON(manblob) if err != nil { return err } return util.PrintManifest(&man, prettyPrint) } } }
func checkManifest(t *testing.T, workingDir string, wantedManifest schema.ImageManifest) { acipath := path.Join(workingDir, ".acbuild", "currentaci") manblob, err := ioutil.ReadFile(path.Join(acipath, aci.ManifestFile)) if err != nil { panic(err) } var man schema.ImageManifest err = man.UnmarshalJSON(manblob) if err != nil { t.Errorf("invalid manifest schema: %v", err) } if str := pretty.Compare(man, wantedManifest); str != "" { t.Errorf("unexpected manifest:\n%s", str) } }
// ReplaceManifest will replace the manifest in the expanded ACI stored at // a.CurrentACIPath with the new manifest stored at manifestPath func (a *ACBuild) ReplaceManifest(manifestPath string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() finfo, err := os.Stat(manifestPath) switch { case os.IsNotExist(err): return fmt.Errorf("no such file or directory: %s", manifestPath) case err != nil: return err case finfo.IsDir(): return fmt.Errorf("%s is a directory", manifestPath) default: break } manblob, err := ioutil.ReadFile(manifestPath) if err != nil { return err } // Marshal and Unmarshal the manifest to assert that it's valid and to // strip any whitespace var man schema.ImageManifest err = man.UnmarshalJSON(manblob) if err != nil { return err } manblob, err = man.MarshalJSON() if err != nil { return err } return ioutil.WriteFile(path.Join(a.CurrentACIPath, aci.ManifestFile), manblob, 0755) }
func testCat(t *testing.T, workingDir string) { wantedManblob, err := ioutil.ReadFile(path.Join(workingDir, ".acbuild", "currentaci", aci.ManifestFile)) if err != nil { panic(err) } wantedManblob = append(wantedManblob, byte('\n')) var man schema.ImageManifest err = man.UnmarshalJSON(wantedManblob) if err != nil { panic(err) } _, manblob, _, err := runACBuild(workingDir, "cat-manifest") if err != nil { t.Fatalf("%v", err) } if manblob != string(wantedManblob) { t.Fatalf("printed manifest and manifest on disk differ") } wantedManblob = prettyPrintMan(wantedManblob) wantedManblob = append(wantedManblob, byte('\n')) _, manblob, _, err = runACBuild(workingDir, "cat-manifest", "--pretty-print") if err != nil { t.Fatalf("%v", err) } if manblob != string(wantedManblob) { t.Fatalf("pretty printed manifest and manifest on disk differ") } checkManifest(t, workingDir, man) checkEmptyRootfs(t, workingDir) }