github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/plugin/create.go (about) 1 package plugin 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/distribution/reference" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/cli" 14 "github.com/docker/docker/cli/command" 15 "github.com/docker/docker/pkg/archive" 16 "github.com/spf13/cobra" 17 "golang.org/x/net/context" 18 ) 19 20 // validateTag checks if the given repoName can be resolved. 21 func validateTag(rawRepo string) error { 22 _, err := reference.ParseNormalizedNamed(rawRepo) 23 24 return err 25 } 26 27 // validateConfig ensures that a valid config.json is available in the given path 28 func validateConfig(path string) error { 29 dt, err := os.Open(filepath.Join(path, "config.json")) 30 if err != nil { 31 return err 32 } 33 34 m := types.PluginConfig{} 35 err = json.NewDecoder(dt).Decode(&m) 36 dt.Close() 37 38 return err 39 } 40 41 // validateContextDir validates the given dir and returns abs path on success. 42 func validateContextDir(contextDir string) (string, error) { 43 absContextDir, err := filepath.Abs(contextDir) 44 if err != nil { 45 return "", err 46 } 47 stat, err := os.Lstat(absContextDir) 48 if err != nil { 49 return "", err 50 } 51 52 if !stat.IsDir() { 53 return "", fmt.Errorf("context must be a directory") 54 } 55 56 return absContextDir, nil 57 } 58 59 type pluginCreateOptions struct { 60 repoName string 61 context string 62 compress bool 63 } 64 65 func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { 66 options := pluginCreateOptions{} 67 68 cmd := &cobra.Command{ 69 Use: "create [OPTIONS] PLUGIN PLUGIN-DATA-DIR", 70 Short: "Create a plugin from a rootfs and configuration. Plugin data directory must contain config.json and rootfs directory.", 71 Args: cli.RequiresMinArgs(2), 72 RunE: func(cmd *cobra.Command, args []string) error { 73 options.repoName = args[0] 74 options.context = args[1] 75 return runCreate(dockerCli, options) 76 }, 77 } 78 79 flags := cmd.Flags() 80 81 flags.BoolVar(&options.compress, "compress", false, "Compress the context using gzip") 82 83 return cmd 84 } 85 86 func runCreate(dockerCli *command.DockerCli, options pluginCreateOptions) error { 87 var ( 88 createCtx io.ReadCloser 89 err error 90 ) 91 92 if err := validateTag(options.repoName); err != nil { 93 return err 94 } 95 96 absContextDir, err := validateContextDir(options.context) 97 if err != nil { 98 return err 99 } 100 101 if err := validateConfig(options.context); err != nil { 102 return err 103 } 104 105 compression := archive.Uncompressed 106 if options.compress { 107 logrus.Debugf("compression enabled") 108 compression = archive.Gzip 109 } 110 111 createCtx, err = archive.TarWithOptions(absContextDir, &archive.TarOptions{ 112 Compression: compression, 113 }) 114 115 if err != nil { 116 return err 117 } 118 119 ctx := context.Background() 120 121 createOptions := types.PluginCreateOptions{RepoName: options.repoName} 122 if err = dockerCli.Client().PluginCreate(ctx, createCtx, createOptions); err != nil { 123 return err 124 } 125 fmt.Fprintln(dockerCli.Out(), options.repoName) 126 return nil 127 }