github.com/skippbox/kompose-origin@v0.0.0-20160524133224-16a9dca7bac2/cli/app/app.go (about) 1 package app 2 3 import ( 4 "fmt" 5 "os" 6 "os/signal" 7 "strconv" 8 "strings" 9 "syscall" 10 11 "golang.org/x/net/context" 12 13 "github.com/Sirupsen/logrus" 14 "github.com/codegangsta/cli" 15 "github.com/docker/libcompose/project" 16 "github.com/docker/libcompose/project/options" 17 ) 18 19 // ProjectAction is an adapter to allow the use of ordinary functions as libcompose actions. 20 // Any function that has the appropriate signature can be register as an action on a codegansta/cli command. 21 // 22 // cli.Command{ 23 // Name: "ps", 24 // Usage: "List containers", 25 // Action: app.WithProject(factory, app.ProjectPs), 26 // } 27 type ProjectAction func(project project.APIProject, c *cli.Context) error 28 29 // BeforeApp is an action that is executed before any cli command. 30 func BeforeApp(c *cli.Context) error { 31 if c.GlobalBool("verbose") { 32 logrus.SetLevel(logrus.DebugLevel) 33 } 34 logrus.Warning("Note: This is an experimental alternate implementation of the Compose CLI (https://github.com/docker/compose)") 35 return nil 36 } 37 38 // WithProject is a helper function to create a cli.Command action with a ProjectFactory. 39 func WithProject(factory ProjectFactory, action ProjectAction) func(context *cli.Context) error { 40 return func(context *cli.Context) error { 41 p, err := factory.Create(context) 42 if err != nil { 43 logrus.Fatalf("Failed to read project: %v", err) 44 } 45 return action(p, context) 46 } 47 } 48 49 // ProjectPs lists the containers. 50 func ProjectPs(p project.APIProject, c *cli.Context) error { 51 qFlag := c.Bool("q") 52 allInfo, err := p.Ps(context.Background(), qFlag, c.Args()...) 53 if err != nil { 54 return cli.NewExitError(err.Error(), 1) 55 } 56 os.Stdout.WriteString(allInfo.String(!qFlag)) 57 return nil 58 } 59 60 // ProjectPort prints the public port for a port binding. 61 func ProjectPort(p project.APIProject, c *cli.Context) error { 62 if len(c.Args()) != 2 { 63 return cli.NewExitError("Please pass arguments in the form: SERVICE PORT", 1) 64 } 65 66 index := c.Int("index") 67 protocol := c.String("protocol") 68 serviceName := c.Args()[0] 69 privatePort := c.Args()[1] 70 71 port, err := p.Port(context.Background(), index, protocol, serviceName, privatePort) 72 if err != nil { 73 return cli.NewExitError(err.Error(), 1) 74 } 75 fmt.Println(port) 76 return nil 77 } 78 79 // ProjectStop stops all services. 80 func ProjectStop(p project.APIProject, c *cli.Context) error { 81 err := p.Stop(context.Background(), c.Int("timeout"), c.Args()...) 82 if err != nil { 83 return cli.NewExitError(err.Error(), 1) 84 } 85 return nil 86 } 87 88 // ProjectDown brings all services down (stops and clean containers). 89 func ProjectDown(p project.APIProject, c *cli.Context) error { 90 options := options.Down{ 91 RemoveVolume: c.Bool("volumes"), 92 RemoveImages: options.ImageType(c.String("rmi")), 93 RemoveOrphans: c.Bool("remove-orphans"), 94 } 95 err := p.Down(context.Background(), options, c.Args()...) 96 if err != nil { 97 return cli.NewExitError(err.Error(), 1) 98 } 99 return nil 100 } 101 102 // ProjectBuild builds or rebuilds services. 103 func ProjectBuild(p project.APIProject, c *cli.Context) error { 104 config := options.Build{ 105 NoCache: c.Bool("no-cache"), 106 ForceRemove: c.Bool("force-rm"), 107 Pull: c.Bool("pull"), 108 } 109 err := p.Build(context.Background(), config, c.Args()...) 110 if err != nil { 111 return cli.NewExitError(err.Error(), 1) 112 } 113 return nil 114 } 115 116 // ProjectCreate creates all services but do not start them. 117 func ProjectCreate(p project.APIProject, c *cli.Context) error { 118 options := options.Create{ 119 NoRecreate: c.Bool("no-recreate"), 120 ForceRecreate: c.Bool("force-recreate"), 121 NoBuild: c.Bool("no-build"), 122 } 123 err := p.Create(context.Background(), options, c.Args()...) 124 if err != nil { 125 return cli.NewExitError(err.Error(), 1) 126 } 127 return nil 128 } 129 130 // ProjectUp brings all services up. 131 func ProjectUp(p project.APIProject, c *cli.Context) error { 132 options := options.Up{ 133 Create: options.Create{ 134 NoRecreate: c.Bool("no-recreate"), 135 ForceRecreate: c.Bool("force-recreate"), 136 NoBuild: c.Bool("no-build"), 137 }, 138 } 139 ctx, cancelFun := context.WithCancel(context.Background()) 140 err := p.Up(ctx, options, c.Args()...) 141 if err != nil { 142 return cli.NewExitError(err.Error(), 1) 143 } 144 if !c.Bool("d") { 145 signalChan := make(chan os.Signal, 1) 146 cleanupDone := make(chan bool) 147 signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) 148 errChan := make(chan error) 149 go func() { 150 errChan <- p.Log(ctx, true, c.Args()...) 151 }() 152 go func() { 153 select { 154 case <-signalChan: 155 fmt.Printf("\nGracefully stopping...\n") 156 cancelFun() 157 ProjectStop(p, c) 158 cleanupDone <- true 159 case err := <-errChan: 160 if err != nil { 161 logrus.Fatal(err) 162 } 163 cleanupDone <- true 164 } 165 }() 166 <-cleanupDone 167 return nil 168 } 169 return nil 170 } 171 172 // ProjectRun runs a given command within a service's container. 173 func ProjectRun(p project.APIProject, c *cli.Context) error { 174 if len(c.Args()) == 1 { 175 logrus.Fatal("No service specified") 176 } 177 178 serviceName := c.Args()[0] 179 commandParts := c.Args()[1:] 180 181 exitCode, err := p.Run(context.Background(), serviceName, commandParts) 182 if err != nil { 183 return cli.NewExitError(err.Error(), 1) 184 } 185 return cli.NewExitError("", exitCode) 186 } 187 188 // ProjectStart starts services. 189 func ProjectStart(p project.APIProject, c *cli.Context) error { 190 err := p.Start(context.Background(), c.Args()...) 191 if err != nil { 192 return cli.NewExitError(err.Error(), 1) 193 } 194 return nil 195 } 196 197 // ProjectRestart restarts services. 198 func ProjectRestart(p project.APIProject, c *cli.Context) error { 199 err := p.Restart(context.Background(), c.Int("timeout"), c.Args()...) 200 if err != nil { 201 return cli.NewExitError(err.Error(), 1) 202 } 203 return nil 204 } 205 206 // ProjectLog gets services logs. 207 func ProjectLog(p project.APIProject, c *cli.Context) error { 208 err := p.Log(context.Background(), c.Bool("follow"), c.Args()...) 209 if err != nil { 210 return cli.NewExitError(err.Error(), 1) 211 } 212 return nil 213 } 214 215 // ProjectPull pulls images for services. 216 func ProjectPull(p project.APIProject, c *cli.Context) error { 217 err := p.Pull(context.Background(), c.Args()...) 218 if err != nil && !c.Bool("ignore-pull-failures") { 219 return cli.NewExitError(err.Error(), 1) 220 } 221 return nil 222 } 223 224 // ProjectDelete deletes services. 225 func ProjectDelete(p project.APIProject, c *cli.Context) error { 226 options := options.Delete{ 227 RemoveVolume: c.Bool("v"), 228 } 229 if !c.Bool("force") { 230 options.BeforeDeleteCallback = func(stoppedContainers []string) bool { 231 fmt.Printf("Going to remove %v\nAre you sure? [yN]\n", strings.Join(stoppedContainers, ", ")) 232 var answer string 233 _, err := fmt.Scanln(&answer) 234 if err != nil { 235 logrus.Error(err) 236 return false 237 } 238 if answer != "y" && answer != "Y" { 239 return false 240 } 241 return true 242 } 243 } 244 err := p.Delete(context.Background(), options, c.Args()...) 245 if err != nil { 246 return cli.NewExitError(err.Error(), 1) 247 } 248 return nil 249 } 250 251 // ProjectKill forces stop service containers. 252 func ProjectKill(p project.APIProject, c *cli.Context) error { 253 err := p.Kill(context.Background(), c.String("signal"), c.Args()...) 254 if err != nil { 255 return cli.NewExitError(err.Error(), 1) 256 } 257 return nil 258 } 259 260 // ProjectPause pauses service containers. 261 func ProjectPause(p project.APIProject, c *cli.Context) error { 262 err := p.Pause(context.Background(), c.Args()...) 263 if err != nil { 264 return cli.NewExitError(err.Error(), 1) 265 } 266 return nil 267 } 268 269 // ProjectUnpause unpauses service containers. 270 func ProjectUnpause(p project.APIProject, c *cli.Context) error { 271 err := p.Unpause(context.Background(), c.Args()...) 272 if err != nil { 273 return cli.NewExitError(err.Error(), 1) 274 } 275 return nil 276 } 277 278 // ProjectScale scales services. 279 func ProjectScale(p project.APIProject, c *cli.Context) error { 280 servicesScale := map[string]int{} 281 for _, arg := range c.Args() { 282 kv := strings.SplitN(arg, "=", 2) 283 if len(kv) != 2 { 284 return cli.NewExitError(fmt.Sprintf("Invalid scale parameter: %s", arg), 2) 285 } 286 287 name := kv[0] 288 289 count, err := strconv.Atoi(kv[1]) 290 if err != nil { 291 return cli.NewExitError(fmt.Sprintf("Invalid scale parameter: %v", err), 2) 292 } 293 294 servicesScale[name] = count 295 } 296 297 err := p.Scale(context.Background(), c.Int("timeout"), servicesScale) 298 if err != nil { 299 return cli.NewExitError(err.Error(), 1) 300 } 301 return nil 302 }