console.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package control
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "sort"
  6. "strings"
  7. "golang.org/x/net/context"
  8. "github.com/codegangsta/cli"
  9. composeConfig "github.com/docker/libcompose/config"
  10. "github.com/docker/libcompose/project/options"
  11. "github.com/rancher/os/cmd/control/service"
  12. "github.com/rancher/os/compose"
  13. "github.com/rancher/os/config"
  14. "github.com/rancher/os/log"
  15. "github.com/rancher/os/util"
  16. "github.com/rancher/os/util/network"
  17. )
  18. func consoleSubcommands() []cli.Command {
  19. return []cli.Command{
  20. {
  21. Name: "switch",
  22. Usage: "switch console without a reboot",
  23. Action: consoleSwitch,
  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 console to be switched on next reboot",
  38. Action: consoleEnable,
  39. },
  40. {
  41. Name: "list",
  42. Usage: "list available consoles",
  43. Action: consoleList,
  44. },
  45. }
  46. }
  47. func consoleSwitch(c *cli.Context) error {
  48. if len(c.Args()) != 1 {
  49. log.Fatal("Must specify exactly one console to switch to")
  50. }
  51. newConsole := c.Args()[0]
  52. cfg := config.LoadConfig()
  53. validateConsole(newConsole, cfg)
  54. if newConsole == currentConsole() {
  55. log.Warnf("Console is already set to %s", newConsole)
  56. }
  57. if !c.Bool("force") {
  58. fmt.Println(`Switching consoles will
  59. 1. destroy the current console container
  60. 2. log you out
  61. 3. restart Docker`)
  62. if !yes("Continue") {
  63. return nil
  64. }
  65. }
  66. if !c.Bool("no-pull") && newConsole != "default" {
  67. if err := compose.StageServices(cfg, newConsole); err != nil {
  68. return err
  69. }
  70. }
  71. service, err := compose.CreateService(nil, "switch-console", &composeConfig.ServiceConfigV1{
  72. LogDriver: "json-file",
  73. Privileged: true,
  74. Net: "host",
  75. Pid: "host",
  76. Image: config.OsBase,
  77. Labels: map[string]string{
  78. config.ScopeLabel: config.System,
  79. },
  80. Command: []string{"/usr/bin/ros", "switch-console", newConsole},
  81. VolumesFrom: []string{"all-volumes"},
  82. })
  83. if err != nil {
  84. return err
  85. }
  86. if err = service.Delete(context.Background(), options.Delete{}); err != nil {
  87. return err
  88. }
  89. if err = service.Up(context.Background(), options.Up{}); err != nil {
  90. return err
  91. }
  92. return service.Log(context.Background(), true)
  93. }
  94. func consoleEnable(c *cli.Context) error {
  95. if len(c.Args()) != 1 {
  96. log.Fatal("Must specify exactly one console to enable")
  97. }
  98. newConsole := c.Args()[0]
  99. cfg := config.LoadConfig()
  100. validateConsole(newConsole, cfg)
  101. if newConsole != "default" {
  102. if err := compose.StageServices(cfg, newConsole); err != nil {
  103. return err
  104. }
  105. }
  106. if err := config.Set("rancher.console", newConsole); err != nil {
  107. log.Errorf("Failed to update 'rancher.console': %v", err)
  108. }
  109. return nil
  110. }
  111. func consoleList(c *cli.Context) error {
  112. cfg := config.LoadConfig()
  113. consoles := availableConsoles(cfg)
  114. currentConsole := currentConsole()
  115. for _, console := range consoles {
  116. if console == currentConsole {
  117. fmt.Printf("current %s\n", console)
  118. } else if console == cfg.Rancher.Console {
  119. fmt.Printf("enabled %s\n", console)
  120. } else {
  121. fmt.Printf("disabled %s\n", console)
  122. }
  123. }
  124. return nil
  125. }
  126. func validateConsole(console string, cfg *config.CloudConfig) {
  127. consoles := availableConsoles(cfg)
  128. if !service.IsLocalOrURL(console) && !util.Contains(consoles, console) {
  129. log.Fatalf("%s is not a valid console", console)
  130. }
  131. }
  132. func availableConsoles(cfg *config.CloudConfig) []string {
  133. consoles, err := network.GetConsoles(cfg.Rancher.Repositories.ToArray())
  134. if err != nil {
  135. log.Fatal(err)
  136. }
  137. consoles = append(consoles, "default")
  138. sort.Strings(consoles)
  139. return consoles
  140. }
  141. func currentConsole() (console string) {
  142. consoleBytes, err := ioutil.ReadFile("/run/console-done")
  143. if err == nil {
  144. console = strings.TrimSpace(string(consoleBytes))
  145. } else {
  146. log.Warnf("Failed to detect current console: %v", err)
  147. }
  148. return
  149. }