diff --git a/docs/kubedb/README.md b/docs/kubedb/README.md new file mode 100644 index 000000000..c3927f321 --- /dev/null +++ b/docs/kubedb/README.md @@ -0,0 +1,20 @@ +# kubedb + +```bash +$ kubedb --help + +kubedb controls k8sdb ThirdPartyResource objects. + +Find more information at https://github.com/k8sdb/kubedb. + +Basic Commands (Beginner): + create Create a resource by filename or stdin + +Basic Commands (Intermediate): + get Display one or many resources + +Other Commands: + help Help about any command + +Use "kubedb --help" for more information about a given command. +``` diff --git a/docs/kubedb/create.md b/docs/kubedb/create.md new file mode 100644 index 000000000..a1408c627 --- /dev/null +++ b/docs/kubedb/create.md @@ -0,0 +1,51 @@ +# kubedb create + +## Example + +##### Help for create command + +```bash +$ kubedb create --help + +Create a resource by filename or stdin. + +JSON and YAML formats are accepted. + +Examples: + # Create a elastic using the data in elastic.json. + kubedb create -f ./elastic.json + + # Create a elastic based on the JSON passed into stdin. + cat elastic.json | kubedb create -f - + +Options: + -f, --filename=[]: Filename to use to create the resource + -R, --recursive=false: Process the directory used in -f, --filename recursively. + +Usage: + kubedb create [options] + +Use "kubedb create options" for a list of global command-line options (applies to all commands). +``` + +##### Create from file +```bash +$ kubedb create -f ./elastic.json + +elastic "elasticsearch-demo" created +``` + +##### Create from stdin +```bash +$ cat ./elastic.json | kubedb create -f - + +elastic "elasticsearch-demo" created +``` + +##### Create from folder +```bash +$ kubedb create -f resources -R + +es "elasticsearch-demo" created +pg "postgres-demo" created +``` diff --git a/docs/kubedb/get.md b/docs/kubedb/get.md index e3e87ae82..ed8da407c 100644 --- a/docs/kubedb/get.md +++ b/docs/kubedb/get.md @@ -2,24 +2,6 @@ ## Example -##### Get help -```bash -$ kubedb --help - -kubedb controls k8sdb ThirdPartyResource objects. - -Find more information at https://github.com/k8sdb/kubedb. - -Basic Commands (Intermediate): - get Display one or many resources - -Other Commands: - help Help about any command - -Use "kubedb --help" for more information about a given command. -``` - - ##### Help for get command ```bash diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 22f4718c5..f05cb1011 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -21,6 +21,12 @@ func NewKubedbCommand(in io.Reader, out, err io.Writer) *cobra.Command { } groups := templates.CommandGroups{ + { + Message: "Basic Commands (Beginner):", + Commands: []*cobra.Command{ + NewCmdCreate(out, err), + }, + }, { Message: "Basic Commands (Intermediate):", Commands: []*cobra.Command{ diff --git a/pkg/cmd/create.go b/pkg/cmd/create.go new file mode 100644 index 000000000..02a424c43 --- /dev/null +++ b/pkg/cmd/create.go @@ -0,0 +1,134 @@ +package cmd + +import ( + "errors" + "io" + + "github.com/k8sdb/kubedb/pkg/cmd/util" + "github.com/k8sdb/kubedb/pkg/kube" + "github.com/spf13/cobra" + "k8s.io/kubernetes/pkg/kubectl/cmd/templates" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/runtime" +) + +// ref: k8s.io/kubernetes/pkg/kubectl/cmd/create.go + +var ( + create_long = templates.LongDesc(` + Create a resource by filename or stdin. + + JSON and YAML formats are accepted.`) + + create_example = templates.Examples(` + # Create a elastic using the data in elastic.json. + kubedb create -f ./elastic.json + + # Create a elastic based on the JSON passed into stdin. + cat elastic.json | kubedb create -f -`) +) + +func NewCmdCreate(out io.Writer, errOut io.Writer) *cobra.Command { + options := &resource.FilenameOptions{} + + cmd := &cobra.Command{ + Use: "create", + Short: "Create a resource by filename or stdin", + Long: create_long, + Example: create_example, + Run: func(cmd *cobra.Command, args []string) { + if cmdutil.IsFilenameEmpty(options.Filenames) { + defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut) + defaultRunFunc(cmd, args) + return + } + f := kube.NewKubeFactory(cmd) + cmdutil.CheckErr(RunCreate(f, out, options)) + }, + } + + util.AddCreateFlags(cmd, options) + return cmd +} + +func RunCreate(f cmdutil.Factory, out io.Writer, options *resource.FilenameOptions) error { + cmdNamespace, enforceNamespace, err := f.DefaultNamespace() + if err != nil { + return err + } + + mapper, typer, err := f.UnstructuredObject() + if err != nil { + return err + } + + r := resource.NewBuilder( + mapper, + typer, + resource.ClientMapperFunc(f.UnstructuredClientForMapping), + runtime.UnstructuredJSONScheme). + Schema(util.Validator()). + ContinueOnError(). + NamespaceParam(cmdNamespace).DefaultNamespace(). + FilenameParam(enforceNamespace, options). + Flatten(). + Do() + + err = r.Err() + if err != nil { + return err + } + + infoList := make([]*resource.Info, 0) + err = r.Visit(func(info *resource.Info, err error) error { + if err != nil { + return err + } + + kind := info.GetObjectKind().GroupVersionKind().Kind + if err := util.CheckSupportedResource(kind); err != nil { + return err + } + + infoList = append(infoList, info) + return nil + }) + if err != nil { + return err + } + + showAlias := false + if len(infoList) > 1 { + showAlias = true + } + + count := 0 + for _, info := range infoList { + if err := createAndRefresh(info); err != nil { + return cmdutil.AddSourceToErr("creating", info.Source, err) + } + count++ + resourceName := info.Mapping.Resource + if showAlias { + if alias, ok := util.ResourceShortFormFor(info.Mapping.Resource); ok { + resourceName = alias + } + } + cmdutil.PrintSuccess(mapper, false, out, resourceName, info.Name, false, "created") + } + + if count == 0 { + return errors.New("no objects passed to create") + } + return nil +} + +func createAndRefresh(info *resource.Info) error { + obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object) + if err != nil { + return err + } + info.Refresh(obj, true) + return nil +} diff --git a/pkg/cmd/util/flags.go b/pkg/cmd/util/flags.go index 5d7e12e18..5dadf065d 100644 --- a/pkg/cmd/util/flags.go +++ b/pkg/cmd/util/flags.go @@ -1,6 +1,9 @@ package util -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" + "k8s.io/kubernetes/pkg/kubectl/resource" +) func AddGetFlags(cmd *cobra.Command) { cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") @@ -10,3 +13,8 @@ func AddGetFlags(cmd *cobra.Command) { cmd.Flags().BoolP("show-all", "a", false, "When printing, show all resources (default hide terminated pods.)") cmd.Flags().Bool("show-labels", false, "When printing, show all labels as the last column (default hide labels column)") } + +func AddCreateFlags(cmd *cobra.Command, options *resource.FilenameOptions) { + cmd.Flags().StringSliceVarP(&options.Filenames, "filename", "f", options.Filenames, "Filename to use to create the resource") + cmd.Flags().BoolVarP(&options.Recursive, "recursive", "R", options.Recursive, "Process the directory used in -f, --filename recursively.") +} diff --git a/pkg/cmd/util/resource.go b/pkg/cmd/util/resource.go index 492f1aaf8..f493575bd 100644 --- a/pkg/cmd/util/resource.go +++ b/pkg/cmd/util/resource.go @@ -40,6 +40,19 @@ func GetSupportedResourceKind(resource string) (string, error) { return resource, nil } +func CheckSupportedResource(kind string) error { + switch kind { + case tapi.ResourceKindElastic: + case tapi.ResourceKindPostgres: + case tapi.ResourceKindDatabaseSnapshot: + case tapi.ResourceKindDeletedDatabase: + return nil + default: + return fmt.Errorf(`kubedb doesn't support a resource type "%v"`, kind) + } + return nil +} + func GetAllSupportedResources(f cmdutil.Factory) ([]string, error) { resources := map[string]string{ diff --git a/pkg/cmd/util/schema.go b/pkg/cmd/util/schema.go new file mode 100644 index 000000000..ecc9c94c7 --- /dev/null +++ b/pkg/cmd/util/schema.go @@ -0,0 +1,17 @@ +package util + +import ( + "k8s.io/kubernetes/pkg/api/validation" +) + +type ConjunctiveSchema []validation.Schema + +func (c *ConjunctiveSchema) ValidateBytes(data []byte) error { + return nil +} + +func Validator() validation.Schema { + return validation.ConjunctiveSchema{ + validation.NoDoubleKeySchema{}, + } +}