// 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 }
// 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 }
// 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 }
// 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 }
// 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), } }
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 }
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 }
// 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), } }
// 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: ®istered.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) } } }