volume.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package client
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/url"
  8. "text/tabwriter"
  9. "text/template"
  10. "github.com/docker/docker/api/types"
  11. Cli "github.com/docker/docker/cli"
  12. "github.com/docker/docker/opts"
  13. flag "github.com/docker/docker/pkg/mflag"
  14. "github.com/docker/docker/pkg/parsers/filters"
  15. )
  16. // CmdVolume is the parent subcommand for all volume commands
  17. //
  18. // Usage: docker volume <COMMAND> <OPTS>
  19. func (cli *DockerCli) CmdVolume(args ...string) error {
  20. description := "Manage Docker volumes\n\nCommands:\n"
  21. commands := [][]string{
  22. {"create", "Create a volume"},
  23. {"inspect", "Return low-level information on a volume"},
  24. {"ls", "List volumes"},
  25. {"rm", "Remove a volume"},
  26. }
  27. for _, cmd := range commands {
  28. description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
  29. }
  30. description += "\nRun 'docker volume COMMAND --help' for more information on a command."
  31. cmd := Cli.Subcmd("volume", []string{"[COMMAND]"}, description, true)
  32. cmd.Require(flag.Exact, 0)
  33. cmd.ParseFlags(args, true)
  34. return cli.CmdVolumeLs(args...)
  35. }
  36. // CmdVolumeLs outputs a list of Docker volumes.
  37. //
  38. // Usage: docker volume ls [OPTIONS]
  39. func (cli *DockerCli) CmdVolumeLs(args ...string) error {
  40. cmd := Cli.Subcmd("volume ls", nil, "List volumes", true)
  41. quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display volume names")
  42. flFilter := opts.NewListOpts(nil)
  43. cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
  44. cmd.Require(flag.Exact, 0)
  45. cmd.ParseFlags(args, true)
  46. volFilterArgs := filters.Args{}
  47. for _, f := range flFilter.GetAll() {
  48. var err error
  49. volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
  50. if err != nil {
  51. return err
  52. }
  53. }
  54. v := url.Values{}
  55. if len(volFilterArgs) > 0 {
  56. filterJSON, err := filters.ToParam(volFilterArgs)
  57. if err != nil {
  58. return err
  59. }
  60. v.Set("filters", filterJSON)
  61. }
  62. resp, err := cli.call("GET", "/volumes?"+v.Encode(), nil, nil)
  63. if err != nil {
  64. return err
  65. }
  66. var volumes types.VolumesListResponse
  67. if err := json.NewDecoder(resp.body).Decode(&volumes); err != nil {
  68. return err
  69. }
  70. w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  71. if !*quiet {
  72. fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
  73. fmt.Fprintf(w, "\n")
  74. }
  75. for _, vol := range volumes.Volumes {
  76. if *quiet {
  77. fmt.Fprintln(w, vol.Name)
  78. continue
  79. }
  80. fmt.Fprintf(w, "%s\t%s\n", vol.Driver, vol.Name)
  81. }
  82. w.Flush()
  83. return nil
  84. }
  85. // CmdVolumeInspect displays low-level information on one or more volumes.
  86. //
  87. // Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
  88. func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
  89. cmd := Cli.Subcmd("volume inspect", []string{"VOLUME [VOLUME...]"}, "Return low-level information on a volume", true)
  90. tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template.")
  91. if err := cmd.Parse(args); err != nil {
  92. return nil
  93. }
  94. cmd.Require(flag.Min, 1)
  95. cmd.ParseFlags(args, true)
  96. var tmpl *template.Template
  97. if *tmplStr != "" {
  98. var err error
  99. tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr)
  100. if err != nil {
  101. return err
  102. }
  103. }
  104. var status = 0
  105. var volumes []*types.Volume
  106. for _, name := range cmd.Args() {
  107. resp, err := cli.call("GET", "/volumes/"+name, nil, nil)
  108. if err != nil {
  109. return err
  110. }
  111. var volume types.Volume
  112. if err := json.NewDecoder(resp.body).Decode(&volume); err != nil {
  113. fmt.Fprintf(cli.err, "%s\n", err)
  114. status = 1
  115. continue
  116. }
  117. if tmpl == nil {
  118. volumes = append(volumes, &volume)
  119. continue
  120. }
  121. if err := tmpl.Execute(cli.out, &volume); err != nil {
  122. if err := tmpl.Execute(cli.out, &volume); err != nil {
  123. fmt.Fprintf(cli.err, "%s\n", err)
  124. status = 1
  125. continue
  126. }
  127. }
  128. io.WriteString(cli.out, "\n")
  129. }
  130. if tmpl != nil {
  131. return nil
  132. }
  133. b, err := json.MarshalIndent(volumes, "", " ")
  134. if err != nil {
  135. return err
  136. }
  137. _, err = io.Copy(cli.out, bytes.NewReader(b))
  138. if err != nil {
  139. return err
  140. }
  141. io.WriteString(cli.out, "\n")
  142. if status != 0 {
  143. return Cli.StatusError{StatusCode: status}
  144. }
  145. return nil
  146. }
  147. // CmdVolumeCreate creates a new container from a given image.
  148. //
  149. // Usage: docker volume create [OPTIONS]
  150. func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
  151. cmd := Cli.Subcmd("volume create", nil, "Create a volume", true)
  152. flDriver := cmd.String([]string{"d", "-driver"}, "local", "Specify volume driver name")
  153. flName := cmd.String([]string{"-name"}, "", "Specify volume name")
  154. flDriverOpts := opts.NewMapOpts(nil, nil)
  155. cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
  156. cmd.Require(flag.Exact, 0)
  157. cmd.ParseFlags(args, true)
  158. volReq := &types.VolumeCreateRequest{
  159. Driver: *flDriver,
  160. DriverOpts: flDriverOpts.GetAll(),
  161. }
  162. if *flName != "" {
  163. volReq.Name = *flName
  164. }
  165. resp, err := cli.call("POST", "/volumes", volReq, nil)
  166. if err != nil {
  167. return err
  168. }
  169. var vol types.Volume
  170. if err := json.NewDecoder(resp.body).Decode(&vol); err != nil {
  171. return err
  172. }
  173. fmt.Fprintf(cli.out, "%s\n", vol.Name)
  174. return nil
  175. }
  176. // CmdVolumeRm removes one or more containers.
  177. //
  178. // Usage: docker volume rm VOLUME [VOLUME...]
  179. func (cli *DockerCli) CmdVolumeRm(args ...string) error {
  180. cmd := Cli.Subcmd("volume rm", []string{"VOLUME [VOLUME...]"}, "Remove a volume", true)
  181. cmd.Require(flag.Min, 1)
  182. cmd.ParseFlags(args, true)
  183. var status = 0
  184. for _, name := range cmd.Args() {
  185. _, err := cli.call("DELETE", "/volumes/"+name, nil, nil)
  186. if err != nil {
  187. fmt.Fprintf(cli.err, "%s\n", err)
  188. status = 1
  189. continue
  190. }
  191. fmt.Fprintf(cli.out, "%s\n", name)
  192. }
  193. if status != 0 {
  194. return Cli.StatusError{StatusCode: status}
  195. }
  196. return nil
  197. }