...

Source file src/github.com/opencontainers/runc/list.go

Documentation: github.com/opencontainers/runc

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"syscall"
    10  	"text/tabwriter"
    11  	"time"
    12  
    13  	"github.com/opencontainers/runc/libcontainer"
    14  	"github.com/opencontainers/runc/libcontainer/user"
    15  	"github.com/opencontainers/runc/libcontainer/utils"
    16  	"github.com/urfave/cli"
    17  )
    18  
    19  const formatOptions = `table or json`
    20  
    21  // containerState represents the platform agnostic pieces relating to a
    22  // running container's status and state
    23  type containerState struct {
    24  	// Version is the OCI version for the container
    25  	Version string `json:"ociVersion"`
    26  	// ID is the container ID
    27  	ID string `json:"id"`
    28  	// InitProcessPid is the init process id in the parent namespace
    29  	InitProcessPid int `json:"pid"`
    30  	// Status is the current status of the container, running, paused, ...
    31  	Status string `json:"status"`
    32  	// Bundle is the path on the filesystem to the bundle
    33  	Bundle string `json:"bundle"`
    34  	// Rootfs is a path to a directory containing the container's root filesystem.
    35  	Rootfs string `json:"rootfs"`
    36  	// Created is the unix timestamp for the creation time of the container in UTC
    37  	Created time.Time `json:"created"`
    38  	// Annotations is the user defined annotations added to the config.
    39  	Annotations map[string]string `json:"annotations,omitempty"`
    40  	// The owner of the state directory (the owner of the container).
    41  	Owner string `json:"owner"`
    42  }
    43  
    44  var listCommand = cli.Command{
    45  	Name:  "list",
    46  	Usage: "lists containers started by runc with the given root",
    47  	ArgsUsage: `
    48  
    49  Where the given root is specified via the global option "--root"
    50  (default: "/run/runc").
    51  
    52  EXAMPLE 1:
    53  To list containers created via the default "--root":
    54         # runc list
    55  
    56  EXAMPLE 2:
    57  To list containers created using a non-default value for "--root":
    58         # runc --root value list`,
    59  	Flags: []cli.Flag{
    60  		cli.StringFlag{
    61  			Name:  "format, f",
    62  			Value: "table",
    63  			Usage: `select one of: ` + formatOptions,
    64  		},
    65  		cli.BoolFlag{
    66  			Name:  "quiet, q",
    67  			Usage: "display only container IDs",
    68  		},
    69  	},
    70  	Action: func(context *cli.Context) error {
    71  		if err := checkArgs(context, 0, exactArgs); err != nil {
    72  			return err
    73  		}
    74  		s, err := getContainers(context)
    75  		if err != nil {
    76  			return err
    77  		}
    78  
    79  		if context.Bool("quiet") {
    80  			for _, item := range s {
    81  				fmt.Println(item.ID)
    82  			}
    83  			return nil
    84  		}
    85  
    86  		switch context.String("format") {
    87  		case "table":
    88  			w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0)
    89  			fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n")
    90  			for _, item := range s {
    91  				fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\n",
    92  					item.ID,
    93  					item.InitProcessPid,
    94  					item.Status,
    95  					item.Bundle,
    96  					item.Created.Format(time.RFC3339Nano),
    97  					item.Owner)
    98  			}
    99  			if err := w.Flush(); err != nil {
   100  				return err
   101  			}
   102  		case "json":
   103  			if err := json.NewEncoder(os.Stdout).Encode(s); err != nil {
   104  				return err
   105  			}
   106  		default:
   107  			return errors.New("invalid format option")
   108  		}
   109  		return nil
   110  	},
   111  }
   112  
   113  func getContainers(context *cli.Context) ([]containerState, error) {
   114  	factory, err := loadFactory(context)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	root := context.GlobalString("root")
   119  	absRoot, err := filepath.Abs(root)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	list, err := os.ReadDir(absRoot)
   124  	if err != nil {
   125  		fatal(err)
   126  	}
   127  
   128  	var s []containerState
   129  	for _, item := range list {
   130  		if item.IsDir() {
   131  			st, err := os.Stat(filepath.Join(absRoot, item.Name()))
   132  			if err != nil {
   133  				fatal(err)
   134  			}
   135  			// This cast is safe on Linux.
   136  			uid := st.Sys().(*syscall.Stat_t).Uid
   137  			owner, err := user.LookupUid(int(uid))
   138  			if err != nil {
   139  				owner.Name = fmt.Sprintf("#%d", uid)
   140  			}
   141  
   142  			container, err := factory.Load(item.Name())
   143  			if err != nil {
   144  				fmt.Fprintf(os.Stderr, "load container %s: %v\n", item.Name(), err)
   145  				continue
   146  			}
   147  			containerStatus, err := container.Status()
   148  			if err != nil {
   149  				fmt.Fprintf(os.Stderr, "status for %s: %v\n", item.Name(), err)
   150  				continue
   151  			}
   152  			state, err := container.State()
   153  			if err != nil {
   154  				fmt.Fprintf(os.Stderr, "state for %s: %v\n", item.Name(), err)
   155  				continue
   156  			}
   157  			pid := state.BaseState.InitProcessPid
   158  			if containerStatus == libcontainer.Stopped {
   159  				pid = 0
   160  			}
   161  			bundle, annotations := utils.Annotations(state.Config.Labels)
   162  			s = append(s, containerState{
   163  				Version:        state.BaseState.Config.Version,
   164  				ID:             state.BaseState.ID,
   165  				InitProcessPid: pid,
   166  				Status:         containerStatus.String(),
   167  				Bundle:         bundle,
   168  				Rootfs:         state.BaseState.Config.Rootfs,
   169  				Created:        state.BaseState.Created,
   170  				Annotations:    annotations,
   171  				Owner:          owner.Name,
   172  			})
   173  		}
   174  	}
   175  	return s, nil
   176  }
   177  

View as plain text