func TestAppIsolatorCPU(t *testing.T) { isUnified, err := cgroup.IsCgroupUnified("/") if err != nil { t.Fatalf("Error determining the cgroup version: %v", err) } if isUnified { // TODO: for now kernel does not support cpu isolator in cgroup2. // Write a test when it does. t.Skip("kernel does not support cpu isolator in cgroup2.") } ok, err := cgroup.IsIsolatorSupported("cpu") if err != nil { t.Fatalf("Error checking cpu isolator support: %v", err) } if !ok { t.Skip("CPU isolator not supported.") } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() t.Logf("Running test: %v", cpuTest.testName) aciFileName := patchTestACI("rkt-inspect-isolators.aci", cpuTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), aciFileName) expectedLine := "CPU Quota: " + strconv.Itoa(CPUQuota) runRktAndCheckOutput(t, rktCmd, expectedLine, false) rktCmd = fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s --cpu 900m", ctx.Cmd(), aciFileName) expectedLine = "CPU Quota: " + strconv.Itoa(900) runRktAndCheckOutput(t, rktCmd, expectedLine, false) }
// prepareAppCgroups makes the cgroups-v1 hierarchy for this application writable // by pod supervisor func prepareAppCgroups(p *stage1types.Pod, ra *schema.RuntimeApp, enterCmd []string) error { isUnified, err := cgroup.IsCgroupUnified("/") if err != nil { return errwrap.Wrap(errors.New("failed to determine cgroup version"), err) } if isUnified { return nil } enabledCgroups, err := v1.GetEnabledCgroups() if err != nil { return errwrap.Wrap(errors.New("error getting cgroups"), err) } b, err := ioutil.ReadFile(filepath.Join(p.Root, "subcgroup")) if err != nil { log.PrintE("continuing with per-app isolators disabled", err) return nil } subcgroup := string(b) serviceName := stage1initcommon.ServiceUnitName(ra.Name) if err := v1.RemountCgroupKnobsRW(enabledCgroups, subcgroup, serviceName, enterCmd); err != nil { return errwrap.Wrap(errors.New("error restricting application cgroups"), err) } return nil }
func stage1() int { uuid, err := types.NewUUID(flag.Arg(0)) if err != nil { log.FatalE("UUID is missing or malformed", err) } root := "." p, err := stage1commontypes.LoadPod(root, uuid) if err != nil { log.FatalE("failed to load pod", err) } // set close-on-exec flag on RKT_LOCK_FD so it gets correctly closed when invoking // network plugins lfd, err := common.GetRktLockFD() if err != nil { log.FatalE("failed to get rkt lock fd", err) } if err := sys.CloseOnExec(lfd, true); err != nil { log.FatalE("failed to set FD_CLOEXEC on rkt lock", err) } mirrorLocalZoneInfo(p.Root) flavor, _, err := stage1initcommon.GetFlavor(p) if err != nil { log.FatalE("failed to get stage1 flavor", err) } var n *networking.Networking if netList.Contained() { fps, err := commonnet.ForwardedPorts(p.Manifest) if err != nil { log.FatalE("error initializing forwarding ports", err) } noDNS := dnsConfMode.Pairs["resolv"] != "default" // force ignore CNI DNS results n, err = networking.Setup(root, p.UUID, fps, netList, localConfig, flavor, noDNS, debug) if err != nil { log.FatalE("failed to setup network", err) } if err = n.Save(); err != nil { log.PrintE("failed to save networking state", err) n.Teardown(flavor, debug) return 254 } if len(mdsToken) > 0 { hostIP, err := n.GetForwardableNetHostIP() if err != nil { log.FatalE("failed to get default Host IP", err) } p.MetadataServiceURL = common.MetadataServicePublicURL(hostIP, mdsToken) } } else { if flavor == "kvm" { log.Fatal("flavor kvm requires private network configuration (try --net)") } if len(mdsToken) > 0 { p.MetadataServiceURL = common.MetadataServicePublicURL(localhostIP, mdsToken) } } insecureOptions := stage1initcommon.Stage1InsecureOptions{ DisablePaths: disablePaths, DisableCapabilities: disableCapabilities, DisableSeccomp: disableSeccomp, } mnt := fs.NewLoggingMounter( fs.MounterFunc(syscall.Mount), fs.UnmounterFunc(syscall.Unmount), diag.Printf, ) if dnsConfMode.Pairs["resolv"] == "host" { stage1initcommon.UseHostResolv(mnt, root) } if dnsConfMode.Pairs["hosts"] == "host" { stage1initcommon.UseHostHosts(mnt, root) } if mutable { if err = stage1initcommon.MutableEnv(p); err != nil { log.FatalE("cannot initialize mutable environment", err) } } else { if err = stage1initcommon.ImmutableEnv(p, interactive, privateUsers, insecureOptions); err != nil { log.FatalE("cannot initialize immutable environment", err) } } if err := stage1initcommon.SetJournalPermissions(p); err != nil { log.PrintE("warning: error setting journal ACLs, you'll need root to read the pod journal", err) } if flavor == "kvm" { kvm.InitDebug(debug) if err := KvmNetworkingToSystemd(p, n); err != nil { log.FatalE("failed to configure systemd for kvm", err) } } canMachinedRegister := false if flavor != "kvm" { // kvm doesn't register with systemd right now, see #2664. canMachinedRegister = machinedRegister() } diag.Printf("canMachinedRegister %t", canMachinedRegister) args, env, err := getArgsEnv(p, flavor, canMachinedRegister, debug, n, insecureOptions) if err != nil { log.FatalE("cannot get environment", err) } diag.Printf("args %q", args) diag.Printf("env %q", env) // create a separate mount namespace so the cgroup filesystems // are unmounted when exiting the pod if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil { log.FatalE("error unsharing", err) } // we recursively make / a "shared and slave" so mount events from the // new namespace don't propagate to the host namespace but mount events // from the host propagate to the new namespace and are forwarded to // its peer group // See https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt if err := mnt.Mount("", "/", "none", syscall.MS_REC|syscall.MS_SLAVE, ""); err != nil { log.FatalE("error making / a slave mount", err) } if err := mnt.Mount("", "/", "none", syscall.MS_REC|syscall.MS_SHARED, ""); err != nil { log.FatalE("error making / a shared and slave mount", err) } unifiedCgroup, err := cgroup.IsCgroupUnified("/") if err != nil { log.FatalE("error determining cgroup version", err) } diag.Printf("unifiedCgroup %t", unifiedCgroup) s1Root := common.Stage1RootfsPath(p.Root) machineID := stage1initcommon.GetMachineID(p) subcgroup, err := getContainerSubCgroup(machineID, canMachinedRegister, unifiedCgroup) if err != nil { log.FatalE("error getting container subcgroup", err) } diag.Printf("subcgroup %q", subcgroup) if err := ioutil.WriteFile(filepath.Join(p.Root, "subcgroup"), []byte(fmt.Sprintf("%s", subcgroup)), 0644); err != nil { log.FatalE("cannot write subcgroup file", err) } if !unifiedCgroup { enabledCgroups, err := v1.GetEnabledCgroups() if err != nil { log.FatalE("error getting v1 cgroups", err) } diag.Printf("enabledCgroups %q", enabledCgroups) if err := mountHostV1Cgroups(mnt, enabledCgroups); err != nil { log.FatalE("couldn't mount the host v1 cgroups", err) } if !canMachinedRegister { if err := v1.JoinSubcgroup("systemd", subcgroup); err != nil { log.FatalE(fmt.Sprintf("error joining subcgroup %q", subcgroup), err) } } var serviceNames []string for _, app := range p.Manifest.Apps { serviceNames = append(serviceNames, stage1initcommon.ServiceUnitName(app.Name)) } diag.Printf("serviceNames %q", serviceNames) if err := mountContainerV1Cgroups(mnt, s1Root, enabledCgroups, subcgroup, serviceNames, insecureOptions); err != nil { log.FatalE("couldn't mount the container v1 cgroups", err) } } // KVM flavor has a bit different logic in handling pid vs ppid, for details look into #2389 // it doesn't require the existence of a "ppid", instead it registers the current pid (which // will be reused by lkvm binary) as a pod process pid used during entering pid_filename := "ppid" if flavor == "kvm" { pid_filename = "pid" } if err = stage1common.WritePid(os.Getpid(), pid_filename); err != nil { log.FatalE("error writing pid", err) } if flavor == "kvm" { if err := KvmPrepareMounts(s1Root, p); err != nil { log.FatalE("error preparing mounts", err) } } err = stage1common.WithClearedCloExec(lfd, func() error { return syscall.Exec(args[0], args, env) }) if err != nil { log.FatalE(fmt.Sprintf("failed to execute %q", args[0]), err) } return 0 }
func cleanupV1Cgroups() error { isUnified, err := cgroup.IsCgroupUnified("/") if err != nil { return errwrap.Wrap(errors.New("failed to determine the cgroup version"), err) } if isUnified { return nil } b, err := ioutil.ReadFile("subcgroup") if err != nil { if os.IsNotExist(err) { diag.Printf("subcgroup file missing, probably a failed pod. Skipping cgroup cleanup.") return nil } return errwrap.Wrap(errors.New("error reading subcgroup file"), err) } subcgroup := string(b) // if we're trying to clean up our own cgroup it means we're running in the // same unit file as the rkt pod. We don't have to do anything, systemd // will do the cleanup for us ourCgroupPath, err := v1.GetOwnCgroupPath("name=systemd") if err == nil { if strings.HasPrefix(ourCgroupPath, "/"+subcgroup) { return nil } } f, err := os.Open(cgroupFsPath) if err != nil { return err } defer f.Close() ns, err := f.Readdirnames(0) if err != nil { return err } var cgroupDirs []string for _, c := range ns { scPath := filepath.Join(cgroupFsPath, c, subcgroup) walkCgroupDirs := func(path string, info os.FileInfo, err error) error { // if the subcgroup is already removed, we're fine if os.IsNotExist(err) { return nil } if err != nil { return err } mode := info.Mode() if mode.IsDir() { cgroupDirs = append(cgroupDirs, path) } return nil } if err := filepath.Walk(scPath, walkCgroupDirs); err != nil { log.PrintE(fmt.Sprintf("error walking subcgroup %q", scPath), err) continue } } // remove descendants before ancestors sort.Sort(sort.Reverse(dirsByLength(cgroupDirs))) for _, d := range cgroupDirs { if err := os.RemoveAll(d); err != nil { log.PrintE(fmt.Sprintf("error removing subcgroup %q", d), err) } } return nil }
func main() { globalFlagset.Parse(os.Args[1:]) args := globalFlagset.Args() if len(args) > 0 { fmt.Fprintln(os.Stderr, "Wrong parameters") os.Exit(254) } if globalFlags.SilentSigterm { terminateCh := make(chan os.Signal, 1) signal.Notify(terminateCh, syscall.SIGTERM) go func() { <-terminateCh os.Exit(0) }() } if globalFlags.PreSleep >= 0 { time.Sleep(time.Duration(globalFlags.PreSleep) * time.Second) } if globalFlags.ReadStdin { reader := bufio.NewReader(os.Stdin) fmt.Printf("Enter text:\n") text, _ := reader.ReadString('\n') fmt.Printf("Received text: %s\n", text) } if globalFlags.PrintNoNewPrivs { r1, _, err := syscall.Syscall( syscall.SYS_PRCTL, uintptr(unix.PR_GET_NO_NEW_PRIVS), uintptr(0), uintptr(0), ) fmt.Printf("no_new_privs: %v err: %v\n", r1, err) } if globalFlags.CheckMknod != "" { /* format: c:5:2:name */ dev := strings.SplitN(globalFlags.CheckMknod, ":", 4) if len(dev) < 4 { fmt.Fprintln(os.Stderr, "Not enough parameters for mknod") os.Exit(254) } typ := dev[0] major, err := strconv.Atoi(dev[1]) if err != nil { fmt.Fprintln(os.Stderr, "Wrong major") os.Exit(254) } minor, err := strconv.Atoi(dev[2]) if err != nil { fmt.Fprintln(os.Stderr, "Wrong minor") os.Exit(254) } nodeName := dev[3] majorMinor := device.Makedev(uint(major), uint(minor)) mode := uint32(0777) switch typ { case "c": mode |= syscall.S_IFCHR case "b": mode |= syscall.S_IFBLK default: fmt.Fprintln(os.Stderr, "Wrong device node type") os.Exit(254) } if err := syscall.Mknod(nodeName, mode, int(majorMinor)); err != nil { fmt.Fprintf(os.Stderr, "mknod %s: fail: %v\n", nodeName, err) os.Exit(254) } else { fmt.Printf("mknod %s: succeed\n", nodeName) os.Exit(0) } } if globalFlags.CheckTty { fd := int(os.Stdin.Fd()) var termios syscall.Termios _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) if err == 0 { fmt.Printf("stdin is a terminal\n") } else { fmt.Printf("stdin is not a terminal\n") } } if globalFlags.CheckPath { envBytes, err := ioutil.ReadFile("/proc/self/environ") if err != nil { fmt.Fprintf(os.Stderr, "Error reading environment from \"/proc/self/environ\": %v\n", err) os.Exit(254) } for _, v := range bytes.Split(envBytes, []byte{0}) { if len(v) == 0 { continue } if strings.HasPrefix(string(v), "PATH=") { if strings.Contains(string(v), "\n") { fmt.Fprintf(os.Stderr, "Malformed PATH: found new line") os.Exit(254) } else { fmt.Printf("PATH is good\n") os.Exit(0) } } else { continue } } fmt.Fprintf(os.Stderr, "PATH not found") os.Exit(254) } if globalFlags.PrintExec { fmt.Fprintf(os.Stdout, "inspect execed as: %s\n", os.Args[0]) } if globalFlags.PrintMsg != "" { fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg) messageLoopStr := os.Getenv("MESSAGE_LOOP") messageLoop, err := strconv.Atoi(messageLoopStr) if err == nil { for i := 0; i < messageLoop; i++ { time.Sleep(time.Second) fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg) } } } if globalFlags.PrintEnv != "" { fmt.Fprintf(os.Stdout, "%s=%s\n", globalFlags.PrintEnv, os.Getenv(globalFlags.PrintEnv)) } if globalFlags.PrintCapsPid >= 0 { caps, err := capability.NewPid(globalFlags.PrintCapsPid) if err != nil { fmt.Fprintf(os.Stderr, "Cannot get caps: %v\n", err) os.Exit(254) } fmt.Printf("Capability set: effective: %s (%s)\n", caps.StringCap(capability.EFFECTIVE), globalFlags.SuffixMsg) fmt.Printf("Capability set: permitted: %s (%s)\n", caps.StringCap(capability.PERMITTED), globalFlags.SuffixMsg) fmt.Printf("Capability set: inheritable: %s (%s)\n", caps.StringCap(capability.INHERITABLE), globalFlags.SuffixMsg) fmt.Printf("Capability set: bounding: %s (%s)\n", caps.StringCap(capability.BOUNDING), globalFlags.SuffixMsg) if capStr := os.Getenv("CAPABILITY"); capStr != "" { capInt, err := strconv.Atoi(capStr) if err != nil { fmt.Fprintf(os.Stderr, "Environment variable $CAPABILITY is not a valid capability number: %v\n", err) os.Exit(254) } c := capability.Cap(capInt) if caps.Get(capability.BOUNDING, c) { fmt.Printf("%v=enabled (%s)\n", c.String(), globalFlags.SuffixMsg) } else { fmt.Printf("%v=disabled (%s)\n", c.String(), globalFlags.SuffixMsg) } } } if globalFlags.PrintUser { fmt.Printf("User: uid=%d euid=%d gid=%d egid=%d\n", os.Getuid(), os.Geteuid(), os.Getgid(), os.Getegid()) } if globalFlags.PrintGroups { gids, err := os.Getgroups() if err != nil { fmt.Fprintf(os.Stderr, "Error getting groups: %v\n", err) os.Exit(254) } // getgroups(2): It is unspecified whether the effective group ID of // the calling process is included in the returned list. (Thus, an // application should also call getegid(2) and add or remove the // resulting value.) egid := os.Getegid() if !in(gids, egid) { gids = append(gids, egid) sort.Ints(gids) } var b bytes.Buffer for _, gid := range gids { b.WriteString(fmt.Sprintf("%d ", gid)) } fmt.Printf("Groups: %s\n", b.String()) } if globalFlags.WriteFile { fileName := os.Getenv("FILE") if globalFlags.FileName != "" { fileName = globalFlags.FileName } content := os.Getenv("CONTENT") if globalFlags.Content != "" { content = globalFlags.Content } err := ioutil.WriteFile(fileName, []byte(content), 0600) if err != nil { fmt.Fprintf(os.Stderr, "Cannot write to file %q: %v\n", fileName, err) os.Exit(254) } } if globalFlags.ReadFile { fileName := os.Getenv("FILE") if globalFlags.FileName != "" { fileName = globalFlags.FileName } dat, err := ioutil.ReadFile(fileName) if err != nil { fmt.Fprintf(os.Stderr, "Cannot read file %q: %v\n", fileName, err) os.Exit(254) } fmt.Print("<<<") fmt.Print(string(dat)) fmt.Print(">>>\n") } if globalFlags.StatFile { fileName := os.Getenv("FILE") if globalFlags.FileName != "" { fileName = globalFlags.FileName } fi, err := os.Stat(fileName) if err != nil { fmt.Fprintf(os.Stderr, "Cannot stat file %q: %v\n", fileName, err) os.Exit(254) } fmt.Printf("%s: mode: %s\n", fileName, fi.Mode().String()) fmt.Printf("%s: user: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Uid) fmt.Printf("%s: group: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Gid) } if globalFlags.HashFile { fileName := os.Getenv("FILE") if globalFlags.FileName != "" { fileName = globalFlags.FileName } dat, err := ioutil.ReadFile(fileName) if err != nil { fmt.Fprintf(os.Stderr, "Cannot read file %q: %v\n", fileName, err) os.Exit(254) } fmt.Printf("sha1sum: %x\n", sha1.Sum(dat)) } if globalFlags.FileSymlinkTarget { fileName := os.Getenv("FILE") if globalFlags.FileName != "" { fileName = globalFlags.FileName } dst, err := os.Readlink(fileName) if err != nil { fmt.Fprintf(os.Stderr, "Cannot read file target %q: %v\n", fileName, err) os.Exit(1) } fmt.Printf("symlink: %q -> %q\n", fileName, dst) } if globalFlags.PrintCwd { wd, err := os.Getwd() if err != nil { fmt.Fprintf(os.Stderr, "Cannot get working directory: %v\n", err) os.Exit(254) } fmt.Printf("cwd: %s\n", wd) } if globalFlags.PrintMemoryLimit { // we use /proc/1/root to escape the chroot we're in and read the file isUnified, err := cgroup.IsCgroupUnified("/proc/1/root/") if err != nil { fmt.Fprintf(os.Stderr, "Error getting cgroup type: %v\n", err) os.Exit(254) } var limitPath string if isUnified { cgroupPath, err := v2.GetOwnCgroupPath() if err != nil { fmt.Fprintf(os.Stderr, "Error getting own memory cgroup path: %v\n", err) os.Exit(254) } limitPath = filepath.Join("/proc/1/root/sys/fs/cgroup/", cgroupPath, "memory.max") fmt.Fprintln(os.Stderr, "limitPath:", limitPath) } else { memCgroupPath, err := v1.GetOwnCgroupPath("memory") if err != nil { fmt.Fprintf(os.Stderr, "Error getting own memory cgroup path: %v\n", err) os.Exit(254) } limitPath = filepath.Join("/proc/1/root/sys/fs/cgroup/memory", memCgroupPath, "memory.limit_in_bytes") fmt.Fprintln(os.Stderr, limitPath) } limit, err := ioutil.ReadFile(limitPath) if err != nil { fmt.Fprintf(os.Stderr, "Can't read %s\n", limitPath) os.Exit(254) } fmt.Printf("Memory Limit: %s\n", string(limit)) } if globalFlags.PrintCPUQuota { cpuCgroupPath, err := v1.GetOwnCgroupPath("cpu") if err != nil { fmt.Fprintf(os.Stderr, "Error getting own cpu cgroup path: %v\n", err) os.Exit(254) } // we use /proc/1/root to escape the chroot we're in and read our // cpu quota periodPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_period_us") periodBytes, err := ioutil.ReadFile(periodPath) if err != nil { fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_period_us\n") os.Exit(254) } quotaPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_quota_us") quotaBytes, err := ioutil.ReadFile(quotaPath) if err != nil { fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_quota_us\n") os.Exit(254) } period, err := strconv.Atoi(strings.Trim(string(periodBytes), "\n")) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } quota, err := strconv.Atoi(strings.Trim(string(quotaBytes), "\n")) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } quotaMilliCores := quota * 1000 / period fmt.Printf("CPU Quota: %s\n", strconv.Itoa(quotaMilliCores)) } if globalFlags.PrintCPUShares { cpuCgroupPath, err := v1.GetOwnCgroupPath("cpu") if err != nil { fmt.Fprintf(os.Stderr, "Error getting own cpu cgroup path: %v\n", err) os.Exit(1) } // we use /proc/1/root to escape the chroot we're in and read our // cpu quota sharesPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.shares") sharesBytes, err := ioutil.ReadFile(sharesPath) if err != nil { fmt.Fprintf(os.Stderr, "Can't read cpu.shares\n") os.Exit(1) } fmt.Printf("CPU Shares: %s", string(sharesBytes)) } if globalFlags.CheckCgroupMounts { rootCgroupPath := "/proc/1/root/sys/fs/cgroup" testPaths := []string{rootCgroupPath} // test a couple of controllers if they're available if _, err := os.Stat(filepath.Join(rootCgroupPath, "memory")); err == nil { testPaths = append(testPaths, filepath.Join(rootCgroupPath, "memory")) } if _, err := os.Stat(filepath.Join(rootCgroupPath, "cpu")); err == nil { testPaths = append(testPaths, filepath.Join(rootCgroupPath, "cpu")) } for _, p := range testPaths { if err := syscall.Mkdir(filepath.Join(p, "test"), 0600); err == nil || err != syscall.EROFS { fmt.Fprintf(os.Stderr, "check-cgroups: FAIL (%v)", err) os.Exit(254) } } fmt.Println("check-cgroups: SUCCESS") } if globalFlags.PrintNetNS { ns, err := os.Readlink("/proc/self/ns/net") if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } fmt.Printf("NetNS: %s\n", ns) } if globalFlags.PrintIPv4 != "" { iface := globalFlags.PrintIPv4 ips, err := testutils.GetIPsv4(iface) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } if len(ips) == 0 { fmt.Fprintf(os.Stderr, "No IPv4 found for interface %+v:\n", iface) os.Exit(254) } fmt.Printf("%v IPv4: %s\n", iface, ips[0]) } if globalFlags.PrintDefaultGWv4 { gw, err := testutils.GetDefaultGWv4() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("DefaultGWv4: %s\n", gw) } if globalFlags.PrintDefaultGWv6 { gw, err := testutils.GetDefaultGWv6() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("DefaultGWv6: %s\n", gw) } if globalFlags.PrintGWv4 != "" { // TODO: GetGW not implemented yet iface := globalFlags.PrintGWv4 gw, err := testutils.GetGWv4(iface) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("%v GWv4: %s\n", iface, gw) } if globalFlags.PrintIPv6 != "" { // TODO } if globalFlags.PrintGWv6 != "" { // TODO } if globalFlags.PrintHostname { hostname, err := os.Hostname() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("Hostname: %s\n", hostname) } if globalFlags.ServeHTTP != "" { err := testutils.HTTPServe(globalFlags.ServeHTTP, globalFlags.ServeHTTPTimeout) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } } if globalFlags.GetHTTP != "" { body, err := testutils.HTTPGet(globalFlags.GetHTTP) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("HTTP-Get received: %s\n", body) } if globalFlags.PrintIfaceCount { ifaceCount, err := testutils.GetIfaceCount() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("Interface count: %d\n", ifaceCount) } if globalFlags.PrintAppAnnotation != "" { mdsUrl, appName := os.Getenv("AC_METADATA_URL"), os.Getenv("AC_APP_NAME") body, err := testutils.HTTPGet(fmt.Sprintf("%s/acMetadata/v1/apps/%s/annotations/%s", mdsUrl, appName, globalFlags.PrintAppAnnotation)) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } fmt.Printf("Annotation %s=%s\n", globalFlags.PrintAppAnnotation, body) } if globalFlags.CheckMountNS { appMountNS, err := os.Readlink("/proc/self/ns/mnt") if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } s1MountNS, err := os.Readlink("/proc/1/ns/mnt") if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(254) } if appMountNS != s1MountNS { fmt.Println("check-mountns: DIFFERENT") } else { fmt.Println("check-mountns: IDENTICAL") os.Exit(254) } } if globalFlags.Sleep >= 0 { time.Sleep(time.Duration(globalFlags.Sleep) * time.Second) } os.Exit(globalFlags.ExitCode) }