// WriteObjectToFile writes the JSON representation of runtime.Object into a temporary // file. func WriteObjectToFile(obj runtime.Object, filename string) error { content, err := runtime.Encode(kapi.Codecs.LegacyCodec(registered.EnabledVersions()...), obj) if err != nil { return err } return ioutil.WriteFile(filename, []byte(content), 0644) }
func (o *AppJSONOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { version, _ := cmd.Flags().GetString("output-version") for _, v := range strings.Split(version, ",") { gv, err := unversioned.ParseGroupVersion(v) if err != nil { return fmt.Errorf("provided output-version %q is not valid: %v", v, err) } o.OutputVersions = append(o.OutputVersions, gv) } o.OutputVersions = append(o.OutputVersions, registered.EnabledVersions()...) o.Action.Bulk.Mapper = clientcmd.ResourceMapper(f) o.Action.Bulk.Op = configcmd.Create mapper, _ := f.Object(false) o.PrintObject = cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, o.Action.Out) o.Generator, _ = cmd.Flags().GetString("generator") ns, _, err := f.DefaultNamespace() if err != nil { return err } o.Namespace = ns o.Client, _, err = f.Clients() return err }
func (c *MasterConfig) defaultAPIGroupVersion() *apiserver.APIGroupVersion { var restMapper meta.MultiRESTMapper seenGroups := sets.String{} for _, gv := range registered.EnabledVersions() { if seenGroups.Has(gv.Group) { continue } seenGroups.Insert(gv.Group) groupMeta, err := registered.Group(gv.Group) if err != nil { continue } restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper)) } statusMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{kubeapiv1.SchemeGroupVersion}, registered.GroupOrDie(kapi.GroupName).InterfacesFor) statusMapper.Add(kubeapiv1.SchemeGroupVersion.WithKind("Status"), meta.RESTScopeRoot) restMapper = meta.MultiRESTMapper(append(restMapper, statusMapper)) return &apiserver.APIGroupVersion{ Root: OpenShiftAPIPrefix, Mapper: restMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: registered.GroupOrDie("").SelfLinker, Admit: c.AdmissionControl, Context: c.getRequestContextMapper(), SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{}, } }
func internalGroupVersions() []unversioned.GroupVersion { groupVersions := registered.EnabledVersions() groups := map[string]struct{}{} for _, gv := range groupVersions { groups[gv.Group] = struct{}{} } result := []unversioned.GroupVersion{} for group := range groups { result = append(result, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal}) } return result }
func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, recreate bool) error { encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...) original, err := runtime.Encode(encoder, currentObj) if err != nil { return err } modified, err := runtime.Encode(encoder, target.Object) if err != nil { return err } if api.Semantic.DeepEqual(original, modified) { return ErrAlreadyExists{target.Name} } patch, err := strategicpatch.CreateTwoWayMergePatch(original, modified, currentObj) if err != nil { return err } // send patch to server helper := resource.NewHelper(target.Client, target.Mapping) _, err = helper.Patch(target.Namespace, target.Name, api.StrategicMergePatchType, patch) if err != nil { return err } if recreate { kind := target.Mapping.GroupVersionKind.Kind client, _ := c.ClientSet() switch kind { case "ReplicationController": rc := currentObj.(*v1.ReplicationController) err = recreatePods(client, target.Namespace, rc.Spec.Selector) case "DaemonSet": daemonSet := currentObj.(*v1beta1.DaemonSet) err = recreatePods(client, target.Namespace, daemonSet.Spec.Selector.MatchLabels) case "StatefulSet": petSet := currentObj.(*apps.StatefulSet) err = recreatePods(client, target.Namespace, petSet.Spec.Selector.MatchLabels) case "ReplicaSet": replicaSet := currentObj.(*v1beta1.ReplicaSet) err = recreatePods(client, target.Namespace, replicaSet.Spec.Selector.MatchLabels) } } return err }
func TestKnownAPIGroups(t *testing.T) { unexposedGroups := sets.NewString("authorization.k8s.io", "componentconfig", "metrics", "policy", "federation", "authentication.k8s.io", "rbac.authorization.k8s.io") enabledGroups := sets.NewString() for _, enabledVersion := range registered.EnabledVersions() { enabledGroups.Insert(enabledVersion.Group) } if missingKnownGroups := KnownKubeAPIGroups.Difference(enabledGroups); len(missingKnownGroups) > 0 { t.Errorf("KnownKubeAPIGroups are missing from registered.EnabledVersions: %v", missingKnownGroups.List()) } if unknownEnabledGroups := enabledGroups.Difference(KnownKubeAPIGroups).Difference(unexposedGroups); len(unknownEnabledGroups) > 0 { t.Errorf("KnownKubeAPIGroups is missing groups from registered.EnabledVersions: %v", unknownEnabledGroups.List()) } }
func getCurrentObject(targetName string, infos []*resource.Info) (runtime.Object, error) { var curr *resource.Info for _, currInfo := range infos { if currInfo.Name == targetName { curr = currInfo } } if curr == nil { return nil, fmt.Errorf("No resource with the name %s found.", targetName) } encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...) defaultVersion := unversioned.GroupVersion{} return resource.AsVersionedObject([]*resource.Info{curr}, false, defaultVersion, encoder) }
// DefaultMultiRESTMapper returns the multi REST mapper with all OpenShift and // Kubernetes objects already registered. func DefaultMultiRESTMapper() meta.MultiRESTMapper { var restMapper meta.MultiRESTMapper seenGroups := sets.String{} for _, gv := range registered.EnabledVersions() { if seenGroups.Has(gv.Group) { continue } seenGroups.Insert(gv.Group) groupMeta, err := registered.Group(gv.Group) if err != nil { continue } restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper)) } return restMapper }
func main() { flag.Parse() if *kubeconfig == "" { log.Fatalf("Need to specify --kubeconfig") } cfg := read(*kubeconfig) secret := &api.Secret{ ObjectMeta: api.ObjectMeta{ Name: *name, Namespace: *ns, }, Data: map[string][]byte{ "config": cfg, }, } fmt.Printf(runtime.EncodeOrDie(api.Codecs.LegacyCodec(registered.EnabledVersions()...), secret)) }
func main() { flag.Parse() if *crt == "" || *key == "" { log.Fatalf("Need to specify -crt -key and -template") } tlsCrt := read(*crt) tlsKey := read(*key) secret := &api.Secret{ ObjectMeta: api.ObjectMeta{ Name: *name, }, Data: map[string][]byte{ api.TLSCertKey: tlsCrt, api.TLSPrivateKeyKey: tlsKey, }, } fmt.Printf(runtime.EncodeOrDie(api.Codecs.LegacyCodec(registered.EnabledVersions()...), secret)) }
func main() { flag.Parse() if *crt == "" || *key == "" { log.Fatalf("Need to specify -crt -key and -template") } nginxCrt := read(*crt) nginxKey := read(*key) secret := &api.Secret{ ObjectMeta: api.ObjectMeta{ Name: "nginxsecret", }, Data: map[string][]byte{ "nginx.crt": nginxCrt, "nginx.key": nginxKey, }, } fmt.Printf(runtime.EncodeOrDie(api.Codecs.LegacyCodec(registered.EnabledVersions()...), secret)) }
func getFakeInfo(podInfo *api.Pod) ([]*resource.Info, *VolumeOptions) { f := clientcmd.NewFactory(nil) fakeMapping := getFakeMapping() info := &resource.Info{ Client: fake.NewSimpleClientset().Core().RESTClient(), Mapping: fakeMapping, Namespace: "default", Name: "fakepod", Object: podInfo, } infos := []*resource.Info{info} vOptions := &VolumeOptions{} vOptions.Name = "fake-mount" vOptions.Encoder = api.Codecs.LegacyCodec(registered.EnabledVersions()...) vOptions.Containers = "*" vOptions.UpdatePodSpecForObject = f.UpdatePodSpecForObject return infos, vOptions }
func updateResource(target *resource.Info, currentObj runtime.Object) error { encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...) originalSerialization, err := runtime.Encode(encoder, currentObj) if err != nil { return err } editedSerialization, err := runtime.Encode(encoder, target.Object) if err != nil { return err } originalJS, err := yaml.ToJSON(originalSerialization) if err != nil { return err } editedJS, err := yaml.ToJSON(editedSerialization) if err != nil { return err } if reflect.DeepEqual(originalJS, editedJS) { return ErrAlreadyExists{target.Name} } patch, err := strategicpatch.CreateStrategicMergePatch(originalJS, editedJS, currentObj) if err != nil { return err } // send patch to server helper := resource.NewHelper(target.Client, target.Mapping) if _, err = helper.Patch(target.Namespace, target.Name, api.StrategicMergePatchType, patch); err != nil { return err } return nil }
func getFakeInfo(podInfo *api.Pod) ([]*resource.Info, *VolumeOptions) { ns := testapi.Default.NegotiatedSerializer() f := clientcmd.NewFactory(nil) client := &fake.RESTClient{ NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }), } fakeMapping := getFakeMapping() info := &resource.Info{ Client: client, Mapping: fakeMapping, Namespace: "default", Name: "fakepod", Object: podInfo, } infos := []*resource.Info{info} vOptions := &VolumeOptions{} vOptions.Name = "fake-mount" vOptions.Encoder = api.Codecs.LegacyCodec(registered.EnabledVersions()...) vOptions.Containers = "*" vOptions.UpdatePodSpecForObject = f.UpdatePodSpecForObject return infos, vOptions }
func (c *MasterConfig) kubernetesAPIMessages(kc *kubernetes.MasterConfig) []string { var messages []string // v1 has to be printed separately since it's served from different endpoint than groups if configapi.HasKubernetesAPIVersion(*c.Options.KubernetesMasterConfig, kubeapiv1.SchemeGroupVersion) { messages = append(messages, fmt.Sprintf("Started Kubernetes API at %%s%s", genericapiserver.DefaultLegacyAPIPrefix)) } versions := registered.EnabledVersions() sort.Sort(sortedGroupVersions(versions)) for _, ver := range versions { if ver.String() == "v1" { // skip legacy v1 as we handle that above continue } if configapi.HasKubernetesAPIVersion(*c.Options.KubernetesMasterConfig, ver) { messages = append(messages, fmt.Sprintf("Started Kubernetes API %s at %%s%s", ver.String(), genericapiserver.APIGroupPrefix)) } } messages = append(messages, fmt.Sprintf("Started Swagger Schema API at %%s%s", kc.Master.GenericConfig.SwaggerConfig.ApiPath)) messages = append(messages, fmt.Sprintf("Started OpenAPI Schema at %%s%s", openAPIServePath)) return messages }
// NewFactory creates a factory with the default Kubernetes resources defined // if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // if optionalClientConfig is not nil, then this factory will make use of it. func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { mapper := kubectl.ShortcutExpander{RESTMapper: registered.RESTMapper()} flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags clientConfig := optionalClientConfig if optionalClientConfig == nil { clientConfig = DefaultClientConfig(flags) } clients := NewClientCache(clientConfig) return &Factory{ clients: clients, flags: flags, // If discoverDynamicAPIs is true, make API calls to the discovery service to find APIs that // have been dynamically added to the apiserver Object: func(discoverDynamicAPIs bool) (meta.RESTMapper, runtime.ObjectTyper) { cfg, err := clientConfig.ClientConfig() CheckErr(err) cmdApiVersion := unversioned.GroupVersion{} if cfg.GroupVersion != nil { cmdApiVersion = *cfg.GroupVersion } if discoverDynamicAPIs { client, err := clients.ClientForVersion(&unversioned.GroupVersion{Version: "v1"}) CheckErr(err) versions, gvks, err := GetThirdPartyGroupVersions(client.Discovery()) CheckErr(err) if len(versions) > 0 { priorityMapper, ok := mapper.RESTMapper.(meta.PriorityRESTMapper) if !ok { CheckErr(fmt.Errorf("expected PriorityMapper, saw: %v", mapper.RESTMapper)) return nil, nil } multiMapper, ok := priorityMapper.Delegate.(meta.MultiRESTMapper) if !ok { CheckErr(fmt.Errorf("unexpected type: %v", mapper.RESTMapper)) return nil, nil } groupsMap := map[string][]unversioned.GroupVersion{} for _, version := range versions { groupsMap[version.Group] = append(groupsMap[version.Group], version) } for group, versionList := range groupsMap { preferredExternalVersion := versionList[0] thirdPartyMapper, err := kubectl.NewThirdPartyResourceMapper(versionList, getGroupVersionKinds(gvks, group)) CheckErr(err) accessor := meta.NewAccessor() groupMeta := apimachinery.GroupMeta{ GroupVersion: preferredExternalVersion, GroupVersions: versionList, RESTMapper: thirdPartyMapper, SelfLinker: runtime.SelfLinker(accessor), InterfacesFor: makeInterfacesFor(versionList), } CheckErr(registered.RegisterGroup(groupMeta)) registered.AddThirdPartyAPIGroupVersions(versionList...) multiMapper = append(meta.MultiRESTMapper{thirdPartyMapper}, multiMapper...) } priorityMapper.Delegate = multiMapper // Re-assign to the RESTMapper here because priorityMapper is actually a copy, so if we // don't re-assign, the above assignement won't actually update mapper.RESTMapper mapper.RESTMapper = priorityMapper } } outputRESTMapper := kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}} priorityRESTMapper := meta.PriorityRESTMapper{ Delegate: outputRESTMapper, ResourcePriority: []unversioned.GroupVersionResource{ {Group: api.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, {Group: extensions.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, {Group: metrics.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, }, KindPriority: []unversioned.GroupVersionKind{ {Group: api.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, {Group: extensions.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, {Group: metrics.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, }, } return priorityRESTMapper, api.Scheme }, Client: func() (*client.Client, error) { return clients.ClientForVersion(nil) }, ClientConfig: func() (*restclient.Config, error) { return clients.ClientConfigForVersion(nil) }, ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { gvk := mapping.GroupVersionKind mappingVersion := mapping.GroupVersionKind.GroupVersion() c, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } switch gvk.Group { case api.GroupName: return c.RESTClient, nil case autoscaling.GroupName: return c.AutoscalingClient.RESTClient, nil case batch.GroupName: return c.BatchClient.RESTClient, nil case apps.GroupName: return c.AppsClient.RESTClient, nil case extensions.GroupName: return c.ExtensionsClient.RESTClient, nil case api.SchemeGroupVersion.Group: return c.RESTClient, nil case extensions.SchemeGroupVersion.Group: return c.ExtensionsClient.RESTClient, nil default: if !registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { return nil, fmt.Errorf("unknown api group/version: %s", gvk.String()) } cfg, err := clientConfig.ClientConfig() if err != nil { return nil, err } gv := gvk.GroupVersion() cfg.GroupVersion = &gv cfg.APIPath = "/apis" cfg.Codec = thirdpartyresourcedata.NewCodec(c.ExtensionsClient.RESTClient.Codec(), gvk.Kind) return restclient.RESTClientFor(cfg) } }, Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), client); ok { return describer, nil } return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) }, Decoder: func(toInternal bool) runtime.Decoder { if toInternal { return api.Codecs.UniversalDecoder() } return api.Codecs.UniversalDeserializer() }, JSONEncoder: func() runtime.Encoder { return api.Codecs.LegacyCodec(registered.EnabledVersions()...) }, Printer: func(mapping *meta.RESTMapping, noHeaders, withNamespace bool, wide bool, showAll bool, showLabels bool, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error) { return kubectl.NewHumanReadablePrinter(noHeaders, withNamespace, wide, showAll, showLabels, absoluteTimestamps, columnLabels), nil }, MapBasedSelectorForObject: func(object runtime.Object) (string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil case *api.Pod: if len(t.Labels) == 0 { return "", fmt.Errorf("the pod has no labels and cannot be exposed") } return kubectl.MakeLabels(t.Labels), nil case *api.Service: if t.Spec.Selector == nil { return "", fmt.Errorf("the service has no pod selector set") } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format", t.Spec.Selector.MatchExpressions) } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil case *extensions.ReplicaSet: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format", t.Spec.Selector.MatchExpressions) } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return "", err } return "", fmt.Errorf("cannot extract pod selector from %v", gvk) } }, PortsForObject: func(object runtime.Object) ([]string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return getPorts(t.Spec.Template.Spec), nil case *api.Pod: return getPorts(t.Spec), nil case *api.Service: return getServicePorts(t.Spec), nil case *extensions.Deployment: return getPorts(t.Spec.Template.Spec), nil case *extensions.ReplicaSet: return getPorts(t.Spec.Template.Spec), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot extract ports from %v", gvk) } }, LabelsForObject: func(object runtime.Object) (map[string]string, error) { return meta.NewAccessor().Labels(object) }, LogsForObject: func(object, options runtime.Object) (*restclient.Request, error) { c, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.Pod: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil case *api.ReplicationController: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector := labels.SelectorFromSet(t.Spec.Selector) sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(c, t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil case *extensions.ReplicaSet: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(c, t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot get the logs from %v", gvk) } }, PauseObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if t.Spec.Paused { return true, nil } t.Spec.Paused = true _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot pause %v", gvk) } }, ResumeObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if !t.Spec.Paused { return true, nil } t.Spec.Paused = false _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot resume %v", gvk) } }, Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), client) }, Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) }, HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) clientset := clientset.FromUnversionedClient(client) if err != nil { return nil, err } return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) }, Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), client) }, Validator: func(validate bool, cacheDir string) (validation.Schema, error) { if validate { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } dir := cacheDir if len(dir) > 0 { version, err := client.ServerVersion() if err != nil { return nil, err } dir = path.Join(cacheDir, version.String()) } return &clientSwaggerSchema{ c: client, cacheDir: dir, mapper: api.RESTMapper, }, nil } return validation.NullSchema{}, nil }, SwaggerSchema: func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() client, err := clients.ClientForVersion(&version) if err != nil { return nil, err } return client.Discovery().SwaggerSchema(version) }, DefaultNamespace: func() (string, bool, error) { return clientConfig.Namespace() }, Generators: func(cmdName string) map[string]kubectl.Generator { return DefaultGenerators(cmdName) }, CanBeExposed: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot expose a %s", kind) } return nil }, CanBeAutoscaled: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot autoscale a %v", kind) } return nil }, AttachablePodForObject: func(object runtime.Object) (*api.Pod, error) { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.ReplicationController: selector := labels.SelectorFromSet(t.Spec.Selector) sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *extensions.Deployment: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *batch.Job: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *api.Pod: return t, nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk) } }, EditorEnvs: func() []string { return []string{"KUBE_EDITOR", "EDITOR"} }, PrintObjectSpecificMessage: func(obj runtime.Object, out io.Writer) { switch obj := obj.(type) { case *api.Service: if obj.Spec.Type == api.ServiceTypeNodePort { msg := fmt.Sprintf( `You have exposed your service on an external port on all nodes in your cluster. If you want to expose this service to the external internet, you may need to set up firewall rules for the service port(s) (%s) to serve traffic. See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more details. `, makePortsString(obj.Spec.Ports, true)) out.Write([]byte(msg)) } } }, } }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if gvk.Group == autoscaling.GroupName { if c.c.AutoscalingClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == policy.GroupName { if c.c.PolicyClient == nil { return errors.New("unable to validate: no policy client") } return getSchemaAndValidate(c.c.PolicyClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == apps.GroupName { if c.c.AppsClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AppsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == batch.GroupName { if c.c.BatchClient == nil { return errors.New("unable to validate: no batch client") } return getSchemaAndValidate(c.c.BatchClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == rbac.GroupName { if c.c.RbacClient == nil { return errors.New("unable to validate: no rbac client") } return getSchemaAndValidate(c.c.RbacClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // Don't attempt to validate third party objects return nil } if gvk.Group == extensions.GroupName { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == federation.GroupName { if c.fedc == nil { return errors.New("unable to validate: no federation client") } return getSchemaAndValidate(c.fedc, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir, c) }
daemonsetLabelPrefix = "daemonset-" daemonsetNameLabel = daemonsetLabelPrefix + "name" daemonsetColorLabel = daemonsetLabelPrefix + "color" ) // This test must be run in serial because it assumes the Daemon Set pods will // always get scheduled. If we run other tests in parallel, this may not // happen. In the future, running in parallel may work if we have an eviction // model which lets the DS controller kick out other pods to make room. // See http://issues.k8s.io/21767 for more details var _ = Describe("Daemon set [Serial]", func() { var f *Framework AfterEach(func() { if daemonsets, err := f.Client.DaemonSets(f.Namespace.Name).List(api.ListOptions{}); err == nil { Logf("daemonset: %s", runtime.EncodeOrDie(api.Codecs.LegacyCodec(registered.EnabledVersions()...), daemonsets)) } else { Logf("unable to dump daemonsets: %v", err) } if pods, err := f.Client.Pods(f.Namespace.Name).List(api.ListOptions{}); err == nil { Logf("pods: %s", runtime.EncodeOrDie(api.Codecs.LegacyCodec(registered.EnabledVersions()...), pods)) } else { Logf("unable to dump pods: %v", err) } err := clearDaemonSetNodeLabels(f.Client) Expect(err).NotTo(HaveOccurred()) }) f = NewDefaultFramework("daemonsets") image := "gcr.io/google_containers/serve_hostname:1.1"
func TestAccessorImplementations(t *testing.T) { for _, gv := range registered.EnabledVersions() { internalGV := schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal} for _, gv := range []schema.GroupVersion{gv, internalGV} { for kind, knownType := range api.Scheme.KnownTypes(gv) { value := reflect.New(knownType) obj := value.Interface() if _, ok := obj.(runtime.Object); !ok { t.Errorf("%v (%v) does not implement runtime.Object", gv.WithKind(kind), knownType) } lm, isLM := obj.(meta.ListMetaAccessor) om, isOM := obj.(meta.ObjectMetaAccessor) switch { case isLM && isOM: t.Errorf("%v (%v) implements ListMetaAccessor and ObjectMetaAccessor", gv.WithKind(kind), knownType) continue case isLM: m := lm.GetListMeta() if m == nil { t.Errorf("%v (%v) returns nil ListMeta", gv.WithKind(kind), knownType) continue } m.SetResourceVersion("102030") if m.GetResourceVersion() != "102030" { t.Errorf("%v (%v) did not preserve resource version", gv.WithKind(kind), knownType) continue } m.SetSelfLink("102030") if m.GetSelfLink() != "102030" { t.Errorf("%v (%v) did not preserve self link", gv.WithKind(kind), knownType) continue } case isOM: m := om.GetObjectMeta() if m == nil { t.Errorf("%v (%v) returns nil ObjectMeta", gv.WithKind(kind), knownType) continue } m.SetResourceVersion("102030") if m.GetResourceVersion() != "102030" { t.Errorf("%v (%v) did not preserve resource version", gv.WithKind(kind), knownType) continue } m.SetSelfLink("102030") if m.GetSelfLink() != "102030" { t.Errorf("%v (%v) did not preserve self link", gv.WithKind(kind), knownType) continue } labels := map[string]string{"a": "b"} m.SetLabels(labels) if !reflect.DeepEqual(m.GetLabels(), labels) { t.Errorf("%v (%v) did not preserve labels", gv.WithKind(kind), knownType) continue } default: if _, ok := obj.(unversioned.ListMetaAccessor); ok { continue } if _, ok := value.Elem().Type().FieldByName("ObjectMeta"); ok { t.Errorf("%v (%v) has ObjectMeta but does not implement ObjectMetaAccessor", gv.WithKind(kind), knownType) continue } if _, ok := value.Elem().Type().FieldByName("ListMeta"); ok { t.Errorf("%v (%v) has ListMeta but does not implement ListMetaAccessor", gv.WithKind(kind), knownType) continue } t.Logf("%v (%v) does not implement ListMetaAccessor or ObjectMetaAccessor", gv.WithKind(kind), knownType) } } } } }
// NewFactory creates a factory with the default Kubernetes resources defined // if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // if optionalClientConfig is not nil, then this factory will make use of it. func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { mapper := kubectl.ShortcutExpander{RESTMapper: registered.RESTMapper()} flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags clientConfig := optionalClientConfig if optionalClientConfig == nil { clientConfig = DefaultClientConfig(flags) } clients := NewClientCache(clientConfig) return &Factory{ clients: clients, flags: flags, // If discoverDynamicAPIs is true, make API calls to the discovery service to find APIs that // have been dynamically added to the apiserver Object: func(discoverDynamicAPIs bool) (meta.RESTMapper, runtime.ObjectTyper) { cfg, err := clientConfig.ClientConfig() checkErrWithPrefix("failed to get client config: ", err) cmdApiVersion := unversioned.GroupVersion{} if cfg.GroupVersion != nil { cmdApiVersion = *cfg.GroupVersion } if discoverDynamicAPIs { client, err := clients.ClientForVersion(&unversioned.GroupVersion{Version: "v1"}) checkErrWithPrefix("failed to find client for version v1: ", err) var versions []unversioned.GroupVersion var gvks []unversioned.GroupVersionKind retries := 3 for i := 0; i < retries; i++ { versions, gvks, err = GetThirdPartyGroupVersions(client.Discovery()) // Retry if we got a NotFound error, because user may delete // a thirdparty group when the GetThirdPartyGroupVersions is // running. if err == nil || !apierrors.IsNotFound(err) { break } } checkErrWithPrefix("failed to get third-party group versions: ", err) if len(versions) > 0 { priorityMapper, ok := mapper.RESTMapper.(meta.PriorityRESTMapper) if !ok { CheckErr(fmt.Errorf("expected PriorityMapper, saw: %v", mapper.RESTMapper)) return nil, nil } multiMapper, ok := priorityMapper.Delegate.(meta.MultiRESTMapper) if !ok { CheckErr(fmt.Errorf("unexpected type: %v", mapper.RESTMapper)) return nil, nil } groupsMap := map[string][]unversioned.GroupVersion{} for _, version := range versions { groupsMap[version.Group] = append(groupsMap[version.Group], version) } for group, versionList := range groupsMap { preferredExternalVersion := versionList[0] thirdPartyMapper, err := kubectl.NewThirdPartyResourceMapper(versionList, getGroupVersionKinds(gvks, group)) checkErrWithPrefix("failed to create third party resource mapper: ", err) accessor := meta.NewAccessor() groupMeta := apimachinery.GroupMeta{ GroupVersion: preferredExternalVersion, GroupVersions: versionList, RESTMapper: thirdPartyMapper, SelfLinker: runtime.SelfLinker(accessor), InterfacesFor: makeInterfacesFor(versionList), } checkErrWithPrefix("failed to register group: ", registered.RegisterGroup(groupMeta)) registered.AddThirdPartyAPIGroupVersions(versionList...) multiMapper = append(meta.MultiRESTMapper{thirdPartyMapper}, multiMapper...) } priorityMapper.Delegate = multiMapper // Reassign to the RESTMapper here because priorityMapper is actually a copy, so if we // don't reassign, the above assignement won't actually update mapper.RESTMapper mapper.RESTMapper = priorityMapper } } outputRESTMapper := kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}} priorityRESTMapper := meta.PriorityRESTMapper{ Delegate: outputRESTMapper, } // TODO: this should come from registered versions groups := []string{api.GroupName, autoscaling.GroupName, extensions.GroupName, federation.GroupName, batch.GroupName} // set a preferred version for _, group := range groups { gvs := registered.EnabledVersionsForGroup(group) if len(gvs) == 0 { continue } priorityRESTMapper.ResourcePriority = append(priorityRESTMapper.ResourcePriority, unversioned.GroupVersionResource{Group: group, Version: gvs[0].Version, Resource: meta.AnyResource}) priorityRESTMapper.KindPriority = append(priorityRESTMapper.KindPriority, unversioned.GroupVersionKind{Group: group, Version: gvs[0].Version, Kind: meta.AnyKind}) } for _, group := range groups { priorityRESTMapper.ResourcePriority = append(priorityRESTMapper.ResourcePriority, unversioned.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource}) priorityRESTMapper.KindPriority = append(priorityRESTMapper.KindPriority, unversioned.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind}) } return priorityRESTMapper, api.Scheme }, Client: func() (*client.Client, error) { return clients.ClientForVersion(nil) }, ClientConfig: func() (*restclient.Config, error) { return clients.ClientConfigForVersion(nil) }, ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { cfg, err := clientConfig.ClientConfig() if err != nil { return nil, err } if err := client.SetKubernetesDefaults(cfg); err != nil { return nil, err } gvk := mapping.GroupVersionKind switch gvk.Group { case federation.GroupName: mappingVersion := mapping.GroupVersionKind.GroupVersion() return clients.FederationClientForVersion(&mappingVersion) case api.GroupName: cfg.APIPath = "/api" default: cfg.APIPath = "/apis" } gv := gvk.GroupVersion() cfg.GroupVersion = &gv if registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { cfg.NegotiatedSerializer = thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, gvk.Kind, gv, gv) } return restclient.RESTClientFor(cfg) }, Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() if mapping.GroupVersionKind.Group == federation.GroupName { fedClientSet, err := clients.FederationClientSetForVersion(&mappingVersion) if err != nil { return nil, err } if mapping.GroupVersionKind.Kind == "Cluster" { return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil } } client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), client); ok { return describer, nil } return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) }, Decoder: func(toInternal bool) runtime.Decoder { var decoder runtime.Decoder if toInternal { decoder = api.Codecs.UniversalDecoder() } else { decoder = api.Codecs.UniversalDeserializer() } return thirdpartyresourcedata.NewDecoder(decoder, "") }, JSONEncoder: func() runtime.Encoder { return api.Codecs.LegacyCodec(registered.EnabledVersions()...) }, Printer: func(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) { return kubectl.NewHumanReadablePrinter(options), nil }, MapBasedSelectorForObject: func(object runtime.Object) (string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil case *api.Pod: if len(t.Labels) == 0 { return "", fmt.Errorf("the pod has no labels and cannot be exposed") } return kubectl.MakeLabels(t.Labels), nil case *api.Service: if t.Spec.Selector == nil { return "", fmt.Errorf("the service has no pod selector set") } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format", t.Spec.Selector.MatchExpressions) } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil case *extensions.ReplicaSet: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format", t.Spec.Selector.MatchExpressions) } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return "", err } return "", fmt.Errorf("cannot extract pod selector from %v", gvks[0]) } }, PortsForObject: func(object runtime.Object) ([]string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return getPorts(t.Spec.Template.Spec), nil case *api.Pod: return getPorts(t.Spec), nil case *api.Service: return getServicePorts(t.Spec), nil case *extensions.Deployment: return getPorts(t.Spec.Template.Spec), nil case *extensions.ReplicaSet: return getPorts(t.Spec.Template.Spec), nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot extract ports from %v", gvks[0]) } }, ProtocolsForObject: func(object runtime.Object) (map[string]string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return getProtocols(t.Spec.Template.Spec), nil case *api.Pod: return getProtocols(t.Spec), nil case *api.Service: return getServiceProtocols(t.Spec), nil case *extensions.Deployment: return getProtocols(t.Spec.Template.Spec), nil case *extensions.ReplicaSet: return getProtocols(t.Spec.Template.Spec), nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot extract protocols from %v", gvks[0]) } }, LabelsForObject: func(object runtime.Object) (map[string]string, error) { return meta.NewAccessor().Labels(object) }, LogsForObject: func(object, options runtime.Object) (*restclient.Request, error) { c, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.Pod: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil case *api.ReplicationController: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector := labels.SelectorFromSet(t.Spec.Selector) sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(c, t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil case *extensions.ReplicaSet: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return controller.ByLogging(pods) } pod, numPods, err := GetFirstPod(c, t.Namespace, selector, 20*time.Second, sortBy) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot get the logs from %v", gvks[0]) } }, PauseObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if t.Spec.Paused { return true, nil } t.Spec.Paused = true _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return false, err } return false, fmt.Errorf("cannot pause %v", gvks[0]) } }, ResumeObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if !t.Spec.Paused { return true, nil } t.Spec.Paused = false _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return false, err } return false, fmt.Errorf("cannot resume %v", gvks[0]) } }, Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), client) }, Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) }, HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) clientset := clientset.FromUnversionedClient(client) if err != nil { return nil, err } return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) }, Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), client) }, StatusViewer: func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.StatusViewerFor(mapping.GroupVersionKind.GroupKind(), client) }, Validator: func(validate bool, cacheDir string) (validation.Schema, error) { if validate { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } dir := cacheDir if len(dir) > 0 { version, err := client.ServerVersion() if err != nil { return nil, err } dir = path.Join(cacheDir, version.String()) } fedClient, err := clients.FederationClientForVersion(nil) if err != nil { return nil, err } return &clientSwaggerSchema{ c: client, fedc: fedClient, cacheDir: dir, mapper: api.RESTMapper, }, nil } return validation.NullSchema{}, nil }, SwaggerSchema: func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() client, err := clients.ClientForVersion(&version) if err != nil { return nil, err } return client.Discovery().SwaggerSchema(version) }, DefaultNamespace: func() (string, bool, error) { return clientConfig.Namespace() }, Generators: func(cmdName string) map[string]kubectl.Generator { return DefaultGenerators(cmdName) }, CanBeExposed: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot expose a %s", kind) } return nil }, CanBeAutoscaled: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot autoscale a %v", kind) } return nil }, AttachablePodForObject: func(object runtime.Object) (*api.Pod, error) { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.ReplicationController: selector := labels.SelectorFromSet(t.Spec.Selector) sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *extensions.Deployment: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *batch.Job: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } pod, _, err := GetFirstPod(client, t.Namespace, selector, 1*time.Minute, sortBy) return pod, err case *api.Pod: return t, nil default: gvks, _, err := api.Scheme.ObjectKinds(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot attach to %v: not implemented", gvks[0]) } }, // UpdatePodSpecForObject update the pod specification for the provided object UpdatePodSpecForObject: func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { // TODO: replace with a swagger schema based approach (identify pod template via schema introspection) switch t := obj.(type) { case *api.Pod: return true, fn(&t.Spec) case *api.ReplicationController: if t.Spec.Template == nil { t.Spec.Template = &api.PodTemplateSpec{} } return true, fn(&t.Spec.Template.Spec) case *extensions.Deployment: return true, fn(&t.Spec.Template.Spec) case *extensions.DaemonSet: return true, fn(&t.Spec.Template.Spec) case *extensions.ReplicaSet: return true, fn(&t.Spec.Template.Spec) case *apps.PetSet: return true, fn(&t.Spec.Template.Spec) case *batch.Job: return true, fn(&t.Spec.Template.Spec) default: return false, fmt.Errorf("the object is not a pod or does not have a pod template") } }, EditorEnvs: func() []string { return []string{"KUBE_EDITOR", "EDITOR"} }, PrintObjectSpecificMessage: func(obj runtime.Object, out io.Writer) { switch obj := obj.(type) { case *api.Service: if obj.Spec.Type == api.ServiceTypeNodePort { msg := fmt.Sprintf( `You have exposed your service on an external port on all nodes in your cluster. If you want to expose this service to the external internet, you may need to set up firewall rules for the service port(s) (%s) to serve traffic. See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more details. `, makePortsString(obj.Spec.Ports, true)) out.Write([]byte(msg)) } if _, ok := obj.Annotations[service.AnnotationLoadBalancerSourceRangesKey]; ok { msg := fmt.Sprintf( `You are using service annotation [service.beta.kubernetes.io/load-balancer-source-ranges]. It has been promoted to field [loadBalancerSourceRanges] in service spec. This annotation will be deprecated in the future. Please use the loadBalancerSourceRanges field instead. See http://releases.k8s.io/HEAD/docs/user-guide/services-firewalls.md for more details. `) out.Write([]byte(msg)) } } }, } }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if gvk.Group == autoscaling.GroupName { if c.c.AutoscalingClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } if gvk.Group == batch.GroupName { if c.c.BatchClient == nil { return errors.New("unable to validate: no batch client") } return getSchemaAndValidate(c.c.BatchClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } if gvk.Group == extensions.GroupName { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir) }
func (f *ring0Factory) JSONEncoder() runtime.Encoder { return api.Codecs.LegacyCodec(registered.EnabledVersions()...) }
// ClientConfigForVersion returns the correct config for a server func (c *ClientCache) ClientConfigForVersion(requiredVersion *schema.GroupVersion) (*restclient.Config, error) { // TODO: have a better config copy method config, discoveryClient, err := c.getDefaultConfig() if err != nil { return nil, err } if requiredVersion == nil && config.GroupVersion != nil { // if someone has set the values via flags, our config will have the groupVersion set // that means it is required. requiredVersion = config.GroupVersion } // required version may still be nil, since config.GroupVersion may have been nil. Do the check // before looking up from the cache if requiredVersion != nil { if config, ok := c.configs[*requiredVersion]; ok { return config, nil } } negotiatedVersion, err := discovery.NegotiateVersion(discoveryClient, requiredVersion, registered.EnabledVersions()) if err != nil { return nil, err } config.GroupVersion = negotiatedVersion // TODO this isn't what we want. Each clientset should be setting defaults as it sees fit. oldclient.SetKubernetesDefaults(&config) if requiredVersion != nil { c.configs[*requiredVersion] = &config } // `version` does not necessarily equal `config.Version`. However, we know that we call this method again with // `config.Version`, we should get the config we've just built. configCopy := config c.configs[*config.GroupVersion] = &configCopy return &config, nil }
// ClientConfigForVersion returns the correct config for a server func (c *ClientCache) ClientConfigForVersion(version *unversioned.GroupVersion) (*restclient.Config, error) { if c.defaultConfig == nil { config, err := c.loader.ClientConfig() if err != nil { return nil, err } c.defaultConfig = config if c.matchVersion { if err := client.MatchesServerVersion(c.defaultClient, config); err != nil { return nil, err } } } if version != nil { if config, ok := c.configs[*version]; ok { return config, nil } } // TODO: have a better config copy method config := *c.defaultConfig // TODO these fall out when we finish the refactor var preferredGV *unversioned.GroupVersion if version != nil { versionCopy := *version preferredGV = &versionCopy } client.SetKubernetesDefaults(&config) negotiatedVersion, err := client.NegotiateVersion(c.defaultClient, &config, preferredGV, registered.EnabledVersions()) if err != nil { return nil, err } config.GroupVersion = negotiatedVersion if version != nil { c.configs[*version] = &config } // `version` does not necessarily equal `config.Version`. However, we know that we call this method again with // `config.Version`, we should get the config we've just built. configCopy := config c.configs[*config.GroupVersion] = &configCopy return &config, nil }
// NewFactory creates a factory with the default Kubernetes resources defined // if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // if optionalClientConfig is not nil, then this factory will make use of it. func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { mapper := kubectl.ShortcutExpander{RESTMapper: api.RESTMapper} flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags.SetNormalizeFunc(util.WarnWordSepNormalizeFunc) // Warn for "_" flags clientConfig := optionalClientConfig if optionalClientConfig == nil { clientConfig = DefaultClientConfig(flags) } clients := NewClientCache(clientConfig) return &Factory{ clients: clients, flags: flags, cmd: recordCommand(os.Args), Object: func() (meta.RESTMapper, runtime.ObjectTyper) { cfg, err := clientConfig.ClientConfig() CheckErr(err) cmdApiVersion := unversioned.GroupVersion{} if cfg.GroupVersion != nil { cmdApiVersion = *cfg.GroupVersion } return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}, api.Scheme }, Client: func() (*client.Client, error) { return clients.ClientForVersion(nil) }, ClientConfig: func() (*client.Config, error) { return clients.ClientConfigForVersion(nil) }, ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } switch mapping.GroupVersionKind.Group { case api.GroupName: return client.RESTClient, nil case extensions.GroupName: return client.ExtensionsClient.RESTClient, nil } return nil, fmt.Errorf("unable to get RESTClient for resource '%s'", mapping.Resource) }, Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), client); ok { return describer, nil } return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) }, Decoder: func(toInternal bool) runtime.Decoder { if toInternal { return api.Codecs.UniversalDecoder() } return api.Codecs.UniversalDeserializer() }, JSONEncoder: func() runtime.Encoder { return api.Codecs.LegacyCodec(registered.EnabledVersions()...) }, Printer: func(mapping *meta.RESTMapping, noHeaders, withNamespace bool, wide bool, showAll bool, showLabels bool, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error) { return kubectl.NewHumanReadablePrinter(noHeaders, withNamespace, wide, showAll, showLabels, absoluteTimestamps, columnLabels), nil }, PodSelectorForObject: func(object runtime.Object) (string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil case *api.Pod: if len(t.Labels) == 0 { return "", fmt.Errorf("the pod has no labels and cannot be exposed") } return kubectl.MakeLabels(t.Labels), nil case *api.Service: if t.Spec.Selector == nil { return "", fmt.Errorf("the service has no pod selector set") } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: return kubectl.MakeLabels(t.Spec.Selector), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return "", err } return "", fmt.Errorf("cannot extract pod selector from %v", gvk) } }, PortsForObject: func(object runtime.Object) ([]string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return getPorts(t.Spec.Template.Spec), nil case *api.Pod: return getPorts(t.Spec), nil case *api.Service: return getServicePorts(t.Spec), nil case *extensions.Deployment: return getPorts(t.Spec.Template.Spec), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot extract ports from %v", gvk) } }, LabelsForObject: func(object runtime.Object) (map[string]string, error) { return meta.NewAccessor().Labels(object) }, LogsForObject: func(object, options runtime.Object) (*client.Request, error) { c, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.Pod: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot get the logs from %v", gvk) } }, PauseObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if t.Spec.Paused { return true, nil } t.Spec.Paused = true _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot pause %v", gvk) } }, ResumeObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if !t.Spec.Paused { return true, nil } t.Spec.Paused = false _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot resume %v", gvk) } }, Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), client) }, Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) }, HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) clientset := clientset.FromUnversionedClient(client) if err != nil { return nil, err } return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) }, Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), client) }, Validator: func(validate bool, cacheDir string) (validation.Schema, error) { if validate { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } dir := cacheDir if len(dir) > 0 { version, err := client.ServerVersion() if err != nil { return nil, err } dir = path.Join(cacheDir, version.String()) } return &clientSwaggerSchema{ c: client, cacheDir: dir, mapper: api.RESTMapper, }, nil } return validation.NullSchema{}, nil }, SwaggerSchema: func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() client, err := clients.ClientForVersion(&version) if err != nil { return nil, err } return client.Discovery().SwaggerSchema(version) }, DefaultNamespace: func() (string, bool, error) { return clientConfig.Namespace() }, Generators: func(cmdName string) map[string]kubectl.Generator { return DefaultGenerators(cmdName) }, CanBeExposed: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"): // nothing to do here default: return fmt.Errorf("cannot expose a %s", kind) } return nil }, CanBeAutoscaled: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), extensions.Kind("Deployment"): // nothing to do here default: return fmt.Errorf("cannot autoscale a %v", kind) } return nil }, AttachablePodForObject: func(object runtime.Object) (*api.Pod, error) { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.ReplicationController: return GetFirstPod(client, t.Namespace, t.Spec.Selector) case *extensions.Deployment: return GetFirstPod(client, t.Namespace, t.Spec.Selector) case *extensions.Job: return GetFirstPod(client, t.Namespace, t.Spec.Selector.MatchLabels) case *api.Pod: return t, nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk) } }, EditorEnvs: func() []string { return []string{"KUBE_EDITOR", "EDITOR"} }, } }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // Don't attempt to validate third party objects return nil } switch gvk.Group { case federation.GroupName: if c.fedc == nil { return errors.New("unable to validate: no federation client") } return getSchemaAndValidate(c.fedc, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) case api.GroupName: return getSchemaAndValidate(c.c, data, "api", gvk.GroupVersion().String(), c.cacheDir, c) default: return getSchemaAndValidate(c.c, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } }
// NewFactory creates a factory with the default Kubernetes resources defined // if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // if optionalClientConfig is not nil, then this factory will make use of it. func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { mapper := kubectl.ShortcutExpander{RESTMapper: registered.RESTMapper()} flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags clientConfig := optionalClientConfig if optionalClientConfig == nil { clientConfig = DefaultClientConfig(flags) } clients := NewClientCache(clientConfig) return &Factory{ clients: clients, flags: flags, Object: func() (meta.RESTMapper, runtime.ObjectTyper) { cfg, err := clientConfig.ClientConfig() CheckErr(err) cmdApiVersion := unversioned.GroupVersion{} if cfg.GroupVersion != nil { cmdApiVersion = *cfg.GroupVersion } outputRESTMapper := kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}} // eventually this should allow me choose a group priority based on the order of the discovery doc, for now hardcode a given order priorityRESTMapper := meta.PriorityRESTMapper{ Delegate: outputRESTMapper, ResourcePriority: []unversioned.GroupVersionResource{ {Group: api.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, {Group: extensions.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, {Group: metrics.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, }, KindPriority: []unversioned.GroupVersionKind{ {Group: api.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, {Group: extensions.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, {Group: metrics.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, }, } return priorityRESTMapper, api.Scheme }, Client: func() (*client.Client, error) { return clients.ClientForVersion(nil) }, ClientConfig: func() (*restclient.Config, error) { return clients.ClientConfigForVersion(nil) }, ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } switch mapping.GroupVersionKind.Group { case api.GroupName: return client.RESTClient, nil case autoscaling.GroupName: return client.AutoscalingClient.RESTClient, nil case batch.GroupName: return client.BatchClient.RESTClient, nil case extensions.GroupName: return client.ExtensionsClient.RESTClient, nil } return nil, fmt.Errorf("unable to get RESTClient for resource '%s'", mapping.Resource) }, Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), client); ok { return describer, nil } return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) }, Decoder: func(toInternal bool) runtime.Decoder { if toInternal { return api.Codecs.UniversalDecoder() } return api.Codecs.UniversalDeserializer() }, JSONEncoder: func() runtime.Encoder { return api.Codecs.LegacyCodec(registered.EnabledVersions()...) }, Printer: func(mapping *meta.RESTMapping, noHeaders, withNamespace bool, wide bool, showAll bool, showLabels bool, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error) { return kubectl.NewHumanReadablePrinter(noHeaders, withNamespace, wide, showAll, showLabels, absoluteTimestamps, columnLabels), nil }, PodSelectorForObject: func(object runtime.Object) (string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil case *api.Pod: if len(t.Labels) == 0 { return "", fmt.Errorf("the pod has no labels and cannot be exposed") } return kubectl.MakeLabels(t.Labels), nil case *api.Service: if t.Spec.Selector == nil { return "", fmt.Errorf("the service has no pod selector set") } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return "", fmt.Errorf("invalid label selector: %v", err) } return selector.String(), nil case *extensions.ReplicaSet: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return "", fmt.Errorf("failed to convert label selector to selector: %v", err) } return selector.String(), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return "", err } return "", fmt.Errorf("cannot extract pod selector from %v", gvk) } }, MapBasedSelectorForObject: func(object runtime.Object) (string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil case *api.Pod: if len(t.Labels) == 0 { return "", fmt.Errorf("the pod has no labels and cannot be exposed") } return kubectl.MakeLabels(t.Labels), nil case *api.Service: if t.Spec.Selector == nil { return "", fmt.Errorf("the service has no pod selector set") } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format") } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil case *extensions.ReplicaSet: // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals // operator, DoubleEquals operator and In operator with only one element in the set. if len(t.Spec.Selector.MatchExpressions) > 0 { return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format") } return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return "", err } return "", fmt.Errorf("cannot extract pod selector from %v", gvk) } }, PortsForObject: func(object runtime.Object) ([]string, error) { // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) switch t := object.(type) { case *api.ReplicationController: return getPorts(t.Spec.Template.Spec), nil case *api.Pod: return getPorts(t.Spec), nil case *api.Service: return getServicePorts(t.Spec), nil case *extensions.Deployment: return getPorts(t.Spec.Template.Spec), nil case *extensions.ReplicaSet: return getPorts(t.Spec.Template.Spec), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot extract ports from %v", gvk) } }, LabelsForObject: func(object runtime.Object) (map[string]string, error) { return meta.NewAccessor().Labels(object) }, LogsForObject: func(object, options runtime.Object) (*restclient.Request, error) { c, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.Pod: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil case *api.ReplicationController: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector := labels.SelectorFromSet(t.Spec.Selector) pod, numPods, err := GetFirstPod(c, t.Namespace, selector) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil case *extensions.ReplicaSet: opts, ok := options.(*api.PodLogOptions) if !ok { return nil, errors.New("provided options object is not a PodLogOptions") } selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } pod, numPods, err := GetFirstPod(c, t.Namespace, selector) if err != nil { return nil, err } if numPods > 1 { fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name) } return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot get the logs from %v", gvk) } }, PauseObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if t.Spec.Paused { return true, nil } t.Spec.Paused = true _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot pause %v", gvk) } }, ResumeObject: func(object runtime.Object) (bool, error) { c, err := clients.ClientForVersion(nil) if err != nil { return false, err } switch t := object.(type) { case *extensions.Deployment: if !t.Spec.Paused { return true, nil } t.Spec.Paused = false _, err := c.Extensions().Deployments(t.Namespace).Update(t) return false, err default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return false, err } return false, fmt.Errorf("cannot resume %v", gvk) } }, Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), client) }, Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) }, HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) clientset := clientset.FromUnversionedClient(client) if err != nil { return nil, err } return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) }, Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), client) }, Validator: func(validate bool, cacheDir string) (validation.Schema, error) { if validate { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } dir := cacheDir if len(dir) > 0 { version, err := client.ServerVersion() if err != nil { return nil, err } dir = path.Join(cacheDir, version.String()) } return &clientSwaggerSchema{ c: client, cacheDir: dir, mapper: api.RESTMapper, }, nil } return validation.NullSchema{}, nil }, SwaggerSchema: func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() client, err := clients.ClientForVersion(&version) if err != nil { return nil, err } return client.Discovery().SwaggerSchema(version) }, DefaultNamespace: func() (string, bool, error) { return clientConfig.Namespace() }, Generators: func(cmdName string) map[string]kubectl.Generator { return DefaultGenerators(cmdName) }, CanBeExposed: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot expose a %s", kind) } return nil }, CanBeAutoscaled: func(kind unversioned.GroupKind) error { switch kind { case api.Kind("ReplicationController"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): // nothing to do here default: return fmt.Errorf("cannot autoscale a %v", kind) } return nil }, AttachablePodForObject: func(object runtime.Object) (*api.Pod, error) { client, err := clients.ClientForVersion(nil) if err != nil { return nil, err } switch t := object.(type) { case *api.ReplicationController: selector := labels.SelectorFromSet(t.Spec.Selector) pod, _, err := GetFirstPod(client, t.Namespace, selector) return pod, err case *extensions.Deployment: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } pod, _, err := GetFirstPod(client, t.Namespace, selector) return pod, err case *extensions.Job: selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("invalid label selector: %v", err) } pod, _, err := GetFirstPod(client, t.Namespace, selector) return pod, err case *api.Pod: return t, nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { return nil, err } return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk) } }, EditorEnvs: func() []string { return []string{"KUBE_EDITOR", "EDITOR"} }, } }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(projectrequestregistry.Strategy, ctx, obj); err != nil { return nil, err } projectRequest := obj.(*projectapi.ProjectRequest) if _, err := r.openshiftClient.Projects().Get(projectRequest.Name); err == nil { return nil, kapierror.NewAlreadyExists(projectapi.Resource("project"), projectRequest.Name) } projectName := projectRequest.Name projectAdmin := "" projectRequester := "" if userInfo, exists := kapi.UserFrom(ctx); exists { projectAdmin = userInfo.GetName() projectRequester = userInfo.GetName() } template, err := r.getTemplate() if err != nil { return nil, err } for i := range template.Parameters { switch template.Parameters[i].Name { case ProjectAdminUserParam: template.Parameters[i].Value = projectAdmin case ProjectDescriptionParam: template.Parameters[i].Value = projectRequest.Description case ProjectDisplayNameParam: template.Parameters[i].Value = projectRequest.DisplayName case ProjectNameParam: template.Parameters[i].Value = projectName case ProjectRequesterParam: template.Parameters[i].Value = projectRequester } } list, err := r.openshiftClient.TemplateConfigs(kapi.NamespaceDefault).Create(template) if err != nil { return nil, err } if err := utilerrors.NewAggregate(runtime.DecodeList(list.Objects, kapi.Codecs.UniversalDecoder())); err != nil { return nil, kapierror.NewInternalError(err) } // one of the items in this list should be the project. We are going to locate it, remove it from the list, create it separately var projectFromTemplate *projectapi.Project objectsToCreate := &kapi.List{} for i := range list.Objects { if templateProject, ok := list.Objects[i].(*projectapi.Project); ok { projectFromTemplate = templateProject if len(list.Objects) > (i + 1) { objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i+1:]...) } break } objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i]) } if projectFromTemplate == nil { return nil, kapierror.NewInternalError(fmt.Errorf("the project template (%s/%s) is not correctly configured: must contain a project resource", r.templateNamespace, r.templateName)) } // we split out project creation separately so that in a case of racers for the same project, only one will win and create the rest of their template objects if _, err := r.openshiftClient.Projects().Create(projectFromTemplate); err != nil { return nil, err } var restMapper meta.MultiRESTMapper seenGroups := sets.String{} for _, gv := range registered.EnabledVersions() { if seenGroups.Has(gv.Group) { continue } seenGroups.Insert(gv.Group) groupMeta, err := registered.Group(gv.Group) if err != nil { continue } restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper)) } bulk := configcmd.Bulk{ Mapper: restMapper, Typer: kapi.Scheme, RESTClientFactory: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { if latest.OriginKind(mapping.GroupVersionKind) { return r.openshiftClient, nil } return r.kubeClient, nil }, } if err := utilerrors.NewAggregate(bulk.Create(objectsToCreate, projectName)); err != nil { return nil, kapierror.NewInternalError(err) } return r.openshiftClient.Projects().Get(projectName) }
// NewFactory creates an object that holds common methods across all OpenShift commands func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory { var restMapper meta.MultiRESTMapper seenGroups := sets.String{} for _, gv := range registered.EnabledVersions() { if seenGroups.Has(gv.Group) { continue } seenGroups.Insert(gv.Group) groupMeta, err := registered.Group(gv.Group) if err != nil { continue } restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper)) } mapper := ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: restMapper}} clients := &clientCache{ clients: make(map[string]*client.Client), configs: make(map[string]*kclient.Config), loader: clientConfig, } w := &Factory{ Factory: cmdutil.NewFactory(clientConfig), OpenShiftClientConfig: clientConfig, clients: clients, } w.Object = func() (meta.RESTMapper, runtime.ObjectTyper) { // Output using whatever version was negotiated in the client cache. The // version we decode with may not be the same as what the server requires. if cfg, err := clients.ClientConfigForVersion(nil); err == nil { cmdApiVersion := unversioned.GroupVersion{} if cfg.GroupVersion != nil { cmdApiVersion = *cfg.GroupVersion } return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}, api.Scheme } return mapper, api.Scheme } kClientForMapping := w.Factory.ClientForMapping w.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { if latest.OriginKind(mapping.GroupVersionKind) { mappingVersion := mapping.GroupVersionKind.GroupVersion() client, err := clients.ClientForVersion(&mappingVersion) if err != nil { return nil, err } return client.RESTClient, nil } return kClientForMapping(mapping) } // Save original Describer function kDescriberFunc := w.Factory.Describer w.Describer = func(mapping *meta.RESTMapping) (kubectl.Describer, error) { if latest.OriginKind(mapping.GroupVersionKind) { oClient, kClient, err := w.Clients() if err != nil { return nil, fmt.Errorf("unable to create client %s: %v", mapping.GroupVersionKind.Kind, err) } mappingVersion := mapping.GroupVersionKind.GroupVersion() cfg, err := clients.ClientConfigForVersion(&mappingVersion) if err != nil { return nil, fmt.Errorf("unable to load a client %s: %v", mapping.GroupVersionKind.Kind, err) } describer, ok := describe.DescriberFor(mapping.GroupVersionKind.GroupKind(), oClient, kClient, cfg.Host) if !ok { return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) } return describer, nil } return kDescriberFunc(mapping) } kScalerFunc := w.Factory.Scaler w.Scaler = func(mapping *meta.RESTMapping) (kubectl.Scaler, error) { oc, kc, err := w.Clients() if err != nil { return nil, err } if mapping.GroupVersionKind.GroupKind() == deployapi.Kind("DeploymentConfig") { return deployscaler.NewDeploymentConfigScaler(oc, kc), nil } return kScalerFunc(mapping) } kReaperFunc := w.Factory.Reaper w.Reaper = func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { oc, kc, err := w.Clients() if err != nil { return nil, err } switch mapping.GroupVersionKind.GroupKind() { case deployapi.Kind("DeploymentConfig"): return deployreaper.NewDeploymentConfigReaper(oc, kc), nil case authorizationapi.Kind("Role"): return authorizationreaper.NewRoleReaper(oc, oc), nil case authorizationapi.Kind("ClusterRole"): return authorizationreaper.NewClusterRoleReaper(oc, oc, oc), nil case userapi.Kind("User"): return authenticationreaper.NewUserReaper( client.UsersInterface(oc), client.GroupsInterface(oc), client.ClusterRoleBindingsInterface(oc), client.RoleBindingsNamespacer(oc), kclient.SecurityContextConstraintsInterface(kc), ), nil case userapi.Kind("Group"): return authenticationreaper.NewGroupReaper( client.GroupsInterface(oc), client.ClusterRoleBindingsInterface(oc), client.RoleBindingsNamespacer(oc), kclient.SecurityContextConstraintsInterface(kc), ), nil case buildapi.Kind("BuildConfig"): return buildreaper.NewBuildConfigReaper(oc), nil } return kReaperFunc(mapping) } kGenerators := w.Factory.Generators w.Generators = func(cmdName string) map[string]kubectl.Generator { originGenerators := DefaultGenerators(cmdName) kubeGenerators := kGenerators(cmdName) ret := map[string]kubectl.Generator{} for k, v := range kubeGenerators { ret[k] = v } for k, v := range originGenerators { ret[k] = v } return ret } kPodSelectorForObjectFunc := w.Factory.PodSelectorForObject w.PodSelectorForObject = func(object runtime.Object) (string, error) { switch t := object.(type) { case *deployapi.DeploymentConfig: return kubectl.MakeLabels(t.Spec.Selector), nil default: return kPodSelectorForObjectFunc(object) } } kMapBasedSelectorForObjectFunc := w.Factory.MapBasedSelectorForObject w.MapBasedSelectorForObject = func(object runtime.Object) (string, error) { switch t := object.(type) { case *deployapi.DeploymentConfig: return kubectl.MakeLabels(t.Spec.Selector), nil default: return kMapBasedSelectorForObjectFunc(object) } } kPortsForObjectFunc := w.Factory.PortsForObject w.PortsForObject = func(object runtime.Object) ([]string, error) { switch t := object.(type) { case *deployapi.DeploymentConfig: return getPorts(t.Spec.Template.Spec), nil default: return kPortsForObjectFunc(object) } } kLogsForObjectFunc := w.Factory.LogsForObject w.LogsForObject = func(object, options runtime.Object) (*kclient.Request, error) { oc, _, err := w.Clients() if err != nil { return nil, err } switch t := object.(type) { case *deployapi.DeploymentConfig: dopts, ok := options.(*deployapi.DeploymentLogOptions) if !ok { return nil, errors.New("provided options object is not a DeploymentLogOptions") } return oc.DeploymentLogs(t.Namespace).Get(t.Name, *dopts), nil case *buildapi.Build: bopts, ok := options.(*buildapi.BuildLogOptions) if !ok { return nil, errors.New("provided options object is not a BuildLogOptions") } if bopts.Version != nil { return nil, errors.New("cannot specify a version and a build") } return oc.BuildLogs(t.Namespace).Get(t.Name, *bopts), nil case *buildapi.BuildConfig: bopts, ok := options.(*buildapi.BuildLogOptions) if !ok { return nil, errors.New("provided options object is not a BuildLogOptions") } builds, err := oc.Builds(t.Namespace).List(api.ListOptions{}) if err != nil { return nil, err } builds.Items = buildapi.FilterBuilds(builds.Items, buildapi.ByBuildConfigLabelPredicate(t.Name)) if len(builds.Items) == 0 { return nil, fmt.Errorf("no builds found for %q", t.Name) } if bopts.Version != nil { // If a version has been specified, try to get the logs from that build. desired := buildutil.BuildNameForConfigVersion(t.Name, int(*bopts.Version)) return oc.BuildLogs(t.Namespace).Get(desired, *bopts), nil } sort.Sort(sort.Reverse(buildapi.BuildSliceByCreationTimestamp(builds.Items))) return oc.BuildLogs(t.Namespace).Get(builds.Items[0].Name, *bopts), nil default: return kLogsForObjectFunc(object, options) } } w.Printer = func(mapping *meta.RESTMapping, noHeaders, withNamespace, wide bool, showAll bool, showLabels, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error) { return describe.NewHumanReadablePrinter(noHeaders, withNamespace, wide, showAll, showLabels, absoluteTimestamps, columnLabels), nil } kCanBeExposed := w.Factory.CanBeExposed w.CanBeExposed = func(kind unversioned.GroupKind) error { if kind == deployapi.Kind("DeploymentConfig") { return nil } return kCanBeExposed(kind) } kCanBeAutoscaled := w.Factory.CanBeAutoscaled w.CanBeAutoscaled = func(kind unversioned.GroupKind) error { if kind == deployapi.Kind("DeploymentConfig") { return nil } return kCanBeAutoscaled(kind) } kAttachablePodForObjectFunc := w.Factory.AttachablePodForObject w.AttachablePodForObject = func(object runtime.Object) (*api.Pod, error) { oc, kc, err := w.Clients() if err != nil { return nil, err } switch t := object.(type) { case *deployapi.DeploymentConfig: var err error var pods *api.PodList for pods == nil || len(pods.Items) == 0 { if t.Status.LatestVersion == 0 { time.Sleep(2 * time.Second) } if t, err = oc.DeploymentConfigs(t.Namespace).Get(t.Name); err != nil { return nil, err } latestDeploymentName := deployutil.LatestDeploymentNameForConfig(t) deployment, err := kc.ReplicationControllers(t.Namespace).Get(latestDeploymentName) if err != nil { if kerrors.IsNotFound(err) { continue } return nil, err } pods, err = kc.Pods(deployment.Namespace).List(api.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector)}) if err != nil { return nil, err } if len(pods.Items) == 0 { time.Sleep(2 * time.Second) } } var oldestPod *api.Pod for _, pod := range pods.Items { if oldestPod == nil || pod.CreationTimestamp.Before(oldestPod.CreationTimestamp) { oldestPod = &pod } } return oldestPod, nil default: return kAttachablePodForObjectFunc(object) } } kSwaggerSchemaFunc := w.Factory.SwaggerSchema w.Factory.SwaggerSchema = func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) { if !latest.OriginKind(gvk) { return kSwaggerSchemaFunc(gvk) } // TODO: we need to register the OpenShift API under the Kube group, and start returning the OpenShift // group from the scheme. oc, _, err := w.Clients() if err != nil { return nil, err } return w.OriginSwaggerSchema(oc.RESTClient, gvk.GroupVersion()) } w.EditorEnvs = func() []string { return []string{"OC_EDITOR", "EDITOR"} } return w }
} wait.Poll(time.Second*30, time.Minute*5, func() (bool, error) { data, err := f.Client.RESTClient.Get().AbsPath("/apis/company.com/v1/foos").DoRaw() if err != nil { return false, err } meta := unversioned.TypeMeta{} if err := json.Unmarshal(data, &meta); err != nil { return false, err } if meta.Kind == "FooList" { return true, nil } status := unversioned.Status{} if err := runtime.DecodeInto(api.Codecs.LegacyCodec(registered.EnabledVersions()...), data, &status); err != nil { return false, err } if status.Code != http.StatusNotFound { return false, fmt.Errorf("Unexpected status: %v", status) } return false, nil }) data, err := f.Client.RESTClient.Get().AbsPath("/apis/company.com/v1/foos").DoRaw() if err != nil { framework.Failf("failed to list with no objects: %v", err) } list := FooList{} if err := json.Unmarshal(data, &list); err != nil { framework.Failf("failed to decode: %#v", err)