// CreateObjects creates bulk of resources provided by items list. Each item must // be valid API type. It requires ObjectTyper to parse the Version and Kind and // RESTMapper to get the resource URI and REST client that knows how to create // given type func CreateObjects(typer runtime.ObjectTyper, mapper meta.RESTMapper, clientFor ClientFunc, objects []runtime.Object) util.ErrorList { allErrors := util.ErrorList{} for i, obj := range objects { version, kind, err := typer.ObjectVersionAndKind(obj) if err != nil { allErrors = append(allErrors, fmt.Errorf("Config.item[%d] kind: %v", i, err)) continue } mapping, err := mapper.RESTMapping(version, kind) if err != nil { allErrors = append(allErrors, fmt.Errorf("Config.item[%d] mapping: %v", i, err)) continue } client, err := clientFor(mapping) if err != nil { allErrors = append(allErrors, fmt.Errorf("Config.item[%d] client: %v", i, err)) continue } if err := CreateObject(client, mapping, obj); err != nil { allErrors = append(allErrors, fmt.Errorf("Config.item[%d]: %v", i, err)) } } return allErrors }
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary // to uniquely locate a resource. Displays a usageError if that contract is not satisfied, or // a generic error if any other problems occur. func ResourceOrTypeFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string) { if len(args) == 0 || len(args) > 2 { usageError(cmd, "Must provide resource or a resource and name as command line params") } resource := kubectl.ExpandResourceShortcut(args[0]) if len(resource) == 0 { usageError(cmd, "Must provide resource or a resource and name as command line params") } namespace = getKubeNamespace(cmd) if len(args) == 2 { name = args[1] if len(name) == 0 { usageError(cmd, "Must provide resource or a resource and name as command line params") } } version, kind, err := mapper.VersionAndKindForResource(resource) checkErr(err) mapping, err = mapper.RESTMapping(version, kind) checkErr(err) return }
// DataToObjects converts the raw JSON data into API objects func DataToObjects(m meta.RESTMapper, t runtime.ObjectTyper, data []byte) (result []runtime.Object, errors []error) { configObj := []runtime.RawExtension{} if err := yaml.Unmarshal(data, &configObj); err != nil { errors = append(errors, fmt.Errorf("config unmarshal: %v", err)) return result, errors } for i, in := range configObj { version, kind, err := t.DataVersionAndKind(in.RawJSON) if err != nil { errors = append(errors, fmt.Errorf("item[%d] kind: %v", i, err)) continue } mapping, err := m.RESTMapping(kind, version) if err != nil { errors = append(errors, fmt.Errorf("item[%d] mapping: %v", i, err)) continue } obj, err := mapping.Codec.Decode(in.RawJSON) if err != nil { errors = append(errors, fmt.Errorf("item[%d] decode: %v", i, err)) continue } result = append(result, obj) } return }
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not // resolve to a known type an error is returned. The returned mapping can be used to determine // the correct REST endpoint to modify this resource with. func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string, data []byte) { configData, err := ReadConfigData(filename) checkErr(err) data = configData version, kind, err := typer.DataVersionAndKind(data) checkErr(err) // TODO: allow unversioned objects? if len(version) == 0 { checkErr(fmt.Errorf("The resource in the provided file has no apiVersion defined")) } mapping, err = mapper.RESTMapping(version, kind) checkErr(err) obj, err := mapping.Codec.Decode(data) checkErr(err) meta := mapping.MetadataAccessor namespace, err = meta.Namespace(obj) checkErr(err) name, err = meta.Name(obj) checkErr(err) return }
// ResourceFromArgsOrFile expects two arguments or a valid file with a given type, and extracts // the fields necessary to uniquely locate a resource. Displays a usageError if that contract is // not satisfied, or a generic error if any other problems occur. func ResourceFromArgsOrFile(cmd *cobra.Command, args []string, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string) { // If command line args are passed in, use those preferentially. if len(args) > 0 && len(args) != 2 { usageError(cmd, "If passing in command line parameters, must be resource and name") } if len(args) == 2 { resource := kubectl.ExpandResourceShortcut(args[0]) namespace = getKubeNamespace(cmd) name = args[1] if len(name) == 0 || len(resource) == 0 { usageError(cmd, "Must specify filename or command line params") } version, kind, err := mapper.VersionAndKindForResource(resource) checkErr(err) mapping, err = mapper.RESTMapping(version, kind) checkErr(err) return } if len(filename) == 0 { usageError(cmd, "Must specify filename or command line params") } mapping, namespace, name, _ = ResourceFromFile(filename, typer, mapper) if len(name) == 0 { checkErr(fmt.Errorf("The resource in the provided file has no name (or ID) defined")) } return }
// CreateObjects creates bulk of resources provided by items list. Each item must // be valid API type. It requires ObjectTyper to parse the Version and Kind and // RESTMapper to get the resource URI and REST client that knows how to create // given type func CreateObjects(typer runtime.ObjectTyper, mapper meta.RESTMapper, clientFor ClientFunc, objects []runtime.Object) errs.ValidationErrorList { allErrors := errs.ValidationErrorList{} for i, obj := range objects { version, kind, err := typer.ObjectVersionAndKind(obj) if err != nil { reportError(&allErrors, i, errs.NewFieldInvalid("kind", obj)) continue } mapping, err := mapper.RESTMapping(version, kind) if err != nil { reportError(&allErrors, i, errs.NewFieldNotSupported("mapping", err)) continue } client, err := clientFor(mapping) if err != nil { reportError(&allErrors, i, errs.NewFieldNotSupported("client", obj)) continue } if err := CreateObject(client, mapping, obj); err != nil { reportError(&allErrors, i, *err) } } return allErrors.Prefix("Config") }
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary // to uniquely locate a resource. Displays a usageError if that contract is not satisfied, or // a generic error if any other problems occur. func ResourceOrTypeFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string) { if len(args) == 0 || len(args) > 2 { usageError(cmd, "Must provide resource or a resource and name as command line params") } resource := args[0] if len(resource) == 0 { usageError(cmd, "Must provide resource or a resource and name as command line params") } namespace = GetKubeNamespace(cmd) if len(args) == 2 { name = args[1] if len(name) == 0 { usageError(cmd, "Must provide resource or a resource and name as command line params") } } defaultVersion, kind, err := mapper.VersionAndKindForResource(resource) checkErr(err) version := GetFlagString(cmd, "api-version") mapping, err = mapper.RESTMapping(kind, version, defaultVersion) checkErr(err) return }
// ResourceFromArgsOrFile expects two arguments or a valid file with a given type, and extracts // the fields necessary to uniquely locate a resource. Displays a usageError if that contract is // not satisfied, or a generic error if any other problems occur. func ResourceFromArgsOrFile(cmd *cobra.Command, args []string, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema, cmdNamespace, cmdVersion string) (mapping *meta.RESTMapping, namespace, name string) { // If command line args are passed in, use those preferentially. if len(args) > 0 && len(args) != 2 { usageError(cmd, "If passing in command line parameters, must be resource and name") } if len(args) == 2 { resource := args[0] namespace = cmdNamespace name = args[1] if len(name) == 0 || len(resource) == 0 { usageError(cmd, "Must specify filename or command line params") } defaultVersion, kind, err := mapper.VersionAndKindForResource(resource) if err != nil { // The error returned by mapper is "no resource defined", which is a usage error usageError(cmd, err.Error()) } mapping, err = mapper.RESTMapping(kind, cmdVersion, defaultVersion) checkErr(err) return } if len(filename) == 0 { usageError(cmd, "Must specify filename or command line params") } mapping, namespace, name, _ = ResourceFromFile(filename, typer, mapper, schema, cmdVersion) if len(name) == 0 { checkErr(fmt.Errorf("the resource in the provided file has no name (or ID) defined")) } return }
// ResourcesFromArgsOrFile computes a list of Resources by extracting info from filename or args. It will // handle label selectors provided. func ResourcesFromArgsOrFile( cmd *cobra.Command, args []string, filename, selector string, typer runtime.ObjectTyper, mapper meta.RESTMapper, clientBuilder func(cmd *cobra.Command, mapping *meta.RESTMapping) (resource.RESTClient, error), schema validation.Schema, requireNames bool, cmdNamespace, cmdVersion string, ) resource.Visitor { // handling filename & resource id if len(selector) == 0 { if requireNames || len(filename) > 0 { mapping, namespace, name := ResourceFromArgsOrFile(cmd, args, filename, typer, mapper, schema, cmdNamespace, cmdVersion) client, err := clientBuilder(cmd, mapping) checkErr(err) return resource.NewInfo(client, mapping, namespace, name) } if len(args) == 2 { mapping, namespace, name := ResourceOrTypeFromArgs(cmd, args, mapper, cmdNamespace, cmdVersion) client, err := clientBuilder(cmd, mapping) checkErr(err) return resource.NewInfo(client, mapping, namespace, name) } } labelSelector, err := labels.ParseSelector(selector) checkErr(err) namespace := cmdNamespace visitors := resource.VisitorList{} if len(args) < 1 { usageError(cmd, "Must specify the type of resource") } if len(args) > 1 { usageError(cmd, "Too many arguments") } types := SplitResourceArgument(args[0]) for _, arg := range types { resourceName := arg if len(resourceName) == 0 { usageError(cmd, "Unknown resource %s", resourceName) } version, kind, err := mapper.VersionAndKindForResource(resourceName) checkErr(err) mapping, err := mapper.RESTMapping(kind, version) checkErr(err) client, err := clientBuilder(cmd, mapping) checkErr(err) visitors = append(visitors, resource.NewSelector(client, mapping, namespace, labelSelector)) } return visitors }
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not // resolve to a known type an error is returned. The returned mapping can be used to determine // the correct REST endpoint to modify this resource with. // DEPRECATED: Use resource.Builder func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema, cmdVersion string) (mapping *meta.RESTMapping, namespace, name string, data []byte, err error) { data, err = ReadConfigData(filename) if err != nil { return } objVersion, kind, err := typer.DataVersionAndKind(data) if err != nil { return } // TODO: allow unversioned objects? if len(objVersion) == 0 { err = fmt.Errorf("the resource in the provided file has no apiVersion defined") } err = schema.ValidateBytes(data) if err != nil { return } // decode using the version stored with the object (allows codec to vary across versions) mapping, err = mapper.RESTMapping(kind, objVersion) if err != nil { return } obj, err := mapping.Codec.Decode(data) if err != nil { return } meta := mapping.MetadataAccessor namespace, err = meta.Namespace(obj) if err != nil { return } name, err = meta.Name(obj) if err != nil { return } // if the preferred API version differs, get a different mapper if cmdVersion != objVersion { mapping, err = mapper.RESTMapping(kind, cmdVersion) } return }
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary // to uniquely locate a resource. Displays a usageError if that contract is not satisfied, or // a generic error if any other problems occur. func ResourceFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string) { if len(args) != 2 { usageError(cmd, "Must provide resource and name command line params") } resource := args[0] namespace = GetKubeNamespace(cmd) name = args[1] if len(name) == 0 || len(resource) == 0 { usageError(cmd, "Must provide resource and name command line params") } version, kind, err := mapper.VersionAndKindForResource(resource) checkErr(err) mapping, err = mapper.RESTMapping(kind, version) checkErr(err) return }
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary // to uniquely locate a resource. Displays a UsageError if that contract is not satisfied, or // a generic error if any other problems occur. // DEPRECATED: Use resource.Builder func ResourceFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper, cmdNamespace string) (mapping *meta.RESTMapping, namespace, name string, err error) { if len(args) != 2 { err = UsageError(cmd, "Must provide resource and name command line params") return } resource := args[0] namespace = cmdNamespace name = args[1] if len(name) == 0 || len(resource) == 0 { err = UsageError(cmd, "Must provide resource and name command line params") return } version, kind, err := mapper.VersionAndKindForResource(resource) if err != nil { return } mapping, err = mapper.RESTMapping(kind, version) return }
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not // resolve to a known type an error is returned. The returned mapping can be used to determine // the correct REST endpoint to modify this resource with. func ResourceFromFile(cmd *cobra.Command, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema) (mapping *meta.RESTMapping, namespace, name string, data []byte) { configData, err := ReadConfigData(filename) checkErr(err) data = configData objVersion, kind, err := typer.DataVersionAndKind(data) checkErr(err) // TODO: allow unversioned objects? if len(objVersion) == 0 { checkErr(fmt.Errorf("the resource in the provided file has no apiVersion defined")) } err = schema.ValidateBytes(data) checkErr(err) // decode using the version stored with the object (allows codec to vary across versions) mapping, err = mapper.RESTMapping(kind, objVersion) checkErr(err) obj, err := mapping.Codec.Decode(data) checkErr(err) meta := mapping.MetadataAccessor namespace, err = meta.Namespace(obj) checkErr(err) name, err = meta.Name(obj) checkErr(err) // if the preferred API version differs, get a different mapper version := GetFlagString(cmd, "api-version") if version != objVersion { mapping, err = mapper.RESTMapping(kind, version) checkErr(err) } return }
// DataToObjects converts the raw JSON data into API objects func DataToObjects(m meta.RESTMapper, t runtime.ObjectTyper, data []byte) (result []runtime.Object, errors errs.ValidationErrorList) { configObj := []runtime.RawExtension{} if err := yaml.Unmarshal(data, &configObj); err != nil { errors = append(errors, errs.NewFieldInvalid("unmarshal", err)) return result, errors.Prefix("Config") } for i, in := range configObj { version, kind, err := t.DataVersionAndKind(in.RawJSON) if err != nil { itemErrs := errs.ValidationErrorList{} itemErrs = append(itemErrs, errs.NewFieldInvalid("kind", string(in.RawJSON))) errors = append(errors, itemErrs.PrefixIndex(i).Prefix("item")...) continue } mapping, err := m.RESTMapping(version, kind) if err != nil { itemErrs := errs.ValidationErrorList{} itemErrs = append(itemErrs, errs.NewFieldRequired("mapping", err)) errors = append(errors, itemErrs.PrefixIndex(i).Prefix("item")...) continue } obj, err := mapping.Codec.Decode(in.RawJSON) if err != nil { itemErrs := errs.ValidationErrorList{} itemErrs = append(itemErrs, errs.NewFieldInvalid("decode", err)) errors = append(errors, itemErrs.PrefixIndex(i).Prefix("item")...) continue } result = append(result, obj) } return }