github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/tests/inspect/inspect.go (about) 1 // Copyright 2015 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "bufio" 19 "bytes" 20 "flag" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "sort" 26 "strconv" 27 "strings" 28 "syscall" 29 "time" 30 "unsafe" 31 32 "github.com/coreos/rkt/Godeps/_workspace/src/github.com/syndtr/gocapability/capability" 33 "github.com/coreos/rkt/common/cgroup" 34 "github.com/coreos/rkt/tests/testutils" 35 ) 36 37 var ( 38 globalFlagset = flag.NewFlagSet("inspect", flag.ExitOnError) 39 globalFlags = struct { 40 ReadStdin bool 41 CheckTty bool 42 PrintExec bool 43 PrintMsg string 44 PrintEnv string 45 PrintCapsPid int 46 PrintUser bool 47 PrintGroups bool 48 CheckCwd string 49 ExitCode int 50 ReadFile bool 51 WriteFile bool 52 StatFile bool 53 Sleep int 54 PreSleep int 55 PrintMemoryLimit bool 56 PrintCPUQuota bool 57 FileName string 58 Content string 59 CheckCgroupMounts bool 60 PrintNetNS bool 61 PrintIPv4 string 62 PrintIPv6 string 63 PrintDefaultGWv4 bool 64 PrintDefaultGWv6 bool 65 PrintGWv4 string 66 PrintGWv6 string 67 GetHttp string 68 ServeHttp string 69 ServeHttpTimeout int 70 PrintIfaceCount bool 71 }{} 72 ) 73 74 func init() { 75 globalFlagset.BoolVar(&globalFlags.ReadStdin, "read-stdin", false, "Read a line from stdin") 76 globalFlagset.BoolVar(&globalFlags.CheckTty, "check-tty", false, "Check if stdin is a terminal") 77 globalFlagset.BoolVar(&globalFlags.PrintExec, "print-exec", false, "Print the command we were execed as (i.e. argv[0])") 78 globalFlagset.StringVar(&globalFlags.PrintMsg, "print-msg", "", "Print the message given as parameter") 79 globalFlagset.StringVar(&globalFlags.CheckCwd, "check-cwd", "", "Check if the current working directory is the one specified") 80 globalFlagset.StringVar(&globalFlags.PrintEnv, "print-env", "", "Print the specified environment variable") 81 globalFlagset.IntVar(&globalFlags.PrintCapsPid, "print-caps-pid", -1, "Print capabilities of the specified pid (or current process if pid=0)") 82 globalFlagset.BoolVar(&globalFlags.PrintUser, "print-user", false, "Print uid and gid") 83 globalFlagset.BoolVar(&globalFlags.PrintGroups, "print-groups", false, "Print all gids") 84 globalFlagset.IntVar(&globalFlags.ExitCode, "exit-code", 0, "Return this exit code") 85 globalFlagset.BoolVar(&globalFlags.ReadFile, "read-file", false, "Print the content of the file $FILE") 86 globalFlagset.BoolVar(&globalFlags.WriteFile, "write-file", false, "Write $CONTENT in the file $FILE") 87 globalFlagset.BoolVar(&globalFlags.StatFile, "stat-file", false, "Print the ownership and mode of the file $FILE") 88 globalFlagset.IntVar(&globalFlags.Sleep, "sleep", -1, "Sleep before exiting (in seconds)") 89 globalFlagset.IntVar(&globalFlags.PreSleep, "pre-sleep", -1, "Sleep before executing (in seconds)") 90 globalFlagset.BoolVar(&globalFlags.PrintMemoryLimit, "print-memorylimit", false, "Print cgroup memory limit") 91 globalFlagset.BoolVar(&globalFlags.PrintCPUQuota, "print-cpuquota", false, "Print cgroup cpu quota in milli-cores") 92 globalFlagset.StringVar(&globalFlags.FileName, "file-name", "", "The file to read/write, $FILE will be ignored if this is specified") 93 globalFlagset.StringVar(&globalFlags.Content, "content", "", "The content to write, $CONTENT will be ignored if this is specified") 94 globalFlagset.BoolVar(&globalFlags.CheckCgroupMounts, "check-cgroups", false, "Try to write to the cgroup filesystem. Everything should be RO except some well-known files") 95 globalFlagset.BoolVar(&globalFlags.PrintNetNS, "print-netns", false, "Print the network namespace") 96 globalFlagset.StringVar(&globalFlags.PrintIPv4, "print-ipv4", "", "Takes an interface name and prints its IPv4") 97 globalFlagset.StringVar(&globalFlags.PrintIPv6, "print-ipv6", "", "Takes an interface name and prints its IPv6") 98 globalFlagset.BoolVar(&globalFlags.PrintDefaultGWv4, "print-defaultgwv4", false, "Print the default IPv4 gateway") 99 globalFlagset.BoolVar(&globalFlags.PrintDefaultGWv6, "print-defaultgwv6", false, "Print the default IPv6 gateway") 100 globalFlagset.StringVar(&globalFlags.PrintGWv4, "print-gwv4", "", "Takes an interface name and prints its gateway's IPv4") 101 globalFlagset.StringVar(&globalFlags.PrintGWv6, "print-gwv6", "", "Takes an interface name and prints its gateway's IPv6") 102 globalFlagset.StringVar(&globalFlags.GetHttp, "get-http", "", "HTTP-Get from the given address") 103 globalFlagset.StringVar(&globalFlags.ServeHttp, "serve-http", "", "Serve the hostname via HTTP on the given address:port") 104 globalFlagset.IntVar(&globalFlags.ServeHttpTimeout, "serve-http-timeout", 30, "HTTP Timeout to wait for a client connection") 105 globalFlagset.BoolVar(&globalFlags.PrintIfaceCount, "print-iface-count", false, "Print the interface count") 106 } 107 108 func in(list []int, el int) bool { 109 for _, x := range list { 110 if el == x { 111 return true 112 } 113 } 114 return false 115 } 116 117 func main() { 118 globalFlagset.Parse(os.Args[1:]) 119 args := globalFlagset.Args() 120 if len(args) > 0 { 121 fmt.Fprintln(os.Stderr, "Wrong parameters") 122 os.Exit(1) 123 } 124 125 if globalFlags.PreSleep >= 0 { 126 time.Sleep(time.Duration(globalFlags.PreSleep) * time.Second) 127 } 128 129 if globalFlags.ReadStdin { 130 reader := bufio.NewReader(os.Stdin) 131 fmt.Printf("Enter text:\n") 132 text, _ := reader.ReadString('\n') 133 fmt.Printf("Received text: %s\n", text) 134 } 135 136 if globalFlags.CheckTty { 137 fd := int(os.Stdin.Fd()) 138 var termios syscall.Termios 139 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 140 if err == 0 { 141 fmt.Printf("stdin is a terminal\n") 142 } else { 143 fmt.Printf("stdin is not a terminal\n") 144 } 145 } 146 147 if globalFlags.PrintExec { 148 fmt.Fprintf(os.Stdout, "inspect execed as: %s\n", os.Args[0]) 149 } 150 151 if globalFlags.PrintMsg != "" { 152 fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg) 153 messageLoopStr := os.Getenv("MESSAGE_LOOP") 154 messageLoop, err := strconv.Atoi(messageLoopStr) 155 if err == nil { 156 for i := 0; i < messageLoop; i++ { 157 time.Sleep(time.Second) 158 fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg) 159 } 160 } 161 } 162 163 if globalFlags.PrintEnv != "" { 164 fmt.Fprintf(os.Stdout, "%s=%s\n", globalFlags.PrintEnv, os.Getenv(globalFlags.PrintEnv)) 165 } 166 167 if globalFlags.PrintCapsPid >= 0 { 168 caps, err := capability.NewPid(globalFlags.PrintCapsPid) 169 if err != nil { 170 fmt.Fprintf(os.Stderr, "Cannot get caps: %v\n", err) 171 os.Exit(1) 172 } 173 fmt.Printf("Capability set: effective: %s\n", caps.StringCap(capability.EFFECTIVE)) 174 fmt.Printf("Capability set: permitted: %s\n", caps.StringCap(capability.PERMITTED)) 175 fmt.Printf("Capability set: inheritable: %s\n", caps.StringCap(capability.INHERITABLE)) 176 fmt.Printf("Capability set: bounding: %s\n", caps.StringCap(capability.BOUNDING)) 177 178 if capStr := os.Getenv("CAPABILITY"); capStr != "" { 179 capInt, err := strconv.Atoi(capStr) 180 if err != nil { 181 fmt.Fprintf(os.Stderr, "Environment variable $CAPABILITY is not a valid capability number: %v\n", err) 182 os.Exit(1) 183 } 184 c := capability.Cap(capInt) 185 if caps.Get(capability.BOUNDING, c) { 186 fmt.Printf("%v=enabled\n", c.String()) 187 } else { 188 fmt.Printf("%v=disabled\n", c.String()) 189 } 190 } 191 } 192 193 if globalFlags.PrintUser { 194 fmt.Printf("User: uid=%d euid=%d gid=%d egid=%d\n", os.Getuid(), os.Geteuid(), os.Getgid(), os.Getegid()) 195 } 196 197 if globalFlags.PrintGroups { 198 gids, err := os.Getgroups() 199 if err != nil { 200 fmt.Fprintf(os.Stderr, "Error getting groups: %v\n", err) 201 os.Exit(1) 202 } 203 // getgroups(2): It is unspecified whether the effective group ID of 204 // the calling process is included in the returned list. (Thus, an 205 // application should also call getegid(2) and add or remove the 206 // resulting value.) 207 egid := os.Getegid() 208 if !in(gids, egid) { 209 gids = append(gids, egid) 210 sort.Ints(gids) 211 } 212 var b bytes.Buffer 213 for _, gid := range gids { 214 b.WriteString(fmt.Sprintf("%d ", gid)) 215 } 216 fmt.Printf("Groups: %s\n", b.String()) 217 } 218 219 if globalFlags.WriteFile { 220 fileName := os.Getenv("FILE") 221 if globalFlags.FileName != "" { 222 fileName = globalFlags.FileName 223 } 224 content := os.Getenv("CONTENT") 225 if globalFlags.Content != "" { 226 content = globalFlags.Content 227 } 228 229 err := ioutil.WriteFile(fileName, []byte(content), 0600) 230 if err != nil { 231 fmt.Fprintf(os.Stderr, "Cannot write to file %q: %v\n", fileName, err) 232 os.Exit(1) 233 } 234 } 235 236 if globalFlags.ReadFile { 237 fileName := os.Getenv("FILE") 238 if globalFlags.FileName != "" { 239 fileName = globalFlags.FileName 240 } 241 242 dat, err := ioutil.ReadFile(fileName) 243 if err != nil { 244 fmt.Fprintf(os.Stderr, "Cannot read file %q: %v\n", fileName, err) 245 os.Exit(1) 246 } 247 fmt.Print("<<<") 248 fmt.Print(string(dat)) 249 fmt.Print(">>>\n") 250 } 251 252 if globalFlags.StatFile { 253 fileName := os.Getenv("FILE") 254 if globalFlags.FileName != "" { 255 fileName = globalFlags.FileName 256 } 257 258 fi, err := os.Stat(fileName) 259 if err != nil { 260 fmt.Fprintf(os.Stderr, "Cannot stat file %q: %v\n", fileName, err) 261 os.Exit(1) 262 } 263 fmt.Printf("%s: mode: %s\n", fileName, fi.Mode().String()) 264 fmt.Printf("%s: user: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Uid) 265 fmt.Printf("%s: group: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Gid) 266 } 267 268 if globalFlags.CheckCwd != "" { 269 wd, err := os.Getwd() 270 if err != nil { 271 fmt.Fprintf(os.Stderr, "Cannot get working directory: %v\n", err) 272 os.Exit(1) 273 } 274 if wd != globalFlags.CheckCwd { 275 fmt.Fprintf(os.Stderr, "Working directory: %q. Expected: %q.\n", wd, globalFlags.CheckCwd) 276 os.Exit(1) 277 } 278 } 279 280 if globalFlags.Sleep >= 0 { 281 time.Sleep(time.Duration(globalFlags.Sleep) * time.Second) 282 } 283 284 if globalFlags.PrintMemoryLimit { 285 memCgroupPath, err := cgroup.GetOwnCgroupPath("memory") 286 if err != nil { 287 fmt.Fprintf(os.Stderr, "Error getting own memory cgroup path: %v\n", err) 288 os.Exit(1) 289 } 290 // we use /proc/1/root to escape the chroot we're in and read our 291 // memory limit 292 limitPath := filepath.Join("/proc/1/root/sys/fs/cgroup/memory", memCgroupPath, "memory.limit_in_bytes") 293 limit, err := ioutil.ReadFile(limitPath) 294 if err != nil { 295 fmt.Fprintf(os.Stderr, "Can't read memory.limit_in_bytes\n") 296 os.Exit(1) 297 } 298 299 fmt.Printf("Memory Limit: %s\n", string(limit)) 300 } 301 302 if globalFlags.PrintCPUQuota { 303 cpuCgroupPath, err := cgroup.GetOwnCgroupPath("cpu") 304 if err != nil { 305 fmt.Fprintf(os.Stderr, "Error getting own cpu cgroup path: %v\n", err) 306 os.Exit(1) 307 } 308 // we use /proc/1/root to escape the chroot we're in and read our 309 // cpu quota 310 periodPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_period_us") 311 periodBytes, err := ioutil.ReadFile(periodPath) 312 if err != nil { 313 fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_period_us\n") 314 os.Exit(1) 315 } 316 quotaPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_quota_us") 317 quotaBytes, err := ioutil.ReadFile(quotaPath) 318 if err != nil { 319 fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_quota_us\n") 320 os.Exit(1) 321 } 322 323 period, err := strconv.Atoi(strings.Trim(string(periodBytes), "\n")) 324 if err != nil { 325 fmt.Fprintf(os.Stderr, "%v\n", err) 326 os.Exit(1) 327 } 328 quota, err := strconv.Atoi(strings.Trim(string(quotaBytes), "\n")) 329 if err != nil { 330 fmt.Fprintf(os.Stderr, "%v\n", err) 331 os.Exit(1) 332 } 333 334 quotaMilliCores := quota * 1000 / period 335 fmt.Printf("CPU Quota: %s\n", strconv.Itoa(quotaMilliCores)) 336 } 337 338 if globalFlags.CheckCgroupMounts { 339 rootCgroupPath := "/proc/1/root/sys/fs/cgroup" 340 testPaths := []string{rootCgroupPath} 341 342 // test a couple of controllers if they're available 343 if cgroup.IsIsolatorSupported("memory") { 344 testPaths = append(testPaths, filepath.Join(rootCgroupPath, "memory")) 345 } 346 if cgroup.IsIsolatorSupported("cpu") { 347 testPaths = append(testPaths, filepath.Join(rootCgroupPath, "cpu")) 348 } 349 350 for _, p := range testPaths { 351 if err := syscall.Mkdir(filepath.Join(p, "test"), 0600); err == nil || err != syscall.EROFS { 352 fmt.Println("check-cgroups: FAIL") 353 os.Exit(1) 354 } 355 } 356 357 fmt.Println("check-cgroups: SUCCESS") 358 } 359 360 if globalFlags.PrintNetNS { 361 ns, err := os.Readlink("/proc/self/ns/net") 362 if err != nil { 363 fmt.Fprintf(os.Stderr, "%v\n", err) 364 os.Exit(1) 365 } 366 fmt.Printf("NetNS: %s\n", ns) 367 } 368 369 if globalFlags.PrintIPv4 != "" { 370 iface := globalFlags.PrintIPv4 371 ips, err := testutils.GetIPsv4(iface) 372 if err != nil { 373 fmt.Fprintf(os.Stderr, "%v\n", err) 374 os.Exit(1) 375 } 376 fmt.Printf("%v IPv4: %s\n", iface, ips[0]) 377 } 378 379 if globalFlags.PrintDefaultGWv4 { 380 gw, err := testutils.GetDefaultGWv4() 381 if err != nil { 382 fmt.Fprintf(os.Stderr, "%v\n", err) 383 os.Exit(1) 384 } 385 fmt.Printf("DefaultGWv4: %s\n", gw) 386 } 387 388 if globalFlags.PrintDefaultGWv6 { 389 gw, err := testutils.GetDefaultGWv6() 390 if err != nil { 391 fmt.Fprintf(os.Stderr, "%v\n", err) 392 os.Exit(1) 393 } 394 fmt.Printf("DefaultGWv6: %s\n", gw) 395 } 396 397 if globalFlags.PrintGWv4 != "" { 398 // TODO: GetGW not implemented yet 399 iface := globalFlags.PrintGWv4 400 gw, err := testutils.GetGWv4(iface) 401 if err != nil { 402 fmt.Fprintf(os.Stderr, "%v\n", err) 403 os.Exit(1) 404 } 405 fmt.Printf("%v GWv4: %s\n", iface, gw) 406 } 407 408 if globalFlags.PrintIPv6 != "" { 409 // TODO 410 } 411 412 if globalFlags.PrintGWv6 != "" { 413 // TODO 414 } 415 416 if globalFlags.ServeHttp != "" { 417 err := testutils.HttpServe(globalFlags.ServeHttp, globalFlags.ServeHttpTimeout) 418 if err != nil { 419 fmt.Fprintf(os.Stderr, "%v\n", err) 420 os.Exit(1) 421 } 422 } 423 424 if globalFlags.GetHttp != "" { 425 body, err := testutils.HttpGet(globalFlags.GetHttp) 426 if err != nil { 427 fmt.Fprintf(os.Stderr, "%v\n", err) 428 os.Exit(1) 429 } 430 fmt.Printf("HTTP-Get received: %s\n", body) 431 } 432 433 if globalFlags.PrintIfaceCount { 434 ifaceCount, err := testutils.GetIfaceCount() 435 if err != nil { 436 fmt.Fprintf(os.Stderr, "%v\n", err) 437 os.Exit(1) 438 } 439 fmt.Printf("Interface count: %d\n", ifaceCount) 440 } 441 442 os.Exit(globalFlags.ExitCode) 443 }