engine.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package control
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "golang.org/x/net/context"
  7. "github.com/codegangsta/cli"
  8. "github.com/docker/docker/reference"
  9. "github.com/docker/libcompose/project/options"
  10. "github.com/rancher/os/cmd/control/service"
  11. "github.com/rancher/os/compose"
  12. "github.com/rancher/os/config"
  13. "github.com/rancher/os/docker"
  14. "github.com/rancher/os/log"
  15. "github.com/rancher/os/util"
  16. "github.com/rancher/os/util/network"
  17. )
  18. func engineSubcommands() []cli.Command {
  19. return []cli.Command{
  20. {
  21. Name: "switch",
  22. Usage: "switch Docker engine without a reboot",
  23. Action: engineSwitch,
  24. Flags: []cli.Flag{
  25. cli.BoolFlag{
  26. Name: "force, f",
  27. Usage: "do not prompt for input",
  28. },
  29. cli.BoolFlag{
  30. Name: "no-pull",
  31. Usage: "don't pull console image",
  32. },
  33. },
  34. },
  35. {
  36. Name: "enable",
  37. Usage: "set Docker engine to be switched on next reboot",
  38. Action: engineEnable,
  39. },
  40. {
  41. Name: "list",
  42. Usage: "list available Docker engines",
  43. Action: engineList,
  44. },
  45. }
  46. }
  47. func engineSwitch(c *cli.Context) error {
  48. if len(c.Args()) != 1 {
  49. log.Fatal("Must specify exactly one Docker engine to switch to")
  50. }
  51. newEngine := c.Args()[0]
  52. cfg := config.LoadConfig()
  53. validateEngine(newEngine, cfg)
  54. project, err := compose.GetProject(cfg, true, false)
  55. if err != nil {
  56. log.Fatal(err)
  57. }
  58. if err = project.Stop(context.Background(), 10, "docker"); err != nil {
  59. log.Fatal(err)
  60. }
  61. if err = compose.LoadSpecialService(project, cfg, "docker", newEngine); err != nil {
  62. log.Fatal(err)
  63. }
  64. if err = project.Up(context.Background(), options.Up{}, "docker"); err != nil {
  65. log.Fatal(err)
  66. }
  67. if err := config.Set("rancher.docker.engine", newEngine); err != nil {
  68. log.Errorf("Failed to update rancher.docker.engine: %v", err)
  69. }
  70. return nil
  71. }
  72. func engineEnable(c *cli.Context) error {
  73. if len(c.Args()) != 1 {
  74. log.Fatal("Must specify exactly one Docker engine to enable")
  75. }
  76. newEngine := c.Args()[0]
  77. cfg := config.LoadConfig()
  78. validateEngine(newEngine, cfg)
  79. if err := compose.StageServices(cfg, newEngine); err != nil {
  80. return err
  81. }
  82. if err := config.Set("rancher.docker.engine", newEngine); err != nil {
  83. log.Errorf("Failed to update 'rancher.docker.engine': %v", err)
  84. }
  85. return nil
  86. }
  87. func engineList(c *cli.Context) error {
  88. cfg := config.LoadConfig()
  89. engines := availableEngines(cfg)
  90. currentEngine := CurrentEngine()
  91. for _, engine := range engines {
  92. if engine == currentEngine {
  93. fmt.Printf("current %s\n", engine)
  94. } else if engine == cfg.Rancher.Docker.Engine {
  95. fmt.Printf("enabled %s\n", engine)
  96. } else {
  97. fmt.Printf("disabled %s\n", engine)
  98. }
  99. }
  100. return nil
  101. }
  102. func validateEngine(engine string, cfg *config.CloudConfig) {
  103. engines := availableEngines(cfg)
  104. if !service.IsLocalOrURL(engine) && !util.Contains(engines, engine) {
  105. log.Fatalf("%s is not a valid engine", engine)
  106. }
  107. }
  108. func availableEngines(cfg *config.CloudConfig) []string {
  109. engines, err := network.GetEngines(cfg.Rancher.Repositories.ToArray())
  110. if err != nil {
  111. log.Fatal(err)
  112. }
  113. sort.Strings(engines)
  114. return engines
  115. }
  116. // CurrentEngine gets the name of the docker that's running
  117. func CurrentEngine() (engine string) {
  118. // sudo system-docker inspect --format "{{.Config.Image}}" docker
  119. client, err := docker.NewSystemClient()
  120. if err != nil {
  121. log.Warnf("Failed to detect current docker: %v", err)
  122. return
  123. }
  124. info, err := client.ContainerInspect(context.Background(), "docker")
  125. if err != nil {
  126. log.Warnf("Failed to detect current docker: %v", err)
  127. return
  128. }
  129. // parse image name, then remove os- prefix and the engine suffix
  130. image, err := reference.ParseNamed(info.Config.Image)
  131. if err != nil {
  132. log.Warnf("Failed to detect current docker(%s): %v", info.Config.Image, err)
  133. return
  134. }
  135. if t, ok := image.(reference.NamedTagged); ok {
  136. tag := t.Tag()
  137. if !strings.HasPrefix(tag, "1.") {
  138. // TODO: this assumes we only do Docker ce :/
  139. tag = tag + "-ce"
  140. }
  141. return "docker-" + tag
  142. }
  143. return
  144. }