create.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cmd
  14. import (
  15. "fmt"
  16. "io"
  17. "github.com/renstrom/dedent"
  18. "github.com/spf13/cobra"
  19. "k8s.io/kubernetes/pkg/api/unversioned"
  20. "k8s.io/kubernetes/pkg/kubectl"
  21. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  22. "k8s.io/kubernetes/pkg/kubectl/resource"
  23. "k8s.io/kubernetes/pkg/runtime"
  24. )
  25. // CreateOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
  26. // referencing the cmd.Flags()
  27. type CreateOptions struct {
  28. Filenames []string
  29. Recursive bool
  30. }
  31. var (
  32. create_long = dedent.Dedent(`
  33. Create a resource by filename or stdin.
  34. JSON and YAML formats are accepted.`)
  35. create_example = dedent.Dedent(`
  36. # Create a pod using the data in pod.json.
  37. kubectl create -f ./pod.json
  38. # Create a pod based on the JSON passed into stdin.
  39. cat pod.json | kubectl create -f -`)
  40. )
  41. func NewCmdCreate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
  42. options := &CreateOptions{}
  43. cmd := &cobra.Command{
  44. Use: "create -f FILENAME",
  45. Short: "Create a resource by filename or stdin",
  46. Long: create_long,
  47. Example: create_example,
  48. Run: func(cmd *cobra.Command, args []string) {
  49. if len(options.Filenames) == 0 {
  50. cmd.Help()
  51. return
  52. }
  53. cmdutil.CheckErr(ValidateArgs(cmd, args))
  54. cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
  55. cmdutil.CheckErr(RunCreate(f, cmd, out, options))
  56. },
  57. }
  58. usage := "Filename, directory, or URL to file to use to create the resource"
  59. kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
  60. cmd.MarkFlagRequired("filename")
  61. cmdutil.AddValidateFlags(cmd)
  62. cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
  63. cmdutil.AddOutputFlagsForMutation(cmd)
  64. cmdutil.AddApplyAnnotationFlags(cmd)
  65. cmdutil.AddRecordFlag(cmd)
  66. cmdutil.AddInclude3rdPartyFlags(cmd)
  67. // create subcommands
  68. cmd.AddCommand(NewCmdCreateNamespace(f, out))
  69. cmd.AddCommand(NewCmdCreateQuota(f, out))
  70. cmd.AddCommand(NewCmdCreateSecret(f, out))
  71. cmd.AddCommand(NewCmdCreateConfigMap(f, out))
  72. cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
  73. cmd.AddCommand(NewCmdCreateService(f, out))
  74. cmd.AddCommand(NewCmdCreateDeployment(f, out))
  75. return cmd
  76. }
  77. func ValidateArgs(cmd *cobra.Command, args []string) error {
  78. if len(args) != 0 {
  79. return cmdutil.UsageError(cmd, "Unexpected args: %v", args)
  80. }
  81. return nil
  82. }
  83. func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateOptions) error {
  84. schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
  85. if err != nil {
  86. return err
  87. }
  88. cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
  89. if err != nil {
  90. return err
  91. }
  92. mapper, typer, err := f.UnstructuredObject()
  93. if err != nil {
  94. return err
  95. }
  96. r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
  97. Schema(schema).
  98. ContinueOnError().
  99. NamespaceParam(cmdNamespace).DefaultNamespace().
  100. FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
  101. Flatten().
  102. Do()
  103. err = r.Err()
  104. if err != nil {
  105. return err
  106. }
  107. count := 0
  108. err = r.Visit(func(info *resource.Info, err error) error {
  109. if err != nil {
  110. return err
  111. }
  112. if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
  113. return cmdutil.AddSourceToErr("creating", info.Source, err)
  114. }
  115. if cmdutil.ShouldRecord(cmd, info) {
  116. if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil {
  117. return cmdutil.AddSourceToErr("creating", info.Source, err)
  118. }
  119. }
  120. if err := createAndRefresh(info); err != nil {
  121. return cmdutil.AddSourceToErr("creating", info.Source, err)
  122. }
  123. count++
  124. shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
  125. if !shortOutput {
  126. f.PrintObjectSpecificMessage(info.Object, out)
  127. }
  128. cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "created")
  129. return nil
  130. })
  131. if err != nil {
  132. return err
  133. }
  134. if count == 0 {
  135. return fmt.Errorf("no objects passed to create")
  136. }
  137. return nil
  138. }
  139. // createAndRefresh creates an object from input info and refreshes info with that object
  140. func createAndRefresh(info *resource.Info) error {
  141. obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
  142. if err != nil {
  143. return err
  144. }
  145. info.Refresh(obj, true)
  146. return nil
  147. }
  148. // NameFromCommandArgs is a utility function for commands that assume the first argument is a resource name
  149. func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) {
  150. if len(args) == 0 {
  151. return "", cmdutil.UsageError(cmd, "NAME is required")
  152. }
  153. return args[0], nil
  154. }
  155. // CreateSubcommandOptions is an options struct to support create subcommands
  156. type CreateSubcommandOptions struct {
  157. // Name of resource being created
  158. Name string
  159. // StructuredGenerator is the resource generator for the object being created
  160. StructuredGenerator kubectl.StructuredGenerator
  161. // DryRun is true if the command should be simulated but not run against the server
  162. DryRun bool
  163. // OutputFormat
  164. OutputFormat string
  165. }
  166. // RunCreateSubcommand executes a create subcommand using the specified options
  167. func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error {
  168. namespace, _, err := f.DefaultNamespace()
  169. if err != nil {
  170. return err
  171. }
  172. obj, err := options.StructuredGenerator.StructuredGenerate()
  173. if err != nil {
  174. return err
  175. }
  176. mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
  177. gvks, _, err := typer.ObjectKinds(obj)
  178. if err != nil {
  179. return err
  180. }
  181. gvk := gvks[0]
  182. mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
  183. if err != nil {
  184. return err
  185. }
  186. client, err := f.ClientForMapping(mapping)
  187. if err != nil {
  188. return err
  189. }
  190. resourceMapper := &resource.Mapper{
  191. ObjectTyper: typer,
  192. RESTMapper: mapper,
  193. ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
  194. }
  195. info, err := resourceMapper.InfoForObject(obj, nil)
  196. if err != nil {
  197. return err
  198. }
  199. if err := kubectl.UpdateApplyAnnotation(info, f.JSONEncoder()); err != nil {
  200. return err
  201. }
  202. if !options.DryRun {
  203. obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
  204. if err != nil {
  205. return err
  206. }
  207. }
  208. if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 {
  209. cmdutil.PrintSuccess(mapper, useShortOutput, out, mapping.Resource, options.Name, "created")
  210. return nil
  211. }
  212. return f.PrintObject(cmd, mapper, obj, out)
  213. }