// patchObj patches calculates a patch between the given new object and the existing marshaled object func patchObj(obj runtime.Object, metadata meta.Object, oldData []byte, mapping *meta.RESTMapping, f *clientcmd.Factory) (runtime.Object, error) { newData, err := json.Marshal(obj) if err != nil { return nil, err } patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj) if err != nil { return nil, err } client, err := f.ClientForMapping(mapping) if err != nil { return nil, err } helper := resource.NewHelper(client, mapping) return helper.Patch(metadata.GetNamespace(), metadata.GetName(), kapi.StrategicMergePatchType, patchBytes) }
func (o *ObserveOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, out, errOut io.Writer) error { var err error var command []string if i := cmd.ArgsLenAtDash(); i != -1 { command = args[i:] args = args[:i] } o.eachCommand = command switch len(args) { case 0: return fmt.Errorf("you must specify at least one argument containing the resource to observe") case 1: default: return fmt.Errorf("you may only specify one argument containing the resource to observe (use '--' to separate your resource and your command)") } gr := unversioned.ParseGroupResource(args[0]) if gr.Empty() { return fmt.Errorf("unknown resource argument") } mapper, _ := f.Object(true) version, err := mapper.KindFor(gr.WithVersion("")) if err != nil { return err } mapping, err := mapper.RESTMapping(version.GroupKind()) if err != nil { return err } o.mapping = mapping o.includeNamespace = mapping.Scope.Name() == meta.RESTScopeNamespace.Name() client, err := f.ClientForMapping(mapping) if err != nil { return err } o.client = client o.namespace, _, err = f.DefaultNamespace() if err != nil { return err } switch o.templateType { case "jsonpath": p, err := NewJSONPathArgumentPrinter(o.includeNamespace, o.strictTemplates, o.templates...) if err != nil { return err } o.printer = p case "gotemplate": p, err := NewGoTemplateArgumentPrinter(o.includeNamespace, o.strictTemplates, o.templates...) if err != nil { return err } o.printer = p default: return fmt.Errorf("template type %q not recognized - valid values are jsonpath and gotemplate", o.templateType) } o.printer = NewVersionedColumnPrinter(o.printer, o.mapping.ObjectConvertor, version.GroupVersion()) o.out, o.errOut = out, errOut if o.noHeaders { o.debugOut = ioutil.Discard } else { o.debugOut = out } o.argumentStore = &objectArgumentsStore{} switch { case len(o.nameSyncCommand) > 0: o.argumentStore.keyFn = func() ([]string, error) { var out []byte err := retryCommandError(o.retryExitStatus, o.retryCount, func() error { c := exec.Command(o.nameSyncCommand[0], o.nameSyncCommand[1:]...) var err error return measureCommandDuration(nameExecDurations, func() error { out, err = c.Output() return err }) }) if err != nil { if exit, ok := err.(*exec.ExitError); ok { if len(exit.Stderr) > 0 { err = fmt.Errorf("%v\n%s", err, string(exit.Stderr)) } } return nil, err } names := strings.Split(string(out), "\n") sort.Sort(sort.StringSlice(names)) var outputNames []string for i, s := range names { if len(s) != 0 { outputNames = names[i:] break } } glog.V(4).Infof("Found existing keys: %v", outputNames) return outputNames, nil } o.knownObjects = o.argumentStore case len(o.deleteCommand) > 0: o.knownObjects = o.argumentStore } return nil }
// calculateIdlableAnnotationsByService calculates the list of objects involved in the idling process from a list of services in a file. // Using the list of services, it figures out the associated scalable objects, and returns a map from the endpoints object for the services to // the list of scalable resources associated with that endpoints object, as well as a map from CrossGroupObjectReferences to scale to 0 to the // name of the associated service. func (o *IdleOptions) calculateIdlableAnnotationsByService(f *clientcmd.Factory) (map[types.NamespacedName]idleUpdateInfo, map[unidlingapi.CrossGroupObjectReference]types.NamespacedName, error) { // load our set of services client, err := f.Client() if err != nil { return nil, nil, err } mapper, _ := f.Object(false) podsLoaded := make(map[kapi.ObjectReference]*kapi.Pod) getPod := func(ref kapi.ObjectReference) (*kapi.Pod, error) { if pod, ok := podsLoaded[ref]; ok { return pod, nil } pod, err := client.Pods(ref.Namespace).Get(ref.Name) if err != nil { return nil, err } podsLoaded[ref] = pod return pod, nil } controllersLoaded := make(map[kapi.ObjectReference]runtime.Object) helpers := make(map[unversioned.GroupKind]*resource.Helper) getController := func(ref kapi.ObjectReference) (runtime.Object, error) { if controller, ok := controllersLoaded[ref]; ok { return controller, nil } gv, err := unversioned.ParseGroupVersion(ref.APIVersion) if err != nil { return nil, err } // just get the unversioned version of this gk := unversioned.GroupKind{Group: gv.Group, Kind: ref.Kind} helper, ok := helpers[gk] if !ok { var mapping *meta.RESTMapping mapping, err = mapper.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: ref.Kind}, "") if err != nil { return nil, err } var client resource.RESTClient client, err = f.ClientForMapping(mapping) if err != nil { return nil, err } helper = resource.NewHelper(client, mapping) helpers[gk] = helper } var controller runtime.Object controller, err = helper.Get(ref.Namespace, ref.Name, false) if err != nil { return nil, err } controllersLoaded[ref] = controller return controller, nil } targetScaleRefs := make(map[unidlingapi.CrossGroupObjectReference]types.NamespacedName) endpointsInfo := make(map[types.NamespacedName]idleUpdateInfo) decoder := f.Decoder(true) err = o.svcBuilder.Do().Visit(func(info *resource.Info, err error) error { if err != nil { return err } endpoints, isEndpoints := info.Object.(*kapi.Endpoints) if !isEndpoints { return fmt.Errorf("you must specify endpoints, not %v (view available endpoints with \"%s get endpoints\").", info.Mapping.Resource, o.cmdFullName) } endpointsName := types.NamespacedName{ Namespace: endpoints.Namespace, Name: endpoints.Name, } scaleRefs, err := findScalableResourcesForEndpoints(endpoints, decoder, getPod, getController) if err != nil { return fmt.Errorf("unable to calculate scalable resources for service %s/%s: %v", endpoints.Namespace, endpoints.Name, err) } for ref := range scaleRefs { targetScaleRefs[ref] = endpointsName } idleInfo := idleUpdateInfo{ obj: endpoints, scaleRefs: scaleRefs, } endpointsInfo[endpointsName] = idleInfo return nil }) return endpointsInfo, targetScaleRefs, err }