github.com/kunnos/engine@v1.13.1/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/docker/api/types" 12 "github.com/docker/docker/cli" 13 "github.com/docker/docker/cli/command" 14 "github.com/docker/docker/pkg/archive" 15 "github.com/docker/docker/reference" 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.ParseNamed(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 45 stat, err := os.Lstat(absContextDir) 46 if err != nil { 47 return "", err 48 } 49 50 if !stat.IsDir() { 51 return "", fmt.Errorf("context must be a directory") 52 } 53 54 return absContextDir, nil 55 } 56 57 type pluginCreateOptions struct { 58 repoName string 59 context string 60 compress bool 61 } 62 63 func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { 64 options := pluginCreateOptions{} 65 66 cmd := &cobra.Command{ 67 Use: "create [OPTIONS] PLUGIN PLUGIN-DATA-DIR", 68 Short: "Create a plugin from a rootfs and configuration. Plugin data directory must contain config.json and rootfs directory.", 69 Args: cli.RequiresMinArgs(2), 70 RunE: func(cmd *cobra.Command, args []string) error { 71 options.repoName = args[0] 72 options.context = args[1] 73 return runCreate(dockerCli, options) 74 }, 75 } 76 77 flags := cmd.Flags() 78 79 flags.BoolVar(&options.compress, "compress", false, "Compress the context using gzip") 80 81 return cmd 82 } 83 84 func runCreate(dockerCli *command.DockerCli, options pluginCreateOptions) error { 85 var ( 86 createCtx io.ReadCloser 87 err error 88 ) 89 90 if err := validateTag(options.repoName); err != nil { 91 return err 92 } 93 94 absContextDir, err := validateContextDir(options.context) 95 if err != nil { 96 return err 97 } 98 99 if err := validateConfig(options.context); err != nil { 100 return err 101 } 102 103 compression := archive.Uncompressed 104 if options.compress { 105 logrus.Debugf("compression enabled") 106 compression = archive.Gzip 107 } 108 109 createCtx, err = archive.TarWithOptions(absContextDir, &archive.TarOptions{ 110 Compression: compression, 111 }) 112 113 if err != nil { 114 return err 115 } 116 117 ctx := context.Background() 118 119 createOptions := types.PluginCreateOptions{RepoName: options.repoName} 120 if err = dockerCli.Client().PluginCreate(ctx, createCtx, createOptions); err != nil { 121 return err 122 } 123 fmt.Fprintln(dockerCli.Out(), options.repoName) 124 return nil 125 }