Example #1
0
File: idle.go Project: dcbw/origin
// 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)
}
Example #2
0
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
}
Example #3
0
File: idle.go Project: dcbw/origin
// 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
}