Beispiel #1
0
// NewClient returns a new client based on the passed in config. The
// codec is ignored, as the dynamic client uses it's own codec.
func NewClient(conf *restclient.Config) (*Client, error) {
	// avoid changing the original config
	confCopy := *conf
	conf = &confCopy

	// TODO: it's questionable that this should be using anything other than unstructured schema and JSON
	conf.ContentType = runtime.ContentTypeJSON
	conf.AcceptContentTypes = runtime.ContentTypeJSON

	if conf.APIPath == "" {
		conf.APIPath = "/api"
	}

	if len(conf.UserAgent) == 0 {
		conf.UserAgent = restclient.DefaultKubernetesUserAgent()
	}
	if conf.NegotiatedSerializer == nil {
		streamingInfo, _ := api.Codecs.StreamingSerializerForMediaType("application/json;stream=watch", nil)
		conf.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: dynamicCodec{}}, streamingInfo)
	}

	cl, err := restclient.RESTClientFor(conf)
	if err != nil {
		return nil, err
	}

	return &Client{cl: cl}, nil
}
Beispiel #2
0
// New creates a new WebhookAuthorizer from the provided kubeconfig file.
//
// The config's cluster field is used to refer to the remote service, user refers to the returned authorizer.
//
//     # clusters refers to the remote service.
//     clusters:
//     - name: name-of-remote-authz-service
//       cluster:
//         certificate-authority: /path/to/ca.pem      # CA for verifying the remote service.
//         server: https://authz.example.com/authorize # URL of remote service to query. Must use 'https'.
//
//     # users refers to the API server's webhook configuration.
//     users:
//     - name: name-of-api-server
//       user:
//         client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
//         client-key: /path/to/key.pem          # key matching the cert
//
// For additional HTTP configuration, refer to the kubeconfig documentation
// http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html.
func New(kubeConfigFile string) (*WebhookAuthorizer, error) {

	for _, groupVersion := range requireEnabled {
		if !registered.IsEnabledVersion(groupVersion) {
			return nil, fmt.Errorf("webhook authz plugin requires enabling extension resource: %s", groupVersion)
		}
	}

	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	loadingRules.ExplicitPath = kubeConfigFile
	loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})

	clientConfig, err := loader.ClientConfig()
	if err != nil {
		return nil, err
	}

	serializer := json.NewSerializer(json.DefaultMetaFactory, api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), false)
	codec := versioning.NewCodecForScheme(api.Scheme, serializer, serializer, encodeVersions, decodeVersions)
	clientConfig.ContentConfig.NegotiatedSerializer = runtimeserializer.NegotiatedSerializerWrapper(
		runtime.SerializerInfo{Serializer: codec},
		runtime.StreamSerializerInfo{},
	)

	restClient, err := restclient.UnversionedRESTClientFor(clientConfig)
	if err != nil {
		return nil, err
	}

	// TODO(ericchiang): Can we ensure remote service is reachable?

	return &WebhookAuthorizer{restClient}, nil
}
Beispiel #3
0
// NewGenericWebhook creates a new GenericWebhook from the provided kubeconfig file.
func NewGenericWebhook(kubeConfigFile string, groupVersions []unversioned.GroupVersion, initialBackoff time.Duration) (*GenericWebhook, error) {
	for _, groupVersion := range groupVersions {
		if !registered.IsEnabledVersion(groupVersion) {
			return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion)
		}
	}

	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	loadingRules.ExplicitPath = kubeConfigFile
	loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})

	clientConfig, err := loader.ClientConfig()
	if err != nil {
		return nil, err
	}
	codec := api.Codecs.LegacyCodec(groupVersions...)
	clientConfig.ContentConfig.NegotiatedSerializer = runtimeserializer.NegotiatedSerializerWrapper(
		runtime.SerializerInfo{Serializer: codec},
		runtime.StreamSerializerInfo{},
	)

	restClient, err := restclient.UnversionedRESTClientFor(clientConfig)
	if err != nil {
		return nil, err
	}

	// TODO(ericchiang): Can we ensure remote service is reachable?

	return &GenericWebhook{restClient, initialBackoff}, nil
}
Beispiel #4
0
// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind
// in the GroupVersionKind may be empty.
func (c *clientPoolImpl) ClientForGroupVersionKind(kind unversioned.GroupVersionKind) (*Client, error) {
	c.lock.Lock()
	defer c.lock.Unlock()

	gv := kind.GroupVersion()

	// do we have a client already configured?
	if existingClient, found := c.clients[gv]; found {
		return existingClient, nil
	}

	// avoid changing the original config
	confCopy := *c.config
	conf := &confCopy

	// we need to set the api path based on group version, if no group, default to legacy path
	conf.APIPath = c.apiPathResolverFunc(kind)

	// we need to make a client
	conf.GroupVersion = &gv

	if conf.NegotiatedSerializer == nil {
		streamingInfo, _ := api.Codecs.StreamingSerializerForMediaType("application/json;stream=watch", nil)
		conf.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: dynamicCodec{}}, streamingInfo)
	}

	dynamicClient, err := NewClient(conf)
	if err != nil {
		return nil, err
	}
	c.clients[gv] = dynamicClient
	return dynamicClient, nil
}
func setDiscoveryDefaults(config *restclient.Config) error {
	config.APIPath = ""
	config.GroupVersion = nil
	codec := runtime.NoopEncoder{Decoder: api.Codecs.UniversalDecoder()}
	config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
	if len(config.UserAgent) == 0 {
		config.UserAgent = restclient.DefaultKubernetesUserAgent()
	}
	return nil
}
Beispiel #6
0
// ContentConfig returns a restclient.ContentConfig for dynamic types.
func ContentConfig() restclient.ContentConfig {
	// TODO: it's questionable that this should be using anything other than unstructured schema and JSON
	codec := dynamicCodec{}
	streamingInfo, _ := api.Codecs.StreamingSerializerForMediaType("application/json;stream=watch", nil)
	return restclient.ContentConfig{
		AcceptContentTypes:   runtime.ContentTypeJSON,
		ContentType:          runtime.ContentTypeJSON,
		NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}, streamingInfo),
	}
}
Beispiel #7
0
func NewTestFactory() (cmdutil.Factory, *TestFactory, runtime.Codec, runtime.NegotiatedSerializer) {
	scheme, mapper, codec := newExternalScheme()
	t := &TestFactory{
		Validator: validation.NullSchema{},
		Mapper:    mapper,
		Typer:     scheme,
	}
	negotiatedSerializer := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
	return &FakeFactory{
		tf:    t,
		Codec: codec,
	}, t, codec, negotiatedSerializer
}
Beispiel #8
0
func NewTestFactory() (*cmdutil.Factory, *testFactory, runtime.Codec, runtime.NegotiatedSerializer) {
	scheme, mapper, codec := newExternalScheme()
	t := &testFactory{
		Validator: validation.NullSchema{},
		Mapper:    mapper,
		Typer:     scheme,
	}
	negotiatedSerializer := serializer.NegotiatedSerializerWrapper(
		runtime.SerializerInfo{Serializer: codec},
		runtime.StreamSerializerInfo{})
	return &cmdutil.Factory{
		Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
			priorityRESTMapper := meta.PriorityRESTMapper{
				Delegate: t.Mapper,
				ResourcePriority: []unversioned.GroupVersionResource{
					{Group: meta.AnyGroup, Version: "v1", Resource: meta.AnyResource},
				},
				KindPriority: []unversioned.GroupVersionKind{
					{Group: meta.AnyGroup, Version: "v1", Kind: meta.AnyKind},
				},
			}
			return priorityRESTMapper, t.Typer
		},
		ClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
			return t.Client, t.Err
		},
		Decoder: func(bool) runtime.Decoder {
			return codec
		},
		JSONEncoder: func() runtime.Encoder {
			return codec
		},
		Describer: func(*meta.RESTMapping) (kubectl.Describer, error) {
			return t.Describer, t.Err
		},
		Printer: func(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
			return t.Printer, t.Err
		},
		Validator: func(validate bool, cacheDir string) (validation.Schema, error) {
			return t.Validator, t.Err
		},
		DefaultNamespace: func() (string, bool, error) {
			return t.Namespace, false, t.Err
		},
		ClientConfig: func() (*restclient.Config, error) {
			return t.ClientConfig, t.Err
		},
	}, t, codec, negotiatedSerializer
}
Beispiel #9
0
// ContentConfig returns a restclient.ContentConfig for dynamic types.
func ContentConfig() restclient.ContentConfig {
	var jsonInfo runtime.SerializerInfo
	// TODO: api.Codecs here should become "pkg/apis/server/scheme" which is the minimal core you need
	// to talk to a kubernetes server
	for _, info := range api.Codecs.SupportedMediaTypes() {
		if info.MediaType == runtime.ContentTypeJSON {
			jsonInfo = info
			break
		}
	}

	jsonInfo.Serializer = dynamicCodec{}
	jsonInfo.PrettySerializer = nil
	return restclient.ContentConfig{
		AcceptContentTypes:   runtime.ContentTypeJSON,
		ContentType:          runtime.ContentTypeJSON,
		NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(jsonInfo),
	}
}
Beispiel #10
0
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
// Because api.List is part of the Kube API, resource.Builder has to perform a conversion on
// api.Scheme, which may not have access to all objects, and not all objects are at the same
// internal versioning scheme. This test verifies that two isolated schemes (Test, and api.Scheme)
// can be conjoined into a single output object.
//
// The expected behavior of the `kubectl get` command is:
// 1. objects using unrecognized schemes will always be returned using that scheme/version, "unlikelyversion" in this test;
// 2. if the specified output-version is a recognized, valid Scheme, then the list should use that scheme, and otherwise it will default to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test;
// 3a. if the specified output-version is a recognized, valid Scheme, in which the requested object (replicationcontroller) can be represented, then the object should be returned using that version;
// 3b. otherwise if the specified output-version is unrecognized, but the requested object (replicationcontroller) is recognized by the client's codec, then it will be converted to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test.
func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
	testCases := map[string]struct {
		outputVersion   string
		listVersion     string
		testtypeVersion string
		rcVersion       string
	}{
		"handles specific version": {
			outputVersion:   registered.GroupOrDie(api.GroupName).GroupVersion.String(),
			listVersion:     registered.GroupOrDie(api.GroupName).GroupVersion.String(),
			testtypeVersion: unlikelyGV.String(),
			rcVersion:       registered.GroupOrDie(api.GroupName).GroupVersion.String(),
		},
		"handles second specific version": {
			outputVersion:   "unlikely.group/unlikelyversion",
			listVersion:     registered.GroupOrDie(api.GroupName).GroupVersion.String(),
			testtypeVersion: unlikelyGV.String(),
			rcVersion:       registered.GroupOrDie(api.GroupName).GroupVersion.String(), // see expected behavior 3b
		},
		"handles common version": {
			outputVersion:   registered.GroupOrDie(api.GroupName).GroupVersion.String(),
			listVersion:     registered.GroupOrDie(api.GroupName).GroupVersion.String(),
			testtypeVersion: unlikelyGV.String(),
			rcVersion:       registered.GroupOrDie(api.GroupName).GroupVersion.String(),
		},
	}
	for k, test := range testCases {
		apiCodec := testapi.Default.Codec()
		apiNegotiatedSerializer := testapi.Default.NegotiatedSerializer()
		regularClient := &fake.RESTClient{
			NegotiatedSerializer: apiNegotiatedSerializer,
			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(apiCodec, &api.ReplicationController{ObjectMeta: api.ObjectMeta{Name: "foo"}})}, nil
			}),
		}

		f, tf, codec := NewMixedFactory(regularClient)
		negotiatedSerializer := serializer.NegotiatedSerializerWrapper(
			runtime.SerializerInfo{Serializer: codec},
			runtime.StreamSerializerInfo{})
		tf.Printer = &testPrinter{}
		tf.Client = &fake.RESTClient{
			NegotiatedSerializer: negotiatedSerializer,
			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
				return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &internalType{Name: "foo"})}, nil
			}),
		}
		tf.Namespace = "test"
		tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &registered.GroupOrDie(api.GroupName).GroupVersion}}
		buf := bytes.NewBuffer([]byte{})
		errBuf := bytes.NewBuffer([]byte{})
		cmd := NewCmdGet(f, buf, errBuf)
		cmd.SetOutput(buf)
		cmd.Flags().Set("output", "json")

		cmd.Flags().Set("output-version", test.outputVersion)
		err := RunGet(f, buf, errBuf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{})
		if err != nil {
			t.Errorf("%s: unexpected error: %v", k, err)
			continue
		}
		out := make(map[string]interface{})
		if err := encjson.Unmarshal(buf.Bytes(), &out); err != nil {
			t.Errorf("%s: unexpected error: %v\n%s", k, err, buf.String())
			continue
		}
		if out["apiVersion"] != test.listVersion {
			t.Errorf("%s: unexpected list: %#v", k, out)
		}
		arr := out["items"].([]interface{})
		if arr[0].(map[string]interface{})["apiVersion"] != test.testtypeVersion {
			t.Errorf("%s: unexpected list: %#v", k, out)
		}
		if arr[1].(map[string]interface{})["apiVersion"] != test.rcVersion {
			t.Errorf("%s: unexpected list: %#v", k, out)
		}
	}
}