Example #1
0
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion string) {
	if s, err := labels.ParseSelector(query.Get("labels")); err != nil {
		label = labels.Everything()
	} else {
		label = s
	}
	if s, err := labels.ParseSelector(query.Get("fields")); err != nil {
		field = labels.Everything()
	} else {
		field = s
	}
	resourceVersion = query.Get("resourceVersion")
	return
}
Example #2
0
// 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
}
Example #3
0
// ParseSelector parses the given string as a resource label selector. Optional.
func (r *Request) ParseSelector(item string) *Request {
	if r.err != nil {
		return r
	}
	r.selector, r.err = labels.ParseSelector(item)
	return r
}
Example #4
0
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion uint64) {
	if s, err := labels.ParseSelector(query.Get("labels")); err != nil {
		label = labels.Everything()
	} else {
		label = s
	}
	if s, err := labels.ParseSelector(query.Get("fields")); err != nil {
		field = labels.Everything()
	} else {
		field = s
	}
	if rv, err := strconv.ParseUint(query.Get("resourceVersion"), 10, 64); err == nil {
		resourceVersion = rv
	}
	return label, field, resourceVersion
}
Example #5
0
func parseSelectorOrDie(s string) labels.Selector {
	selector, err := labels.ParseSelector(s)
	if err != nil {
		panic(err)
	}
	return selector
}
Example #6
0
func (self *realPodsApi) getNodeSelector(nodeList *nodes.NodeList) (labels.Selector, error) {
	nodeLabels := []string{}
	for host := range nodeList.Items {
		nodeLabels = append(nodeLabels, fmt.Sprintf("DesiredState.Host==%s", host))
	}
	glog.V(2).Infof("using labels %v to find pods", nodeLabels)
	return labels.ParseSelector(strings.Join(nodeLabels, ","))
}
Example #7
0
func (f *Factory) NewCmdGet(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "get [(-o|--output=)json|yaml|...] <resource> [<id>]",
		Short: "Display one or many resources",
		Long: `Display one or many resources.

Possible resources include pods (po), replication controllers (rc), services
(se), minions (mi), or events (ev).

If you specify a Go template, you can use any fields defined for the API version
you are connecting to the server with.

Examples:
  $ kubectl get pods
  <list all pods in ps output format>

  $ kubectl get replicationController 1234-56-7890-234234-456456
  <list single replication controller in ps output format>

  $ kubectl get -f json pod 1234-56-7890-234234-456456
  <list single pod in json output format>`,
		Run: func(cmd *cobra.Command, args []string) {
			mapping, namespace, name := ResourceOrTypeFromArgs(cmd, args, f.Mapper)

			selector := GetFlagString(cmd, "selector")
			labels, err := labels.ParseSelector(selector)
			checkErr(err)

			client, err := f.Client(cmd, mapping)
			checkErr(err)

			outputFormat := GetFlagString(cmd, "output")
			templateFile := GetFlagString(cmd, "template")
			defaultPrinter, err := f.Printer(cmd, mapping, GetFlagBool(cmd, "no-headers"))
			checkErr(err)

			outputVersion := GetFlagString(cmd, "output-version")
			if len(outputVersion) == 0 {
				outputVersion = mapping.APIVersion
			}
			printer, err := kubectl.GetPrinter(outputVersion, outputFormat, templateFile, defaultPrinter)
			checkErr(err)

			obj, err := kubectl.NewRESTHelper(client, mapping).Get(namespace, name, labels)
			checkErr(err)

			if err := printer.PrintObj(obj, out); err != nil {
				checkErr(fmt.Errorf("Unable to output the provided object: %v", err))
			}
		},
	}
	cmd.Flags().StringP("output", "o", "", "Output format: json|yaml|template|templatefile")
	cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version)")
	cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers")
	cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when --output=template or --output=templatefile")
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
	return cmd
}
Example #8
0
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion string, err error) {
	s, perr := labels.ParseSelector(query.Get("labels"))
	if perr != nil {
		err = perr
		return
	}
	label = s

	s, perr = labels.ParseSelector(query.Get("fields"))
	if perr != nil {
		err = perr
		return
	}
	field = s

	resourceVersion = query.Get("resourceVersion")
	return
}
Example #9
0
// SelectorParam defines a selector that should be applied to the object types to load.
// This will not affect files loaded from disk or URL. If the parameter is empty it is
// a no-op - to select all resources invoke `b.Selector(labels.Everything)`.
func (b *Builder) SelectorParam(s string) *Builder {
	selector, err := labels.ParseSelector(s)
	if err != nil {
		b.errs = append(b.errs, fmt.Errorf("the provided selector %q is not valid: %v", s, err))
	}
	if selector.Empty() {
		return b
	}
	return b.Selector(selector)
}
// ParseSelectorParam parses the given string as a resource label selector.
// This is a convenience function so you don't have to first check that it's a
// validly formatted selector.
func (r *Request) ParseSelectorParam(paramName, item string) *Request {
	if r.err != nil {
		return r
	}
	sel, err := labels.ParseSelector(item)
	if err != nil {
		r.err = err
		return r
	}
	return r.setParam(paramName, sel.String())
}
func validateLabels(a, b string) bool {
	sA, _ := labels.ParseSelector(a)
	sB, _ := labels.ParseSelector(b)
	return sA.String() == sB.String()
}
Example #12
0
// handleRESTStorage is the main dispatcher for a storage object.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The s accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (s *APIServer) handleRESTStorage(parts []string, req *http.Request, w http.ResponseWriter, storage RESTStorage) {
	sync := req.URL.Query().Get("sync") == "true"
	timeout := parseTimeout(req.URL.Query().Get("timeout"))
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			selector, err := labels.ParseSelector(req.URL.Query().Get("labels"))
			if err != nil {
				internalError(err, w)
				return
			}
			list, err := storage.List(selector)
			if err != nil {
				internalError(err, w)
				return
			}
			writeJSON(http.StatusOK, list, w)
		case 2:
			item, err := storage.Get(parts[1])
			if IsNotFound(err) {
				notFound(w, req)
				return
			}
			if err != nil {
				internalError(err, w)
				return
			}
			writeJSON(http.StatusOK, item, w)
		default:
			notFound(w, req)
		}

	case "POST":
		if len(parts) != 1 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			internalError(err, w)
			return
		}
		obj, err := storage.Extract(body)
		if IsNotFound(err) {
			notFound(w, req)
			return
		}
		if err != nil {
			internalError(err, w)
			return
		}
		out, err := storage.Create(obj)
		if IsNotFound(err) {
			notFound(w, req)
			return
		}
		if err != nil {
			internalError(err, w)
			return
		}
		op := s.createOperation(out, sync, timeout)
		s.finishReq(op, w)

	case "DELETE":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		out, err := storage.Delete(parts[1])
		if IsNotFound(err) {
			notFound(w, req)
			return
		}
		if err != nil {
			internalError(err, w)
			return
		}
		op := s.createOperation(out, sync, timeout)
		s.finishReq(op, w)

	case "PUT":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			internalError(err, w)
			return
		}
		obj, err := storage.Extract(body)
		if IsNotFound(err) {
			notFound(w, req)
			return
		}
		if err != nil {
			internalError(err, w)
			return
		}
		out, err := storage.Update(obj)
		if IsNotFound(err) {
			notFound(w, req)
			return
		}
		if err != nil {
			internalError(err, w)
			return
		}
		op := s.createOperation(out, sync, timeout)
		s.finishReq(op, w)

	default:
		notFound(w, req)
	}
}
Example #13
0
// handleRESTStorage is the main dispatcher for a storage object.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The s accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w http.ResponseWriter, storage RESTStorage) {
	ctx := api.NewContext()
	sync := req.URL.Query().Get("sync") == "true"
	timeout := parseTimeout(req.URL.Query().Get("timeout"))
	// TODO for now, we pull namespace from query parameter, but according to spec, it must go in resource path in future PR
	// if a namespace if specified, it's always used.
	// for list/watch operations, a namespace is not required if omitted.
	// for all other operations, if namespace is omitted, we will default to default namespace.
	namespace := req.URL.Query().Get("namespace")
	if len(namespace) > 0 {
		ctx = api.WithNamespace(ctx, namespace)
	}
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			label, err := labels.ParseSelector(req.URL.Query().Get("labels"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			field, err := labels.ParseSelector(req.URL.Query().Get("fields"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			list, err := storage.List(ctx, label, field)
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			if err := h.setSelfLink(list, req); err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, list, w)
		case 2:
			item, err := storage.Get(api.WithNamespaceDefaultIfNone(ctx), parts[1])
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			if err := h.setSelfLink(item, req); err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, item, w)
		default:
			notFound(w, req)
		}

	case "POST":
		if len(parts) != 1 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		out, err := storage.Create(api.WithNamespaceDefaultIfNone(ctx), obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, curry(h.setSelfLinkAddName, req))
		h.finishReq(op, req, w)

	case "DELETE":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		out, err := storage.Delete(api.WithNamespaceDefaultIfNone(ctx), parts[1])
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, nil)
		h.finishReq(op, req, w)

	case "PUT":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		out, err := storage.Update(api.WithNamespaceDefaultIfNone(ctx), obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, curry(h.setSelfLink, req))
		h.finishReq(op, req, w)

	default:
		notFound(w, req)
	}
}
Example #14
0
// handleREST is the main dispatcher for the server.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The server accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (server *ApiServer) handleREST(parts []string, requestUrl *url.URL, req *http.Request, w http.ResponseWriter, storage RESTStorage) {
	sync := requestUrl.Query().Get("sync") == "true"
	timeout, err := time.ParseDuration(requestUrl.Query().Get("timeout"))
	if err != nil && len(requestUrl.Query().Get("timeout")) > 0 {
		log.Printf("Failed to parse: %#v '%s'", err, requestUrl.Query().Get("timeout"))
		timeout = time.Second * 30
	}
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			selector, err := labels.ParseSelector(requestUrl.Query().Get("labels"))
			if err != nil {
				server.error(err, w)
				return
			}
			controllers, err := storage.List(selector)
			if err != nil {
				server.error(err, w)
				return
			}
			server.write(http.StatusOK, controllers, w)
		case 2:
			item, err := storage.Get(parts[1])
			if err != nil {
				server.error(err, w)
				return
			}
			if item == nil {
				server.notFound(req, w)
				return
			}
			server.write(200, item, w)
		default:
			server.notFound(req, w)
		}
		return
	case "POST":
		if len(parts) != 1 {
			server.notFound(req, w)
			return
		}
		body, err := server.readBody(req)
		if err != nil {
			server.error(err, w)
			return
		}
		obj, err := storage.Extract(body)
		if err != nil {
			server.error(err, w)
			return
		}
		out, err := storage.Create(obj)
		if err == nil && sync {
			obj, err = server.waitForObject(out, timeout)
		}
		if err != nil {
			server.error(err, w)
			return
		}
		var statusCode int
		if sync {
			statusCode = http.StatusOK
		} else {
			statusCode = http.StatusAccepted
		}
		server.write(statusCode, obj, w)
		return
	case "DELETE":
		if len(parts) != 2 {
			server.notFound(req, w)
			return
		}
		out, err := storage.Delete(parts[1])
		var obj interface{}
		obj = Status{Success: true}
		if err == nil && sync {
			obj, err = server.waitForObject(out, timeout)
		}
		if err != nil {
			server.error(err, w)
			return
		}
		var statusCode int
		if sync {
			statusCode = http.StatusOK
		} else {
			statusCode = http.StatusAccepted
		}
		server.write(statusCode, obj, w)
		return
	case "PUT":
		if len(parts) != 2 {
			server.notFound(req, w)
			return
		}
		body, err := server.readBody(req)
		if err != nil {
			server.error(err, w)
		}
		obj, err := storage.Extract(body)
		if err != nil {
			server.error(err, w)
			return
		}
		out, err := storage.Update(obj)
		if err == nil && sync {
			obj, err = server.waitForObject(out, timeout)
		}
		if err != nil {
			server.error(err, w)
			return
		}
		var statusCode int
		if sync {
			statusCode = http.StatusOK
		} else {
			statusCode = http.StatusAccepted
		}
		server.write(statusCode, obj, w)
		return
	default:
		server.notFound(req, w)
	}
}
Example #15
0
func TestListPodListSelection(t *testing.T) {
	podRegistry := registrytest.NewPodRegistry(nil)
	podRegistry.Pods = &api.PodList{
		Items: []api.Pod{
			{
				JSONBase: api.JSONBase{ID: "foo"},
			}, {
				JSONBase:     api.JSONBase{ID: "bar"},
				DesiredState: api.PodState{Host: "barhost"},
			}, {
				JSONBase:     api.JSONBase{ID: "baz"},
				DesiredState: api.PodState{Status: "bazstatus"},
			}, {
				JSONBase: api.JSONBase{ID: "qux"},
				Labels:   map[string]string{"label": "qux"},
			}, {
				JSONBase: api.JSONBase{ID: "zot"},
			},
		},
	}
	storage := REST{
		registry: podRegistry,
	}

	table := []struct {
		label, field string
		expectedIDs  util.StringSet
	}{
		{
			expectedIDs: util.NewStringSet("foo", "bar", "baz", "qux", "zot"),
		}, {
			field:       "ID=zot",
			expectedIDs: util.NewStringSet("zot"),
		}, {
			label:       "label=qux",
			expectedIDs: util.NewStringSet("qux"),
		}, {
			field:       "DesiredState.Status=bazstatus",
			expectedIDs: util.NewStringSet("baz"),
		}, {
			field:       "DesiredState.Host=barhost",
			expectedIDs: util.NewStringSet("bar"),
		}, {
			field:       "DesiredState.Host=",
			expectedIDs: util.NewStringSet("foo", "baz", "qux", "zot"),
		}, {
			field:       "DesiredState.Host!=",
			expectedIDs: util.NewStringSet("bar"),
		},
	}

	for index, item := range table {
		label, err := labels.ParseSelector(item.label)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		field, err := labels.ParseSelector(item.field)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		podsObj, err := storage.List(label, field)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		pods := podsObj.(*api.PodList)

		if e, a := len(item.expectedIDs), len(pods.Items); e != a {
			t.Errorf("%v: Expected %v, got %v", index, e, a)
		}
		for _, pod := range pods.Items {
			if !item.expectedIDs.Has(pod.ID) {
				t.Errorf("%v: Unexpected pod %v", index, pod.ID)
			}
			t.Logf("%v: Got pod ID: %v", index, pod.ID)
		}
	}
}
Example #16
0
func TestListPodListSelection(t *testing.T) {
	podRegistry := registrytest.NewPodRegistry(nil)
	podRegistry.Pods = &api.PodList{
		Items: []api.Pod{
			{
				ObjectMeta: api.ObjectMeta{Name: "foo"},
			}, {
				ObjectMeta: api.ObjectMeta{Name: "bar"},
				Status:     api.PodStatus{Host: "barhost"},
			}, {
				ObjectMeta: api.ObjectMeta{Name: "baz"},
				Status:     api.PodStatus{Phase: "bazstatus"},
			}, {
				ObjectMeta: api.ObjectMeta{
					Name:   "qux",
					Labels: map[string]string{"label": "qux"},
				},
			}, {
				ObjectMeta: api.ObjectMeta{Name: "zot"},
			},
		},
	}
	storage := REST{
		registry: podRegistry,
		podCache: &fakeCache{statusToReturn: &api.PodStatus{}},
	}
	ctx := api.NewContext()

	table := []struct {
		label, field string
		expectedIDs  util.StringSet
	}{
		{
			expectedIDs: util.NewStringSet("foo", "bar", "baz", "qux", "zot"),
		}, {
			field:       "name=zot",
			expectedIDs: util.NewStringSet("zot"),
		}, {
			label:       "label=qux",
			expectedIDs: util.NewStringSet("qux"),
		}, {
			field:       "Status.Phase=bazstatus",
			expectedIDs: util.NewStringSet("baz"),
		}, {
			field:       "Status.Host=barhost",
			expectedIDs: util.NewStringSet("bar"),
		}, {
			field:       "Status.Host=",
			expectedIDs: util.NewStringSet("foo", "baz", "qux", "zot"),
		}, {
			field:       "Status.Host!=",
			expectedIDs: util.NewStringSet("bar"),
		},
	}

	for index, item := range table {
		label, err := labels.ParseSelector(item.label)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		field, err := labels.ParseSelector(item.field)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		podsObj, err := storage.List(ctx, label, field)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		pods := podsObj.(*api.PodList)

		if e, a := len(item.expectedIDs), len(pods.Items); e != a {
			t.Errorf("%v: Expected %v, got %v", index, e, a)
		}
		for _, pod := range pods.Items {
			if !item.expectedIDs.Has(pod.Name) {
				t.Errorf("%v: Unexpected pod %v", index, pod.Name)
			}
			t.Logf("%v: Got pod Name: %v", index, pod.Name)
		}
	}
}
Example #17
0
// handleREST is the main dispatcher for the server.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The server accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (server *ApiServer) handleREST(parts []string, requestUrl *url.URL, req *http.Request, w http.ResponseWriter, storage RESTStorage) {
	sync := requestUrl.Query().Get("sync") == "true"
	timeout := parseTimeout(requestUrl.Query().Get("timeout"))
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			selector, err := labels.ParseSelector(requestUrl.Query().Get("labels"))
			if err != nil {
				server.error(err, w)
				return
			}
			list, err := storage.List(selector)
			if err != nil {
				server.error(err, w)
				return
			}
			server.write(http.StatusOK, list, w)
		case 2:
			item, err := storage.Get(parts[1])
			if err != nil {
				server.error(err, w)
				return
			}
			if item == nil {
				server.notFound(req, w)
				return
			}
			server.write(http.StatusOK, item, w)
		default:
			server.notFound(req, w)
		}
	case "POST":
		if len(parts) != 1 {
			server.notFound(req, w)
			return
		}
		body, err := server.readBody(req)
		if err != nil {
			server.error(err, w)
			return
		}
		obj, err := storage.Extract(body)
		if err != nil {
			server.error(err, w)
			return
		}
		out, err := storage.Create(obj)
		if err != nil {
			server.error(err, w)
			return
		}
		server.finishReq(out, sync, timeout, w)
	case "DELETE":
		if len(parts) != 2 {
			server.notFound(req, w)
			return
		}
		out, err := storage.Delete(parts[1])
		if err != nil {
			server.error(err, w)
			return
		}
		server.finishReq(out, sync, timeout, w)
	case "PUT":
		if len(parts) != 2 {
			server.notFound(req, w)
			return
		}
		body, err := server.readBody(req)
		if err != nil {
			server.error(err, w)
		}
		obj, err := storage.Extract(body)
		if err != nil {
			server.error(err, w)
			return
		}
		out, err := storage.Update(obj)
		if err != nil {
			server.error(err, w)
			return
		}
		server.finishReq(out, sync, timeout, w)
	default:
		server.notFound(req, w)
	}
}
Example #18
0
func (f *Factory) NewCmdGet(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "get [(-o|--output=)json|yaml|...] <resource> [<id>]",
		Short: "Display one or many resources",
		Long: `Display one or many resources.

Possible resources include pods (po), replication controllers (rc), services
(se), minions (mi), or events (ev).

If you specify a Go template, you can use any fields defined for the API version
you are connecting to the server with.

Examples:
  $ kubectl get pods
  <list all pods in ps output format>

  $ kubectl get replicationController 1234-56-7890-234234-456456
  <list single replication controller in ps output format>

  $ kubectl get -o json pod 1234-56-7890-234234-456456
  <list single pod in json output format>`,
		Run: func(cmd *cobra.Command, args []string) {
			mapping, namespace, name := ResourceOrTypeFromArgs(cmd, args, f.Mapper)

			selector := GetFlagString(cmd, "selector")
			labelSelector, err := labels.ParseSelector(selector)
			checkErr(err)

			client, err := f.RESTClient(cmd, mapping)
			checkErr(err)

			outputFormat := GetFlagString(cmd, "output")
			templateFile := GetFlagString(cmd, "template")
			defaultPrinter, err := f.Printer(cmd, mapping, GetFlagBool(cmd, "no-headers"))
			checkErr(err)

			outputVersion := GetFlagString(cmd, "output-version")
			if len(outputVersion) == 0 {
				outputVersion = mapping.APIVersion
			}

			printer, err := kubectl.GetPrinter(outputFormat, templateFile, outputVersion, mapping.ObjectConvertor, defaultPrinter)
			checkErr(err)

			restHelper := resource.NewHelper(client, mapping)
			var obj runtime.Object
			if len(name) == 0 {
				obj, err = restHelper.List(namespace, labelSelector)
			} else {
				obj, err = restHelper.Get(namespace, name)
			}
			checkErr(err)

			isWatch, isWatchOnly := GetFlagBool(cmd, "watch"), GetFlagBool(cmd, "watch-only")

			// print the current object
			if !isWatchOnly {
				if err := printer.PrintObj(obj, out); err != nil {
					checkErr(fmt.Errorf("unable to output the provided object: %v", err))
				}
			}

			// print watched changes
			if isWatch || isWatchOnly {
				rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
				checkErr(err)

				w, err := restHelper.Watch(namespace, rv, labelSelector, labels.Everything())
				checkErr(err)

				kubectl.WatchLoop(w, printer, out)
			}
		},
	}
	cmd.Flags().StringP("output", "o", "", "Output format: json|yaml|template|templatefile")
	cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version)")
	cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers")
	cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when --output=template or --output=templatefile")
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
	cmd.Flags().BoolP("watch", "w", false, "After listing/getting the requested object, watch for changes.")
	cmd.Flags().Bool("watch-only", false, "Watch for changes to the requseted object(s), without listing/getting first.")
	return cmd
}
func TestSelectionPredicate(t *testing.T) {
	table := map[string]struct {
		labelSelector, fieldSelector string
		labels, fields               labels.Set
		err                          error
		shouldMatch                  bool
	}{
		"A": {
			labelSelector: "name=foo",
			fieldSelector: "uid=12345",
			labels:        labels.Set{"name": "foo"},
			fields:        labels.Set{"uid": "12345"},
			shouldMatch:   true,
		},
		"B": {
			labelSelector: "name=foo",
			fieldSelector: "uid=12345",
			labels:        labels.Set{"name": "foo"},
			fields:        labels.Set{},
			shouldMatch:   false,
		},
		"C": {
			labelSelector: "name=foo",
			fieldSelector: "uid=12345",
			labels:        labels.Set{},
			fields:        labels.Set{"uid": "12345"},
			shouldMatch:   false,
		},
		"error": {
			labelSelector: "name=foo",
			fieldSelector: "uid=12345",
			err:           errors.New("maybe this is a 'wrong object type' error"),
			shouldMatch:   false,
		},
	}

	for name, item := range table {
		parsedLabel, err := labels.ParseSelector(item.labelSelector)
		if err != nil {
			panic(err)
		}
		parsedField, err := labels.ParseSelector(item.fieldSelector)
		if err != nil {
			panic(err)
		}
		sp := &SelectionPredicate{
			Label: parsedLabel,
			Field: parsedField,
			GetAttrs: func(runtime.Object) (label, field labels.Set, err error) {
				return item.labels, item.fields, item.err
			},
		}
		got, err := sp.Matches(&Ignored{})
		if e, a := item.err, err; e != a {
			t.Errorf("%v: expected %v, got %v", name, e, a)
			continue
		}
		if e, a := item.shouldMatch, got; e != a {
			t.Errorf("%v: expected %v, got %v", name, e, a)
		}
	}
}
// handleRESTStorage is the main dispatcher for a storage object.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The s accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w http.ResponseWriter, storage RESTStorage, namespace, kind string) {
	ctx := api.WithNamespace(api.NewContext(), namespace)
	sync := req.URL.Query().Get("sync") == "true"
	timeout := parseTimeout(req.URL.Query().Get("timeout"))
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			label, err := labels.ParseSelector(req.URL.Query().Get("labels"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			field, err := labels.ParseSelector(req.URL.Query().Get("fields"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			lister, ok := storage.(RESTLister)
			if !ok {
				errorJSON(errors.NewMethodNotSupported(kind, "list"), h.codec, w)
				return
			}
			list, err := lister.List(ctx, label, field)
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			if err := h.setSelfLink(list, req); err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, list, w)
		case 2:
			getter, ok := storage.(RESTGetter)
			if !ok {
				errorJSON(errors.NewMethodNotSupported(kind, "get"), h.codec, w)
				return
			}
			item, err := getter.Get(ctx, parts[1])
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			if err := h.setSelfLink(item, req); err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, item, w)
		default:
			notFound(w, req)
		}

	case "POST":
		if len(parts) != 1 {
			notFound(w, req)
			return
		}
		creater, ok := storage.(RESTCreater)
		if !ok {
			errorJSON(errors.NewMethodNotSupported(kind, "create"), h.codec, w)
			return
		}

		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}

		// invoke admission control
		err = h.admissionControl.Admit(admission.NewAttributesRecord(obj, namespace, parts[0], "CREATE"))
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}

		out, err := creater.Create(ctx, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, curry(h.setSelfLinkAddName, req))
		h.finishReq(op, req, w)

	case "DELETE":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		deleter, ok := storage.(RESTDeleter)
		if !ok {
			errorJSON(errors.NewMethodNotSupported(kind, "delete"), h.codec, w)
			return
		}

		// invoke admission control
		err := h.admissionControl.Admit(admission.NewAttributesRecord(nil, namespace, parts[0], "DELETE"))
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}

		out, err := deleter.Delete(ctx, parts[1])
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, nil)
		h.finishReq(op, req, w)

	case "PUT":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		updater, ok := storage.(RESTUpdater)
		if !ok {
			errorJSON(errors.NewMethodNotSupported(kind, "create"), h.codec, w)
			return
		}

		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}

		// invoke admission control
		err = h.admissionControl.Admit(admission.NewAttributesRecord(obj, namespace, parts[0], "UPDATE"))
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}

		out, err := updater.Update(ctx, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout, curry(h.setSelfLink, req))
		h.finishReq(op, req, w)

	default:
		notFound(w, req)
	}
}
Example #21
0
// handleRESTStorage is the main dispatcher for a storage object.  It switches on the HTTP method, and then
// on path length, according to the following table:
//   Method     Path          Action
//   GET        /foo          list
//   GET        /foo/bar      get 'bar'
//   POST       /foo          create
//   PUT        /foo/bar      update 'bar'
//   DELETE     /foo/bar      delete 'bar'
// Returns 404 if the method/pattern doesn't match one of these entries
// The s accepts several query parameters:
//    sync=[false|true] Synchronous request (only applies to create, update, delete operations)
//    timeout=<duration> Timeout for synchronous requests, only applies if sync=true
//    labels=<label-selector> Used for filtering list operations
func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w http.ResponseWriter, storage RESTStorage) {
	sync := req.URL.Query().Get("sync") == "true"
	timeout := parseTimeout(req.URL.Query().Get("timeout"))
	switch req.Method {
	case "GET":
		switch len(parts) {
		case 1:
			label, err := labels.ParseSelector(req.URL.Query().Get("labels"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			field, err := labels.ParseSelector(req.URL.Query().Get("fields"))
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			list, err := storage.List(label, field)
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, list, w)
		case 2:
			item, err := storage.Get(parts[1])
			if err != nil {
				errorJSON(err, h.codec, w)
				return
			}
			writeJSON(http.StatusOK, h.codec, item, w)
		default:
			notFound(w, req)
		}

	case "POST":
		if len(parts) != 1 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		out, err := storage.Create(obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout)
		h.finishReq(op, req, w)

	case "DELETE":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		out, err := storage.Delete(parts[1])
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout)
		h.finishReq(op, req, w)

	case "PUT":
		if len(parts) != 2 {
			notFound(w, req)
			return
		}
		body, err := readBody(req)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		obj := storage.New()
		err = h.codec.DecodeInto(body, obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		out, err := storage.Update(obj)
		if err != nil {
			errorJSON(err, h.codec, w)
			return
		}
		op := h.createOperation(out, sync, timeout)
		h.finishReq(op, req, w)

	default:
		notFound(w, req)
	}
}