// TODO: Consider using a mocking library instead or fully fleshing this out into a fake impl and putting it in some // generally available location func (f *Factory) ValidateBytes(data []byte) error { var obj interface{} out, err := k8syaml.ToJSON(data) if err != nil { return err } data = out if err := json.Unmarshal(data, &obj); err != nil { return err } fields, ok := obj.(map[string]interface{}) if !ok { return fmt.Errorf("error in unmarshaling data %s", string(data)) } // Note: This only supports the 2 api versions we expect from the test it is currently supporting. groupVersion := fields["apiVersion"] switch groupVersion { case "v1": return f.defaultSchema.ValidateBytes(data) case "extensions/v1beta1": return f.extensionsSchema.ValidateBytes(data) default: return fmt.Errorf("Unsupported API version %s", groupVersion) } }
func (c *commandTokenSource) parseTokenCmdOutput(output []byte) (*oauth2.Token, error) { output, err := yaml.ToJSON(output) if err != nil { return nil, err } var data interface{} if err := json.Unmarshal(output, &data); err != nil { return nil, err } accessToken, err := parseJSONPath(data, "token-key", c.tokenKey) if err != nil { return nil, fmt.Errorf("error parsing token-key %q: %v", c.tokenKey, err) } expiryStr, err := parseJSONPath(data, "expiry-key", c.expiryKey) if err != nil { return nil, fmt.Errorf("error parsing expiry-key %q: %v", c.expiryKey, err) } var expiry time.Time if t, err := time.Parse(c.timeFmt, expiryStr); err != nil { glog.V(4).Infof("Failed to parse token expiry from %s (fmt=%s): %v", expiryStr, c.timeFmt, err) } else { expiry = t } return &oauth2.Token{ AccessToken: accessToken, TokenType: "Bearer", Expiry: expiry, }, nil }
func IsThirdPartyObject(rawData []byte, gvk *schema.GroupVersionKind) (isThirdParty bool, gvkOut *schema.GroupVersionKind, err error) { var gv schema.GroupVersion if gvk == nil { data, err := yaml.ToJSON(rawData) if err != nil { return false, nil, err } metadata := metav1.TypeMeta{} if err = json.Unmarshal(data, &metadata); err != nil { return false, nil, err } gv, err = schema.ParseGroupVersion(metadata.APIVersion) if err != nil { return false, nil, err } gvkOut = &schema.GroupVersionKind{ Group: gv.Group, Version: gv.Version, Kind: metadata.Kind, } } else { gv = gvk.GroupVersion() gvkOut = gvk } return api.Registry.IsThirdPartyAPIGroupVersion(gv), gvkOut, nil }
func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) { // JSON is valid YAML, so this should work for everything. json, err := utilyaml.ToJSON(data) if err != nil { return false, nil, err } obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), json) if err != nil { return false, pod, err } // Check whether the object could be converted to single pod. if _, ok := obj.(*api.Pod); !ok { err = fmt.Errorf("invalid pod: %#v", obj) return false, pod, err } newPod := obj.(*api.Pod) // Apply default values and validate the pod. if err = defaultFn(newPod); err != nil { return true, pod, err } if errs := validation.ValidatePod(newPod); len(errs) > 0 { err = fmt.Errorf("invalid pod: %v", errs) return true, pod, err } v1Pod := &v1.Pod{} if err := v1.Convert_api_Pod_To_v1_Pod(newPod, v1Pod, nil); err != nil { return true, nil, err } return true, v1Pod, nil }
func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error { return filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() && path != inDir { return filepath.SkipDir } file := filepath.Base(path) if ext := filepath.Ext(file); ext == ".json" || ext == ".yaml" { glog.Infof("Testing %s", path) data, err := ioutil.ReadFile(path) if err != nil { return err } name := strings.TrimSuffix(file, ext) if ext == ".yaml" { out, err := yaml.ToJSON(data) if err != nil { return fmt.Errorf("%s: %v", path, err) } data = out } fn(name, path, data) } return nil }) }
func (c yamlSerializer) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { out, err := yaml.ToJSON(data) if err != nil { return nil, nil, err } data = out return c.Serializer.Decode(data, gvk, into) }
// stripComments will transform a YAML file into JSON, thus dropping any comments // in it. Note that if the given file has a syntax error, the transformation will // fail and we will manually drop all comments from the file. func stripComments(file []byte) []byte { stripped := file stripped, err := yaml.ToJSON(stripped) if err != nil { stripped = manualStrip(file) } return stripped }
// NewDelta accepts two JSON or YAML documents and calculates the difference // between them. It returns a Delta object which can be used to resolve // conflicts against a third version with a common parent, or an error // if either document is in error. func NewDelta(from, to []byte) (*Delta, error) { d := &Delta{} before, err := yaml.ToJSON(from) if err != nil { return nil, err } after, err := yaml.ToJSON(to) if err != nil { return nil, err } diff, err := jsonpatch.CreateMergePatch(before, after) if err != nil { return nil, err } glog.V(6).Infof("Patch created from:\n%s\n%s\n%s", string(before), string(after), string(diff)) d.original = before d.edit = diff return d, nil }
// rcFromManifest reads a .json/yaml file and returns the rc in it. func rcFromManifest(fileName string) *v1.ReplicationController { var controller v1.ReplicationController framework.Logf("Parsing rc from %v", fileName) data := generated.ReadOrDie(fileName) json, err := utilyaml.ToJSON(data) Expect(err).NotTo(HaveOccurred()) Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &controller)).NotTo(HaveOccurred()) return &controller }
// svcFromManifest reads a .json/yaml file and returns the rc in it. func svcFromManifest(fileName string) *v1.Service { var svc v1.Service framework.Logf("Parsing service from %v", fileName) data := generated.ReadOrDie(fileName) json, err := utilyaml.ToJSON(data) Expect(err).NotTo(HaveOccurred()) Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &svc)).NotTo(HaveOccurred()) return &svc }
// ingFromManifest reads a .json/yaml file and returns the rc in it. func ingFromManifest(fileName string) *extensions.Ingress { var ing extensions.Ingress framework.Logf("Parsing ingress from %v", fileName) data, err := ioutil.ReadFile(fileName) framework.ExpectNoError(err) json, err := utilyaml.ToJSON(data) framework.ExpectNoError(err) framework.ExpectNoError(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &ing)) return &ing }
func podFromManifest(filename string) (*v1.Pod, error) { var pod v1.Pod framework.Logf("Parsing pod from %v", filename) data := generated.ReadOrDie(filename) json, err := utilyaml.ToJSON(data) if err != nil { return nil, err } if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &pod); err != nil { return nil, err } return &pod, nil }
func statefulSetFromManifest(fileName, ns string) *apps.StatefulSet { var ss apps.StatefulSet framework.Logf("Parsing statefulset from %v", fileName) data, err := ioutil.ReadFile(fileName) Expect(err).NotTo(HaveOccurred()) json, err := utilyaml.ToJSON(data) Expect(err).NotTo(HaveOccurred()) Expect(runtime.DecodeInto(api.Codecs.UniversalDecoder(), json, &ss)).NotTo(HaveOccurred()) ss.Namespace = ns if ss.Spec.Selector == nil { ss.Spec.Selector = &metav1.LabelSelector{ MatchLabels: ss.Spec.Template.Labels, } } return &ss }
func (s *SwaggerSchema) ValidateBytes(data []byte) error { var obj interface{} out, err := yaml.ToJSON(data) if err != nil { return err } data = out if err := json.Unmarshal(data, &obj); err != nil { return err } fields, ok := obj.(map[string]interface{}) if !ok { return fmt.Errorf("error in unmarshaling data %s", string(data)) } groupVersion := fields["apiVersion"] if groupVersion == nil { return fmt.Errorf("apiVersion not set") } if _, ok := groupVersion.(string); !ok { return fmt.Errorf("apiVersion isn't string type") } kind := fields["kind"] if kind == nil { return fmt.Errorf("kind not set") } if _, ok := kind.(string); !ok { return fmt.Errorf("kind isn't string type") } if strings.HasSuffix(kind.(string), "List") { return utilerrors.NewAggregate(s.validateList(fields)) } version := apiutil.GetVersion(groupVersion.(string)) allErrs := s.ValidateObject(obj, "", version+"."+kind.(string)) if len(allErrs) == 1 { return allErrs[0] } return utilerrors.NewAggregate(allErrs) }
// Apply attempts to apply the changes described by Delta onto latest, // returning an error if the changes cannot be applied cleanly. // IsConflicting will be true if the changes overlap, otherwise a // generic error will be returned. func (d *Delta) Apply(latest []byte) ([]byte, error) { base, err := yaml.ToJSON(latest) if err != nil { return nil, err } changes, err := jsonpatch.CreateMergePatch(d.original, base) if err != nil { return nil, err } diff1 := make(map[string]interface{}) if err := json.Unmarshal(d.edit, &diff1); err != nil { return nil, err } diff2 := make(map[string]interface{}) if err := json.Unmarshal(changes, &diff2); err != nil { return nil, err } for _, fn := range d.preconditions { hold1, _ := fn(diff1) hold2, _ := fn(diff2) if !hold1 || !hold2 { return nil, ErrPreconditionFailed } } glog.V(6).Infof("Testing for conflict between:\n%s\n%s", string(d.edit), string(changes)) hasConflicts, err := strategicpatch.HasConflicts(diff1, diff2) if err != nil { return nil, err } if hasConflicts { return nil, ErrConflict } return jsonpatch.MergePatch(base, d.edit) }
func visitToPatch( originalObj runtime.Object, updates *resource.Info, mapper meta.RESTMapper, resourceMapper *resource.Mapper, encoder runtime.Encoder, out, errOut io.Writer, defaultVersion schema.GroupVersion, results *editResults, file string, ) error { patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper) err := patchVisitor.Visit(func(info *resource.Info, incomingErr error) error { currOriginalObj := originalObj // if we're editing a list, then navigate the list to find the item that we're currently trying to edit if meta.IsListType(originalObj) { currOriginalObj = nil editObjUID, err := meta.NewAccessor().UID(info.Object) if err != nil { return err } listItems, err := meta.ExtractList(originalObj) if err != nil { return err } // iterate through the list to find the item with the matching UID for i := range listItems { originalObjUID, err := meta.NewAccessor().UID(listItems[i]) if err != nil { return err } if editObjUID == originalObjUID { currOriginalObj = listItems[i] break } } if currOriginalObj == nil { return fmt.Errorf("no original object found for %#v", info.Object) } } originalSerialization, err := runtime.Encode(encoder, currOriginalObj) if err != nil { return err } editedSerialization, err := runtime.Encode(encoder, info.Object) if err != nil { return err } // compute the patch on a per-item basis // use strategic merge to create a patch originalJS, err := yaml.ToJSON(originalSerialization) if err != nil { return err } editedJS, err := yaml.ToJSON(editedSerialization) if err != nil { return err } if reflect.DeepEqual(originalJS, editedJS) { // no edit, so just skip it. cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, false, "skipped") return nil } preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"), strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")} patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, preconditions...) if err != nil { glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err) if strategicpatch.IsPreconditionFailed(err) { return fmt.Errorf("%s", "At least one of apiVersion, kind and name was changed") } return err } results.version = defaultVersion patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch) if err != nil { fmt.Fprintln(out, results.addError(err, info)) return nil } info.Refresh(patched, true) cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, false, "edited") return nil }) return err }
func TestReadme(t *testing.T) { paths := []struct { file string expectedType []runtime.Object }{ {"../README.md", []runtime.Object{&api.Pod{}}}, {"../examples/volumes/iscsi/README.md", []runtime.Object{&api.Pod{}}}, } for _, path := range paths { data, err := ioutil.ReadFile(path.file) if err != nil { t.Errorf("Unable to read file %s: %v", path, err) continue } matches := sampleRegexp.FindAllStringSubmatch(string(data), -1) if matches == nil { continue } ix := 0 for _, match := range matches { var content, subtype string for i, name := range sampleRegexp.SubexpNames() { if name == "type" { subtype = match[i] } if name == "content" && match[i] != "" { content = match[i] } } if subtype == "yaml" && subsetRegexp.FindString(content) != "" { t.Logf("skipping (%s): \n%s", subtype, content) continue } var expectedType runtime.Object if len(path.expectedType) == 1 { expectedType = path.expectedType[0] } else { expectedType = path.expectedType[ix] ix++ } json, err := yaml.ToJSON([]byte(content)) if err != nil { t.Errorf("%s could not be converted to JSON: %v\n%s", path, err, string(content)) } if err := runtime.DecodeInto(testapi.Default.Codec(), json, expectedType); err != nil { t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content)) continue } if errors := validateObject(expectedType); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } _, err = runtime.Encode(testapi.Default.Codec(), expectedType) if err != nil { t.Errorf("Could not encode object: %v", err) continue } } } }
func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *PatchOptions) error { switch { case options.Local && len(args) != 0: return fmt.Errorf("cannot specify --local and server resources") } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } patchType := types.StrategicMergePatchType patchTypeString := strings.ToLower(cmdutil.GetFlagString(cmd, "type")) if len(patchTypeString) != 0 { ok := false patchType, ok = patchTypes[patchTypeString] if !ok { return cmdutil.UsageError(cmd, fmt.Sprintf("--type must be one of %v, not %q", sets.StringKeySet(patchTypes).List(), patchTypeString)) } } patch := cmdutil.GetFlagString(cmd, "patch") if len(patch) == 0 { return cmdutil.UsageError(cmd, "Must specify -p to patch") } patchBytes, err := yaml.ToJSON([]byte(patch)) if err != nil { return fmt.Errorf("unable to parse %q: %v", patch, err) } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, &options.FilenameOptions). ResourceTypeOrNameArgs(false, args...). Flatten(). Do() err = r.Err() if err != nil { return err } count := 0 err = r.Visit(func(info *resource.Info, err error) error { if err != nil { return err } name, namespace := info.Name, info.Namespace mapping := info.ResourceMapping() client, err := f.ClientForMapping(mapping) if err != nil { return err } if !options.Local { dataChangedMsg := "not patched" helper := resource.NewHelper(client, mapping) patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes) if err != nil { return err } if cmdutil.ShouldRecord(cmd, info) { // don't return an error on failure. The patch itself succeeded, its only the hint for that change that failed // don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command // also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this // record hint is likely to be invalid anyway, so avoid the bad hint patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) if err == nil { helper.Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch) } } count++ oldData, err := json.Marshal(info.Object) if err != nil { return err } newData, err := json.Marshal(patchedObj) if err != nil { return err } if !reflect.DeepEqual(oldData, newData) { dataChangedMsg = "patched" } if options.OutputFormat == "name" || len(options.OutputFormat) == 0 { cmdutil.PrintSuccess(mapper, options.OutputFormat == "name", out, "", name, false, dataChangedMsg) } return nil } count++ patchedObj, err := api.Scheme.DeepCopy(info.VersionedObject) if err != nil { return err } originalObjJS, err := runtime.Encode(api.Codecs.LegacyCodec(mapping.GroupVersionKind.GroupVersion()), info.VersionedObject.(runtime.Object)) if err != nil { return err } originalPatchedObjJS, err := getPatchedJSON(patchType, originalObjJS, patchBytes, patchedObj.(runtime.Object)) if err != nil { return err } targetObj, err := runtime.Decode(api.Codecs.UniversalDecoder(), originalPatchedObjJS) if err != nil { return err } // TODO: if we ever want to go generic, this allows a clean -o yaml without trying to print columns or anything // rawExtension := &runtime.Unknown{ // Raw: originalPatchedObjJS, // } printer, err := f.PrinterForMapping(cmd, mapping, false) if err != nil { return err } if err := printer.PrintObj(targetObj, out); err != nil { return err } return nil }) if err != nil { return err } if count == 0 { return fmt.Errorf("no objects passed to patch") } return nil }