Example #1
0
// TODO(jonboulle): find a cleaner way to communicate instead of all these args.
func validate(amOK bool, am io.Reader, fsmOK bool, fsm io.Reader, rfsOK bool, files []string) error {
	if !amOK && !fsmOK {
		return ErrNoManifest
	}
	if amOK {
		if !rfsOK {
			return ErrNoRootFS
		}
		b, err := ioutil.ReadAll(am)
		if err != nil {
			return fmt.Errorf("error reading app manifest: %v", err)
		}
		var a schema.AppManifest
		if err := a.UnmarshalJSON(b); err != nil {
			return fmt.Errorf("app manifest validation failed: %v", err)
		}
	}
	var rfsfiles []string
	for _, f := range files {
		switch {
		case strings.HasPrefix(f, "rootfs"):
			rfsfiles = append(rfsfiles, strings.TrimPrefix(f, "rootfs"))
		default:
			return fmt.Errorf("unrecognized file path in layout: %q", f)
		}
	}
	if fsmOK {
		b, err := ioutil.ReadAll(fsm)
		if err != nil {
			return fmt.Errorf("error reading fileset manifest: %v", err)
		}
		var f schema.FilesetManifest
		if err := f.UnmarshalJSON(b); err != nil {
			return fmt.Errorf("fileset manifest validation failed: %v", err)
		}
		// TODO(jonboulle): this is not quite correct since it does not
		// deal with dependent filesets. Maybe filesAreSuperset()?
		return filesEqual(f.Files, rfsfiles)
	}
	return nil
}
Example #2
0
func runValidate(args []string) (exit int) {
	if len(args) < 1 {
		stderr("must pass one or more files")
		return 1
	}

	for _, path := range args {
		vt := valType
		fi, err := os.Stat(path)
		if err != nil {
			stderr("unable to access %s: %v", path, err)
			return 1
		}
		var fh *os.File
		if fi.IsDir() {
			switch vt {
			case typeImageLayout:
			case "":
				vt = typeImageLayout
			case typeManifest, typeAppImage:
				stderr("%s is a directory (wrong --type?)", path)
				return 1
			default:
				// should never happen
				panic(fmt.Sprintf("unexpected type: %v", vt))
			}
		} else {
			fh, err = os.Open(path)
			if err != nil {
				stderr("%s: unable to open: %v", path, err)
				return 1
			}
		}

		if vt == "" {
			vt, err = detectValType(fh)
			if err != nil {
				stderr("%s: error detecting file type: %v", path, err)
				return 1
			}
		}
		switch vt {
		case typeImageLayout:
			err = aci.ValidateLayout(path)
			if err != nil {
				stderr("%s: invalid image layout: %v", path, err)
				exit = 1
			} else if globalFlags.Debug {
				stderr("%s: valid image layout", path)
			}
		case typeAppImage:
			fr, err := maybeDecompress(fh)
			if err != nil {
				stderr("%s: error decompressing file: %v", path, err)
				return 1
			}
			tr := tar.NewReader(fr)
			err = aci.ValidateArchive(tr)
			fh.Close()
			if err != nil {
				stderr("%s: error validating: %v", path, err)
				exit = 1
			} else if globalFlags.Debug {
				stderr("%s: valid app container image", path)
			}
		case typeManifest:
			b, err := ioutil.ReadAll(fh)
			fh.Close()
			if err != nil {
				stderr("%s: unable to read file %s", path, err)
				return 1
			}
			k := schema.Kind{}
			if err := k.UnmarshalJSON(b); err != nil {
				stderr("%s: error unmarshaling manifest: %v", path, err)
				return 1
			}
			switch k.ACKind {
			case "AppManifest":
				m := schema.AppManifest{}
				err = m.UnmarshalJSON(b)
			case "ContainerRuntimeManifest":
				m := schema.ContainerRuntimeManifest{}
				err = m.UnmarshalJSON(b)
			case "FilesetManifest":
				m := schema.FilesetManifest{}
				err = m.UnmarshalJSON(b)
			default:
				// Should not get here; schema.Kind unmarshal should fail
				panic("bad ACKind")
			}
			if err != nil {
				stderr("%s: invalid %s: %v", path, k.ACKind, err)
				exit = 1
			} else if globalFlags.Debug {
				stderr("%s: valid %s", path, k.ACKind)
			}
		default:
			stderr("%s: unable to detect filetype (try --type)", path)
			return 1
		}
	}

	return
}
Example #3
0
func runBuild(args []string) (exit int) {
	if len(args) != 2 {
		stderr("build: Must provide directory and output file")
		return 1
	}
	switch {
	case buildFilesetName != "" && buildAppManifest == "":
	case buildFilesetName == "" && buildAppManifest != "":
	default:
		stderr("build: must specify either --fileset-name or --app-manifest")
		return 1
	}

	root := args[0]
	tgt := args[1]
	ext := filepath.Ext(tgt)
	if ext != schema.ACIExtension {
		stderr("build: Extension must be %s (given %s)", schema.ACIExtension, ext)
		return 1
	}

	mode := os.O_CREATE | os.O_WRONLY
	if !buildOverwrite {
		mode |= os.O_EXCL
	}
	fh, err := os.OpenFile(tgt, mode, 0644)
	if err != nil {
		if os.IsExist(err) {
			stderr("build: Target file exists (try --overwrite)")
		} else {
			stderr("build: Unable to open target %s: %v", tgt, err)
		}
		return 1
	}

	gw := gzip.NewWriter(fh)
	tr := tar.NewWriter(gw)

	defer func() {
		tr.Close()
		gw.Close()
		fh.Close()
		if exit != 0 && !buildOverwrite {
			os.Remove(tgt)
		}
	}()

	var aw aci.ArchiveWriter
	if buildFilesetName != "" {
		aw, err = aci.NewFilesetWriter(buildFilesetName, tr)
		if err != nil {
			stderr("build: Unable to create FilesetWriter: %v", err)
			return 1
		}
	} else {
		b, err := ioutil.ReadFile(buildAppManifest)
		if err != nil {
			stderr("build: Unable to read App Manifest: %v", err)
			return 1
		}
		var am schema.AppManifest
		if err := am.UnmarshalJSON(b); err != nil {
			stderr("build: Unable to load App Manifest: %v", err)
			return 1
		}
		aw = aci.NewAppWriter(am, tr)
	}

	err = filepath.Walk(root, buildWalker(root, aw, buildRootfs))
	if err != nil {
		stderr("build: Error walking rootfs: %v", err)
		return 1
	}

	err = aw.Close()
	if err != nil {
		stderr("build: Unable to close Fileset image %s: %v", tgt, err)
		return 1
	}

	return
}