From f1ff4d0940cc44dd45337193280bb8488d6abdf5 Mon Sep 17 00:00:00 2001 From: Ma Shimiao Date: Thu, 23 Jun 2016 19:57:34 +0800 Subject: [PATCH] validate: add mount type check Signed-off-by: Ma Shimiao --- completions/bash/ocitools | 2 +- man/ocitools-validate.1.md | 11 +++++- validate.go | 81 ++++++++++++++++++++++++++++++++------ 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/completions/bash/ocitools b/completions/bash/ocitools index 3664dfb02..2e61822b1 100644 --- a/completions/bash/ocitools +++ b/completions/bash/ocitools @@ -253,7 +253,7 @@ _ocitools_validate() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--hooks --path --help" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--host-specific --path --help" -- "$cur" ) ) ;; esac diff --git a/man/ocitools-validate.1.md b/man/ocitools-validate.1.md index bb465d502..a65a152cc 100644 --- a/man/ocitools-validate.1.md +++ b/man/ocitools-validate.1.md @@ -18,8 +18,15 @@ Validate an OCI bundle **--path=PATH Path to bundle -**--hooks** - Check specified hooks exist and are executable on the host. +**--host-specific** + Check host specific configs. + By default, validation only tests for compatibility with a hypothetical host. + With this flag, validation will also run more specific tests to see whether + the current host is capable of launching a container from the configuration. + For example, validating a compliant Windows configuration on a Linux machine + will pass without this flag ("there may be a Windows host capable of + launching this container"), but will fail with it ("this host is not capable + of launching this container"). # SEE ALSO **ocitools**(1) diff --git a/validate.go b/validate.go index 4ed2c6e92..e173cfc24 100644 --- a/validate.go +++ b/validate.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "encoding/json" "fmt" "io/ioutil" @@ -20,7 +21,7 @@ import ( var bundleValidateFlags = []cli.Flag{ cli.StringFlag{Name: "path", Value: ".", Usage: "path to a bundle"}, - cli.BoolFlag{Name: "hooks", Usage: "Check specified hooks exist and are executable on the host."}, + cli.BoolFlag{Name: "host-specific", Usage: "Check host specific configs."}, } var ( @@ -79,20 +80,21 @@ var bundleValidateCommand = cli.Command{ return fmt.Errorf("The root path %q is not a directory.", rootfsPath) } - hooksCheck := context.Bool("hooks") - bundleValidate(spec, rootfsPath, hooksCheck) + hostCheck := context.Bool("host-specific") + bundleValidate(spec, rootfsPath, hostCheck) logrus.Infof("Bundle validation succeeded.") return nil }, } -func bundleValidate(spec rspec.Spec, rootfs string, hooksCheck bool) { +func bundleValidate(spec rspec.Spec, rootfs string, hostCheck bool) { checkMandatoryField(spec) checkSemVer(spec.Version) checkPlatform(spec.Platform) checkProcess(spec.Process, rootfs) + checkMounts(spec, hostCheck) checkLinux(spec) - checkHooks(spec.Hooks, hooksCheck) + checkHooks(spec.Hooks, hostCheck) } func checkSemVer(version string) { @@ -129,19 +131,19 @@ func checkPlatform(platform rspec.Platform) { logrus.Fatalf("Operation system %q of the bundle is not supported yet.", platform.OS) } -func checkHooks(hooks rspec.Hooks, hooksCheck bool) { - checkEventHooks("pre-start", hooks.Prestart, hooksCheck) - checkEventHooks("post-start", hooks.Poststart, hooksCheck) - checkEventHooks("post-stop", hooks.Poststop, hooksCheck) +func checkHooks(hooks rspec.Hooks, hostCheck bool) { + checkEventHooks("pre-start", hooks.Prestart, hostCheck) + checkEventHooks("post-start", hooks.Poststart, hostCheck) + checkEventHooks("post-stop", hooks.Poststop, hostCheck) } -func checkEventHooks(hookType string, hooks []rspec.Hook, hooksCheck bool) { +func checkEventHooks(hookType string, hooks []rspec.Hook, hostCheck bool) { for _, hook := range hooks { if !filepath.IsAbs(hook.Path) { logrus.Fatalf("The %s hook %v: is not absolute path", hookType, hook.Path) } - if hooksCheck { + if hostCheck { fi, err := os.Stat(hook.Path) if err != nil { logrus.Fatalf("Cannot find %s hook: %v", hookType, hook.Path) @@ -192,6 +194,63 @@ func checkProcess(process rspec.Process, rootfs string) { } } +func supportedMountTypes(OS string, hostCheck bool) (map[string]bool, error) { + supportedTypes := make(map[string]bool) + + if OS != "linux" && OS != "windows" { + logrus.Warnf("%v is not supported to check mount type", OS) + return nil, nil + } else if OS == "windows" { + supportedTypes["ntfs"] = true + return supportedTypes, nil + } + + if hostCheck { + f, err := os.Open("/proc/filesystems") + if err != nil { + return nil, err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + if err := s.Err(); err != nil { + return supportedTypes, err + } + + text := s.Text() + parts := strings.Split(text, "\t") + if len(parts) > 1 { + supportedTypes[parts[1]] = true + } else { + supportedTypes[parts[0]] = true + } + } + + supportedTypes["bind"] = true + + return supportedTypes, nil + } else { + logrus.Warn("Checking linux mount types without --host-specific is not supported yet") + return nil, nil + } +} + +func checkMounts(spec rspec.Spec, hostCheck bool) { + supportedTypes, err := supportedMountTypes(spec.Platform.OS, hostCheck) + if err != nil { + logrus.Fatal(err) + } + + if supportedTypes != nil { + for _, mount := range spec.Mounts { + if !supportedTypes[mount.Type] { + logrus.Fatalf("Unsupported mount type %q", mount.Type) + } + } + } +} + //Linux only func checkLinux(spec rspec.Spec) { utsExists := false