1
2
3 package main
4
5 import (
6 "fmt"
7 "io"
8 "os"
9 "strings"
10
11 "github.com/Microsoft/go-winio"
12 "github.com/Microsoft/go-winio/pkg/etwlogrus"
13 "github.com/Microsoft/hcsshim/internal/regstate"
14 "github.com/Microsoft/hcsshim/internal/runhcs"
15 "github.com/opencontainers/runtime-spec/specs-go"
16 "github.com/sirupsen/logrus"
17 "github.com/urfave/cli"
18 )
19
20
21
22
23
24
25 var version = ""
26
27
28
29 var gitCommit = ""
30
31 var stateKey *regstate.Key
32
33 var logFormat string
34
35 const (
36 specConfig = "config.json"
37 usage = `Open Container Initiative runtime for Windows
38
39 runhcs is a fork of runc, modified to run containers on Windows with or without Hyper-V isolation. Like runc, it is a command line client for running applications packaged according to the Open Container Initiative (OCI) format.
40
41 runhcs integrates with existing process supervisors to provide a production container runtime environment for applications. It can be used with your existing process monitoring tools and the container will be spawned as a direct child of the process supervisor.
42
43 Containers are configured using bundles. A bundle for a container is a directory that includes a specification file named "` + specConfig + `". Bundle contents will depend on the container type.
44
45 To start a new instance of a container:
46
47 # runhcs run [ -b bundle ] <container-id>
48
49 Where "<container-id>" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host. Providing the bundle directory using "-b" is optional. The default value for "bundle" is the current directory.`
50 )
51
52 func main() {
53
54
55 if hook, err := etwlogrus.NewHook("Microsoft.Virtualization.RunHCS"); err == nil {
56 logrus.AddHook(hook)
57 } else {
58 logrus.Error(err)
59 }
60
61 app := cli.NewApp()
62 app.Name = "runhcs"
63 app.Usage = usage
64
65 var v []string
66 if version != "" {
67 v = append(v, version)
68 }
69 if gitCommit != "" {
70 v = append(v, fmt.Sprintf("commit: %s", gitCommit))
71 }
72 v = append(v, fmt.Sprintf("spec: %s", specs.Version))
73 app.Version = strings.Join(v, "\n")
74
75 app.Flags = []cli.Flag{
76 cli.BoolFlag{
77 Name: "debug",
78 Usage: "enable debug output for logging",
79 },
80 cli.StringFlag{
81 Name: "log",
82 Value: "nul",
83 Usage: `set the log file path or named pipe (e.g. \\.\pipe\ProtectedPrefix\Administrators\runhcs-log) where internal debug information is written`,
84 },
85 cli.StringFlag{
86 Name: "log-format",
87 Value: "text",
88 Usage: "set the format used by logs ('text' (default), or 'json')",
89 },
90 cli.StringFlag{
91 Name: "owner",
92 Value: "runhcs",
93 Usage: "compute system owner",
94 },
95 cli.StringFlag{
96 Name: "root",
97 Value: "default",
98 Usage: "registry key for storage of container state",
99 },
100 }
101 app.Commands = []cli.Command{
102 createCommand,
103 createScratchCommand,
104 deleteCommand,
105
106 execCommand,
107 killCommand,
108 listCommand,
109 pauseCommand,
110 prepareDiskCommand,
111 psCommand,
112 resizeTtyCommand,
113 resumeCommand,
114 runCommand,
115 shimCommand,
116 startCommand,
117 stateCommand,
118
119 vmshimCommand,
120 }
121 app.Before = func(context *cli.Context) error {
122 if context.GlobalBool("debug") {
123 logrus.SetLevel(logrus.DebugLevel)
124 }
125 if path := context.GlobalString("log"); path != "" {
126 var f io.Writer
127 var err error
128 if strings.HasPrefix(path, runhcs.SafePipePrefix) {
129 f, err = winio.DialPipe(path, nil)
130 } else {
131 f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
132 }
133 if err != nil {
134 return err
135 }
136 logrus.SetOutput(f)
137 }
138 switch logFormat = context.GlobalString("log-format"); logFormat {
139 case "text":
140
141 case "json":
142 logrus.SetFormatter(new(logrus.JSONFormatter))
143 default:
144 return fmt.Errorf("unknown log-format %q", logFormat)
145 }
146
147 var err error
148 stateKey, err = regstate.Open(context.GlobalString("root"), false)
149 if err != nil {
150 return err
151 }
152 return nil
153 }
154
155
156
157 fatalWriter.Writer = cli.ErrWriter
158 cli.ErrWriter = &fatalWriter
159 if err := app.Run(os.Args); err != nil {
160 fmt.Fprintln(cli.ErrWriter, err)
161 os.Exit(1)
162 }
163 }
164
165 type logErrorWriter struct {
166 Writer io.Writer
167 }
168
169 var fatalWriter logErrorWriter
170
171 func (f *logErrorWriter) Write(p []byte) (n int, err error) {
172 logrus.Error(string(p))
173 return f.Writer.Write(p)
174 }
175
View as plain text