config.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package control
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "sort"
  8. "strings"
  9. log "github.com/Sirupsen/logrus"
  10. "gopkg.in/yaml.v2"
  11. "github.com/codegangsta/cli"
  12. "github.com/rancherio/os/config"
  13. )
  14. func configSubcommands() []cli.Command {
  15. return []cli.Command{
  16. {
  17. Name: "get",
  18. Usage: "get value",
  19. Action: configGet,
  20. },
  21. {
  22. Name: "set",
  23. Usage: "set a value",
  24. Action: configSet,
  25. },
  26. {
  27. Name: "import",
  28. Usage: "import configuration from standard in or a file",
  29. Action: runImport,
  30. Flags: []cli.Flag{
  31. cli.StringFlag{
  32. Name: "input, i",
  33. Usage: "File from which to read",
  34. },
  35. },
  36. },
  37. {
  38. Name: "images",
  39. Usage: "List Docker images for a configuration from a file",
  40. Action: runImages,
  41. Flags: []cli.Flag{
  42. cli.StringFlag{
  43. Name: "input, i",
  44. Usage: "File from which to read config",
  45. },
  46. },
  47. },
  48. {
  49. Name: "export",
  50. Usage: "export configuration",
  51. Flags: []cli.Flag{
  52. cli.StringFlag{
  53. Name: "output, o",
  54. Usage: "File to which to save",
  55. },
  56. cli.BoolFlag{
  57. Name: "private, p",
  58. Usage: "Include private information such as keys",
  59. },
  60. cli.BoolFlag{
  61. Name: "full, f",
  62. Usage: "Include full configuration, including internal and default settings",
  63. },
  64. },
  65. Action: export,
  66. },
  67. {
  68. Name: "merge",
  69. Usage: "merge configuration from stdin",
  70. Action: merge,
  71. },
  72. }
  73. }
  74. func imagesFromConfig(cfg *config.Config) []string {
  75. imagesMap := map[string]int{}
  76. for _, service := range cfg.BootstrapContainers {
  77. imagesMap[service.Image] = 1
  78. }
  79. for _, service := range cfg.Autoformat {
  80. imagesMap[service.Image] = 1
  81. }
  82. for _, service := range cfg.SystemContainers {
  83. imagesMap[service.Image] = 1
  84. }
  85. images := make([]string, len(imagesMap))
  86. i := 0
  87. for image := range imagesMap {
  88. images[i] = image
  89. i += 1
  90. }
  91. sort.Strings(images)
  92. return images
  93. }
  94. func runImages(c *cli.Context) {
  95. configFile := c.String("input")
  96. cfg := config.ReadConfig(configFile)
  97. if cfg == nil {
  98. log.Fatalf("Could not read config from file %v", configFile)
  99. }
  100. images := imagesFromConfig(cfg)
  101. fmt.Println(strings.Join(images, " "))
  102. }
  103. func runImport(c *cli.Context) {
  104. var input io.ReadCloser
  105. var err error
  106. input = os.Stdin
  107. cfg, err := config.LoadConfig()
  108. if err != nil {
  109. log.Fatal(err)
  110. }
  111. inputFile := c.String("input")
  112. if inputFile != "" {
  113. input, err = os.Open(inputFile)
  114. if err != nil {
  115. log.Fatal(err)
  116. }
  117. defer input.Close()
  118. }
  119. bytes, err := ioutil.ReadAll(input)
  120. if err != nil {
  121. log.Fatal(err)
  122. }
  123. err = cfg.Import(bytes)
  124. if err != nil {
  125. log.Fatal(err)
  126. }
  127. }
  128. func configSet(c *cli.Context) {
  129. key := c.Args().Get(0)
  130. value := c.Args().Get(1)
  131. if key == "" {
  132. return
  133. }
  134. cfg, err := config.LoadConfig()
  135. if err != nil {
  136. log.Fatal(err)
  137. }
  138. err = cfg.Set(key, value)
  139. if err != nil {
  140. log.Fatal(err)
  141. }
  142. }
  143. func configGet(c *cli.Context) {
  144. arg := c.Args().Get(0)
  145. if arg == "" {
  146. return
  147. }
  148. cfg, err := config.LoadConfig()
  149. if err != nil {
  150. log.Fatal(err)
  151. }
  152. val, err := cfg.Get(arg)
  153. if err != nil {
  154. log.Fatal(err)
  155. }
  156. printYaml := false
  157. switch val.(type) {
  158. case []interface{}:
  159. printYaml = true
  160. case map[interface{}]interface{}:
  161. printYaml = true
  162. }
  163. if printYaml {
  164. bytes, err := yaml.Marshal(val)
  165. if err != nil {
  166. log.Fatal(err)
  167. }
  168. fmt.Println(string(bytes))
  169. } else {
  170. fmt.Println(val)
  171. }
  172. }
  173. func getOrSetVal(args string, data map[interface{}]interface{}, value interface{}) interface{} {
  174. parts := strings.Split(args, ".")
  175. for i, part := range parts {
  176. val, ok := data[part]
  177. last := i+1 == len(parts)
  178. // Reached end, set the value
  179. if last && value != nil {
  180. if s, ok := value.(string); ok {
  181. value = config.DummyMarshall(s)
  182. }
  183. data[part] = value
  184. return value
  185. }
  186. // Missing intermediate key, create key
  187. if !last && value != nil && !ok {
  188. newData := map[interface{}]interface{}{}
  189. data[part] = newData
  190. data = newData
  191. continue
  192. }
  193. if !ok {
  194. break
  195. }
  196. if last {
  197. return val
  198. }
  199. newData, ok := val.(map[interface{}]interface{})
  200. if !ok {
  201. break
  202. }
  203. data = newData
  204. }
  205. return ""
  206. }
  207. func merge(c *cli.Context) {
  208. bytes, err := ioutil.ReadAll(os.Stdin)
  209. if err != nil {
  210. log.Fatal(err)
  211. }
  212. cfg, err := config.LoadConfig()
  213. if err != nil {
  214. log.Fatal(err)
  215. }
  216. err = cfg.Merge(bytes)
  217. if err != nil {
  218. log.Fatal(err)
  219. }
  220. }
  221. func export(c *cli.Context) {
  222. content, err := config.Dump(c.Bool("private"), c.Bool("full"))
  223. if err != nil {
  224. log.Fatal(err)
  225. }
  226. output := c.String("output")
  227. if output == "" {
  228. fmt.Println(content)
  229. } else {
  230. err := ioutil.WriteFile(output, []byte(content), 0400)
  231. if err != nil {
  232. log.Fatal(err)
  233. }
  234. }
  235. }