Exemple #1
0
// VersionedParams will take the provided object, serialize it to a map[string][]string using the
// implicit RESTClient API version and the provided object convertor, and then add those as parameters
// to the request. Use this to provide versioned query parameters from client libraries.
func (r *Request) VersionedParams(obj runtime.Object, convertor runtime.ObjectConvertor) *Request {
	if r.err != nil {
		return r
	}
	versioned, err := convertor.ConvertToVersion(obj, r.groupVersion.String())
	if err != nil {
		r.err = err
		return r
	}
	params, err := queryparams.Convert(versioned)
	if err != nil {
		r.err = err
		return r
	}
	for k, v := range params {
		for _, value := range v {
			// TODO: Move it to setParam method, once we get rid of
			// FieldSelectorParam & LabelSelectorParam methods.
			if k == unversioned.LabelSelectorQueryParam(r.groupVersion.String()) && value == "" {
				// Don't set an empty selector for backward compatibility.
				// Since there is no way to get the difference between empty
				// and unspecified string, we don't set it to avoid having
				// labelSelector= param in every request.
				continue
			}
			if k == unversioned.FieldSelectorQueryParam(r.groupVersion.String()) {
				if value == "" {
					// Don't set an empty selector for backward compatibility.
					// Since there is no way to get the difference between empty
					// and unspecified string, we don't set it to avoid having
					// fieldSelector= param in every request.
					continue
				}
				// TODO: Filtering should be handled somewhere else.
				selector, err := fields.ParseSelector(value)
				if err != nil {
					r.err = fmt.Errorf("unparsable field selector: %v", err)
					return r
				}
				filteredSelector, err := selector.Transform(
					func(field, value string) (newField, newValue string, err error) {
						return fieldMappings.filterField(r.groupVersion, r.resource, field, value)
					})
				if err != nil {
					r.err = fmt.Errorf("untransformable field selector: %v", err)
					return r
				}
				value = filteredSelector.String()
			}

			r.setParam(k, value)
		}
	}
	return r
}
Exemple #2
0
// EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
// Returns an error if conversion is not possible.
func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersion) (url.Values, error) {
	gvk, _, err := c.typer.ObjectKind(obj)
	if err != nil {
		return nil, err
	}
	if to != gvk.GroupVersion() {
		out, err := c.convertor.ConvertToVersion(obj, to)
		if err != nil {
			return nil, err
		}
		obj = out
	}
	return queryparams.Convert(obj)
}
func (e *Streamer) setupRequestParameters(obj runtime.Object) error {
	versioned, err := api.Scheme.ConvertToVersion(obj, e.config.Version)
	if err != nil {
		return err
	}
	params, err := queryparams.Convert(versioned)
	if err != nil {
		return err
	}
	for k, v := range params {
		for _, vv := range v {
			e.req.Param(k, vv)
		}
	}
	return nil
}
Exemple #4
0
// VersionedParams will take the provided object, serialize it to a map[string][]string using the
// implicit RESTClient API version and the provided object convertor, and then add those as parameters
// to the request. Use this to provide versioned query parameters from client libraries.
func (r *Request) VersionedParams(obj runtime.Object, convertor runtime.ObjectConvertor) *Request {
	if r.err != nil {
		return r
	}
	versioned, err := convertor.ConvertToVersion(obj, r.apiVersion)
	if err != nil {
		r.err = err
		return r
	}
	params, err := queryparams.Convert(versioned)
	if err != nil {
		r.err = err
		return r
	}
	for k, v := range params {
		for _, vv := range v {
			r.setParam(k, vv)
		}
	}
	return r
}
func TestBinaryBuildRequestOptions(t *testing.T) {
	r := &newer.BinaryBuildRequestOptions{
		AsFile: "Dockerfile",
		Commit: "abcdef",
	}
	versioned, err := knewer.Scheme.ConvertToVersion(r, "v1")
	if err != nil {
		t.Fatal(err)
	}
	params, err := queryparams.Convert(versioned)
	if err != nil {
		t.Fatal(err)
	}
	decoded := &older.BinaryBuildRequestOptions{}
	if err := knewer.Scheme.Convert(&params, decoded); err != nil {
		t.Fatal(err)
	}
	if decoded.Commit != "abcdef" || decoded.AsFile != "Dockerfile" {
		t.Errorf("unexpected decoded object: %#v", decoded)
	}
}
Exemple #6
0
func (parameterCodec) EncodeParameters(obj runtime.Object, to unversioned.GroupVersion) (url.Values, error) {
	return queryparams.Convert(obj)
}
Exemple #7
0
func TestConvert(t *testing.T) {
	sinceSeconds := int64(123)
	sinceTime := unversioned.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)

	tests := []struct {
		input    interface{}
		expected url.Values
	}{
		{
			input: &foo{
				Str: "hello",
			},
			expected: url.Values{"str": {"hello"}},
		},
		{
			input: &foo{
				Str:     "test string",
				Slice:   []string{"one", "two", "three"},
				Integer: 234,
				Boolean: true,
			},
			expected: url.Values{"str": {"test string"}, "slice": {"one", "two", "three"}, "integer": {"234"}, "boolean": {"true"}},
		},
		{
			input: &foo{
				Str:       "named types",
				NamedStr:  "value1",
				NamedBool: true,
			},
			expected: url.Values{"str": {"named types"}, "namedStr": {"value1"}, "namedBool": {"true"}},
		},
		{
			input: &foo{
				Str: "don't ignore embedded struct",
				Foobar: bar{
					Float1: 5.0,
				},
			},
			expected: url.Values{"str": {"don't ignore embedded struct"}, "float1": {"5"}, "float2": {"0"}},
		},
		{
			// Ignore untagged fields
			input: &bar{
				Float1:   23.5,
				Float2:   100.7,
				Int1:     1,
				Int2:     2,
				Int3:     3,
				Ignored:  1,
				Ignored2: "ignored",
			},
			expected: url.Values{"float1": {"23.5"}, "float2": {"100.7"}, "int1": {"1"}, "int2": {"2"}, "int3": {"3"}},
		},
		{
			// include fields that are not tagged omitempty
			input: &foo{
				NamedStr: "named str",
			},
			expected: url.Values{"str": {""}, "namedStr": {"named str"}},
		},
		{
			input: &baz{
				Ptr:  intp(5),
				Bptr: boolp(true),
			},
			expected: url.Values{"ptr": {"5"}, "bptr": {"true"}},
		},
		{
			input: &baz{
				Bptr: boolp(true),
			},
			expected: url.Values{"ptr": {""}, "bptr": {"true"}},
		},
		{
			input: &baz{
				Ptr: intp(5),
			},
			expected: url.Values{"ptr": {"5"}},
		},
		{
			input: &childStructs{
				Container:    "mycontainer",
				Follow:       true,
				Previous:     true,
				SinceSeconds: &sinceSeconds,
				SinceTime:    &sinceTime, // test a custom marshaller
				EmptyTime:    nil,        // test a nil custom marshaller without omitempty
			},
			expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "sinceTime": {"2000-01-01T12:34:56Z"}, "emptyTime": {""}},
		},
		{
			input: &childStructs{
				Container:    "mycontainer",
				Follow:       true,
				Previous:     true,
				SinceSeconds: &sinceSeconds,
				SinceTime:    nil, // test a nil custom marshaller with omitempty
			},
			expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "emptyTime": {""}},
		},
	}

	for _, test := range tests {
		result, err := queryparams.Convert(test.input)
		if err != nil {
			t.Errorf("Unexpected error while converting %#v: %v", test.input, err)
		}
		validateResult(t, test.input, result, test.expected)
	}
}
func TestConvert(t *testing.T) {
	tests := []struct {
		input    interface{}
		expected url.Values
	}{
		{
			input: &foo{
				Str: "hello",
			},
			expected: url.Values{"str": {"hello"}},
		},
		{
			input: &foo{
				Str:     "test string",
				Slice:   []string{"one", "two", "three"},
				Integer: 234,
				Boolean: true,
			},
			expected: url.Values{"str": {"test string"}, "slice": {"one", "two", "three"}, "integer": {"234"}, "boolean": {"true"}},
		},
		{
			input: &foo{
				Str:       "named types",
				NamedStr:  "value1",
				NamedBool: true,
			},
			expected: url.Values{"str": {"named types"}, "namedStr": {"value1"}, "namedBool": {"true"}},
		},
		{
			input: &foo{
				Str: "don't ignore embedded struct",
				Foobar: bar{
					Float1: 5.0,
				},
			},
			expected: url.Values{"str": {"don't ignore embedded struct"}, "float1": {"5"}, "float2": {"0"}},
		},
		{
			// Ignore untagged fields
			input: &bar{
				Float1:   23.5,
				Float2:   100.7,
				Int1:     1,
				Int2:     2,
				Int3:     3,
				Ignored:  1,
				Ignored2: "ignored",
			},
			expected: url.Values{"float1": {"23.5"}, "float2": {"100.7"}, "int1": {"1"}, "int2": {"2"}, "int3": {"3"}},
		},
		{
			// include fields that are not tagged omitempty
			input: &foo{
				NamedStr: "named str",
			},
			expected: url.Values{"str": {""}, "namedStr": {"named str"}},
		},
		{
			input: &baz{
				Ptr:  intp(5),
				Bptr: boolp(true),
			},
			expected: url.Values{"ptr": {"5"}, "bptr": {"true"}},
		},
		{
			input: &baz{
				Bptr: boolp(true),
			},
			expected: url.Values{"ptr": {""}, "bptr": {"true"}},
		},
		{
			input: &baz{
				Ptr: intp(5),
			},
			expected: url.Values{"ptr": {"5"}},
		},
	}

	for _, test := range tests {
		result, err := queryparams.Convert(test.input)
		if err != nil {
			t.Errorf("Unexpected error while converting %#v: %v", test.input, err)
		}
		validateResult(t, test.input, result, test.expected)
	}
}
Exemple #9
0
// Execute sends a remote command execution request, upgrading the
// connection and creating streams to represent stdin/stdout/stderr. Data is
// copied between these streams and the supplied stdin/stdout/stderr parameters.
func (e *Executor) Execute() error {
	opts := api.PodExecOptions{
		Stdin:   (e.stdin != nil),
		Stdout:  (e.stdout != nil),
		Stderr:  (!e.tty && e.stderr != nil),
		TTY:     e.tty,
		Command: e.command,
	}

	versioned, err := api.Scheme.ConvertToVersion(&opts, e.config.Version)
	if err != nil {
		return err
	}
	params, err := queryparams.Convert(versioned)
	if err != nil {
		return err
	}
	for k, v := range params {
		for _, vv := range v {
			e.req.Param(k, vv)
		}
	}

	if e.upgrader == nil {
		e.upgrader = &defaultUpgrader{}
	}
	conn, err := e.upgrader.upgrade(e.req, e.config)
	if err != nil {
		return err
	}
	defer conn.Close()

	doneChan := make(chan struct{}, 2)
	errorChan := make(chan error)

	cp := func(s string, dst io.Writer, src io.Reader) {
		glog.V(4).Infof("Copying %s", s)
		defer glog.V(4).Infof("Done copying %s", s)
		if _, err := io.Copy(dst, src); err != nil && err != io.EOF {
			glog.Errorf("Error copying %s: %v", s, err)
		}
		if s == api.StreamTypeStdout || s == api.StreamTypeStderr {
			doneChan <- struct{}{}
		}
	}

	headers := http.Header{}
	headers.Set(api.StreamType, api.StreamTypeError)
	errorStream, err := conn.CreateStream(headers)
	if err != nil {
		return err
	}
	go func() {
		message, err := ioutil.ReadAll(errorStream)
		if err != nil && err != io.EOF {
			errorChan <- fmt.Errorf("Error reading from error stream: %s", err)
			return
		}
		if len(message) > 0 {
			errorChan <- fmt.Errorf("Error executing remote command: %s", message)
			return
		}
	}()
	defer errorStream.Reset()

	if opts.Stdin {
		headers.Set(api.StreamType, api.StreamTypeStdin)
		remoteStdin, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStdin.Reset()
		// TODO this goroutine will never exit cleanly (the io.Copy never unblocks)
		// because stdin is not closed until the process exits. If we try to call
		// stdin.Close(), it returns no error but doesn't unblock the copy. It will
		// exit when the process exits, instead.
		go cp(api.StreamTypeStdin, remoteStdin, e.stdin)
	}

	waitCount := 0
	completedStreams := 0

	if opts.Stdout {
		waitCount++
		headers.Set(api.StreamType, api.StreamTypeStdout)
		remoteStdout, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStdout.Reset()
		go cp(api.StreamTypeStdout, e.stdout, remoteStdout)
	}

	if opts.Stderr && !e.tty {
		waitCount++
		headers.Set(api.StreamType, api.StreamTypeStderr)
		remoteStderr, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStderr.Reset()
		go cp(api.StreamTypeStderr, e.stderr, remoteStderr)
	}

Loop:
	for {
		select {
		case <-doneChan:
			completedStreams++
			if completedStreams == waitCount {
				break Loop
			}
		case err := <-errorChan:
			return err
		}
	}

	return nil
}