func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data) if err != nil { return err } gv, err := unversioned.ParseGroupVersion(version) if err != nil { return fmt.Errorf("unable to parse group/version from %q: %v", version, err) } if ok := registered.IsRegisteredAPIGroupVersion(gv); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", version, registered.RegisteredGroupVersions) } resource, _ := meta.KindToResource(kind, false) gvk, err := c.mapper.KindFor(resource) if err != nil { return fmt.Errorf("could not find api group for %s: %v", kind, err) } if gvk.Group == "extensions" { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", version, c.cacheDir) } return getSchemaAndValidate(c.c.RESTClient, data, "api", version, c.cacheDir) }
// InstallThirdPartyResource installs a third party resource specified by 'rsrc'. When a resource is // installed a corresponding RESTful resource is added as a valid path in the web service provided by // the master. // // For example, if you install a resource ThirdPartyResource{ Name: "foo.company.com", Versions: {"v1"} } // then the following RESTful resource is created on the server: // http://<host>/apis/company.com/v1/foos/... func (m *Master) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) error { kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) if err != nil { return err } plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ Group: group, Version: rsrc.Versions[0].Name, Kind: kind, }) thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name, plural.Resource) if err := thirdparty.InstallREST(m.HandlerContainer); err != nil { glog.Fatalf("Unable to setup thirdparty api: %v", err) } path := makeThirdPartyPath(group) groupVersion := unversioned.GroupVersionForDiscovery{ GroupVersion: group + "/" + rsrc.Versions[0].Name, Version: rsrc.Versions[0].Name, } apiGroup := unversioned.APIGroup{ Name: group, Versions: []unversioned.GroupVersionForDiscovery{groupVersion}, PreferredVersion: groupVersion, } apiserver.AddGroupWebService(api.Codecs, m.HandlerContainer, path, apiGroup) m.addThirdPartyResourceStorage(path, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup) apiserver.InstallServiceErrorHandler(api.Codecs, m.HandlerContainer, m.NewRequestInfoResolver(), []string{thirdparty.GroupVersion.String()}) return nil }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data) if err != nil { return err } if ok := registered.IsRegisteredAPIVersion(version); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", version, registered.RegisteredVersions) } resource, _ := meta.KindToResource(kind, false) group, err := c.mapper.GroupForResource(resource) if err != nil { return fmt.Errorf("could not find api group for %s: %v", kind, err) } if group == "experimental" { g, err := latest.Group(group) if err != nil { return err } if c.c.ExperimentalClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExperimentalClient.RESTClient, data, "apis/"+g.Group, version, c.cacheDir) } return getSchemaAndValidate(c.c.RESTClient, data, "api", version, c.cacheDir) }
// Get takes the reference to scale subresource and returns the subresource or error, if one occurs. func (c *scales) Get(kind string, name string) (result *extensions.Scale, err error) { result = &extensions.Scale{} // TODO this method needs to take a proper unambiguous kind fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind} resource, _ := meta.KindToResource(fullyQualifiedKind) err = c.client.Get().Namespace(c.ns).Resource(resource.Resource).Name(name).SubResource("scale").Do().Into(result) return }
func (c *scales) Update(kind string, scale *experimental.Scale) (result *experimental.Scale, err error) { result = &experimental.Scale{} resource, _ := meta.KindToResource(kind, false) err = c.client.Put(). Namespace(scale.Namespace). Resource(resource). Name(scale.Name). SubResource("scale"). Body(scale). Do(). Into(result) return }
// Complete calls the upstream Complete for the logs command and then resolves the // resource a user requested to view its logs and creates the appropriate logOptions // object for it. func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if err := o.KubeLogOptions.Complete(f.Factory, out, cmd, args); err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions) mapper, typer := f.Object() infos, err := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace).DefaultNamespace(). ResourceNames("pods", args...). SingleResourceType().RequireObject(false). Do().Infos() if err != nil { return err } if len(infos) != 1 { return errors.New("expected a resource") } _, resource := meta.KindToResource(infos[0].Mapping.Kind, false) // TODO: podLogOptions should be included in our own logOptions objects. switch resource { case "build", "buildconfig": o.Options = &buildapi.BuildLogOptions{ Follow: podLogOptions.Follow, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } case "deploymentconfig": o.Options = &deployapi.DeploymentLogOptions{ Follow: podLogOptions.Follow, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } default: o.Options = nil } return nil }
func (c *scales) Update(kind string, scale *v1beta1.Scale) (result *v1beta1.Scale, err error) { result = &v1beta1.Scale{} // TODO this method needs to take a proper unambiguous kind fullyQualifiedKind := schema.GroupVersionKind{Kind: kind} resource, _ := meta.KindToResource(fullyQualifiedKind) err = c.client.Put(). Namespace(scale.Namespace). Resource(resource.Resource). Name(scale.Name). SubResource("scale"). Body(scale). Do(). Into(result) return }
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object // and print "resource/name" pair. If the object is a List, print all items in it. func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error { objvalue := reflect.ValueOf(obj).Elem() kind := objvalue.FieldByName("Kind") if !kind.IsValid() { kind = reflect.ValueOf("<unknown>") } if kind.String() == "List" { items := objvalue.FieldByName("Items") if items.Type().String() == "[]runtime.RawExtension" { for i := 0; i < items.Len(); i++ { rawObj := items.Index(i).FieldByName("RawJSON").Interface().([]byte) scheme := api.Scheme version, kind, err := scheme.DataVersionAndKind(rawObj) if err != nil { return err } decodedObj, err := scheme.DecodeToVersion(rawObj, "") if err != nil { return err } tpmeta := api.TypeMeta{ APIVersion: version, Kind: kind, } s := reflect.ValueOf(decodedObj).Elem() s.FieldByName("TypeMeta").Set(reflect.ValueOf(tpmeta)) p.PrintObj(decodedObj, w) } } else { return errors.New("the list object contains unrecognized items.") } } else { name := objvalue.FieldByName("Name") if !name.IsValid() { name = reflect.ValueOf("<unknown>") } _, resource := meta.KindToResource(kind.String(), false) fmt.Fprintf(w, "%s/%s\n", resource, name) } return nil }
// InstallThirdPartyResource installs a third party resource specified by 'rsrc'. When a resource is // installed a corresponding RESTful resource is added as a valid path in the web service provided by // the master. // // For example, if you install a resource ThirdPartyResource{ Name: "foo.company.com", Versions: {"v1"} } // then the following RESTful resource is created on the server: // http://<host>/apis/company.com/v1/foos/... func (m *ThirdPartyResourceServer) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) error { kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) if err != nil { return err } if len(rsrc.Versions) == 0 { return fmt.Errorf("ThirdPartyResource %s has no defined versions", rsrc.Name) } plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ Group: group, Version: rsrc.Versions[0].Name, Kind: kind, }) path := extensionsrest.MakeThirdPartyPath(group) groupVersion := unversioned.GroupVersionForDiscovery{ GroupVersion: group + "/" + rsrc.Versions[0].Name, Version: rsrc.Versions[0].Name, } apiGroup := unversioned.APIGroup{ Name: group, Versions: []unversioned.GroupVersionForDiscovery{groupVersion}, PreferredVersion: groupVersion, } thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name, plural.Resource) // If storage exists, this group has already been added, just update // the group with the new API if m.hasThirdPartyGroupStorage(path) { m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup) return thirdparty.UpdateREST(m.genericAPIServer.HandlerContainer.Container) } if err := thirdparty.InstallREST(m.genericAPIServer.HandlerContainer.Container); err != nil { glog.Errorf("Unable to setup thirdparty api: %v", err) } m.genericAPIServer.HandlerContainer.Add(apiserver.NewGroupWebService(api.Codecs, path, apiGroup)) m.addThirdPartyResourceStorage(path, plural.Resource, thirdparty.Storage[plural.Resource].(*thirdpartyresourcedataetcd.REST), apiGroup) return nil }
// HasThirdPartyResource returns true if a particular third party resource currently installed. func (m *ThirdPartyResourceServer) HasThirdPartyResource(rsrc *extensions.ThirdPartyResource) (bool, error) { kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(rsrc) if err != nil { return false, err } path := extensionsrest.MakeThirdPartyPath(group) m.thirdPartyResourcesLock.Lock() defer m.thirdPartyResourcesLock.Unlock() entry := m.thirdPartyResources[path] if entry == nil { return false, nil } plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ Group: group, Version: rsrc.Versions[0].Name, Kind: kind, }) _, found := entry.storage[plural.Resource] return found, nil }
func TestInstallMultipleAPIs(t *testing.T) { names := []string{"foo.company.com", "bar.company.com"} versions := []string{"v1", "v1"} _, etcdserver, server, assert := initThirdPartyMultiple(t, versions, names) defer server.Close() defer etcdserver.Terminate(t) for ix := range names { kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind( &extensions.ThirdPartyResource{ObjectMeta: api.ObjectMeta{Name: names[ix]}}) assert.NoError(err, "Failed to extract group & kind") plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ Group: group, Version: versions[ix], Kind: kind, }) resp, err := http.Get( fmt.Sprintf("%s/apis/%s/%s/namespaces/default/%s", server.URL, group, versions[ix], plural.Resource)) if !assert.NoError(err, "Failed to do HTTP GET") { return } defer resp.Body.Close() assert.Equal(http.StatusOK, resp.StatusCode) data, err := ioutil.ReadAll(resp.Body) assert.NoError(err) obj := map[string]interface{}{} if err = json.Unmarshal(data, &obj); err != nil { assert.NoError(err, fmt.Sprintf("unexpected error: %v", err)) } kindOut, found := obj["kind"] if !found { t.Errorf("Missing 'kind' in %v", obj) } assert.Equal(kindOut, kind+"List") } }
// ResolveResource returns the resource type and name of the resourceString. // If the resource string has no specified type, defaultResource will be returned. func ResolveResource(defaultResource, resourceString string, mapper meta.RESTMapper) (string, string, error) { if mapper == nil { return "", "", errors.New("mapper cannot be nil") } var name string parts := strings.Split(resourceString, "/") switch len(parts) { case 1: name = parts[0] case 2: gvk, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: parts[0]}) if err != nil { return "", "", err } name = parts[1] resource, _ := meta.KindToResource(gvk, false) return resource.Resource, name, nil default: return "", "", fmt.Errorf("invalid resource format: %s", resourceString) } return defaultResource, name, nil }
func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *RollingUpdateOptions) error { if len(os.Args) > 1 && os.Args[1] == "rollingupdate" { printDeprecationWarning("rolling-update", "rollingupdate") } err := validateArguments(cmd, options.Filenames, args) if err != nil { return err } deploymentKey := cmdutil.GetFlagString(cmd, "deployment-label-key") filename := "" image := cmdutil.GetFlagString(cmd, "image") pullPolicy := cmdutil.GetFlagString(cmd, "image-pull-policy") oldName := args[0] rollback := cmdutil.GetFlagBool(cmd, "rollback") period := cmdutil.GetFlagDuration(cmd, "update-period") interval := cmdutil.GetFlagDuration(cmd, "poll-interval") timeout := cmdutil.GetFlagDuration(cmd, "timeout") dryrun := cmdutil.GetFlagBool(cmd, "dry-run") outputFormat := cmdutil.GetFlagString(cmd, "output") container := cmdutil.GetFlagString(cmd, "container") if len(options.Filenames) > 0 { filename = options.Filenames[0] } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } var newRc *api.ReplicationController // fetch rc oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName) if err != nil { if !errors.IsNotFound(err) || len(image) == 0 || len(args) > 1 { return err } // We're in the middle of a rename, look for an RC with a source annotation of oldName newRc, err := kubectl.FindSourceController(client, cmdNamespace, oldName) if err != nil { return err } return kubectl.Rename(client, newRc, oldName) } var keepOldName bool var replicasDefaulted bool mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd)) if len(filename) != 0 { schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } request := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). Schema(schema). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, false, filename). Do() obj, err := request.Object() if err != nil { return err } var ok bool // Handle filename input from stdin. The resource builder always returns an api.List // when creating resource(s) from a stream. if list, ok := obj.(*api.List); ok { if len(list.Items) > 1 { return cmdutil.UsageError(cmd, "%s specifies multiple items", filename) } obj = list.Items[0] } newRc, ok = obj.(*api.ReplicationController) if !ok { if gvk, err := typer.ObjectKind(obj); err == nil { return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvk) } glog.V(4).Infof("Object %#v is not a ReplicationController", obj) return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) } infos, err := request.Infos() if err != nil || len(infos) != 1 { glog.V(2).Infof("was not able to recover adequate information to discover if .spec.replicas was defaulted") } else { replicasDefaulted = isReplicasDefaulted(infos[0]) } } // If the --image option is specified, we need to create a new rc with at least one different selector // than the old rc. This selector is the hash of the rc, with a suffix to provide uniqueness for // same-image updates. if len(image) != 0 { codec := api.Codecs.LegacyCodec(client.APIVersion()) keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc != nil { if inProgressImage := newRc.Spec.Template.Spec.Containers[0].Image; inProgressImage != image { return cmdutil.UsageError(cmd, "Found existing in-progress update to image (%s).\nEither continue in-progress update with --image=%s or rollback with --rollback", inProgressImage, inProgressImage) } fmt.Fprintf(out, "Found existing update in progress (%s), resuming.\n", newRc.Name) } else { config := &kubectl.NewControllerConfig{ Namespace: cmdNamespace, OldName: oldName, NewName: newName, Image: image, Container: container, DeploymentKey: deploymentKey, } if oldRc.Spec.Template.Spec.Containers[0].Image == image { if len(pullPolicy) == 0 { return cmdutil.UsageError(cmd, "--image-pull-policy (Always|Never|IfNotPresent) must be provided when --image is the same as existing container image") } config.PullPolicy = api.PullPolicy(pullPolicy) } newRc, err = kubectl.CreateNewControllerFromCurrentController(client, codec, config) if err != nil { return err } } // Update the existing replication controller with pointers to the 'next' controller // and adding the <deploymentKey> label if necessary to distinguish it from the 'next' controller. oldHash, err := api.HashObject(oldRc, codec) if err != nil { return err } // If new image is same as old, the hash may not be distinct, so add a suffix. oldHash += "-orig" oldRc, err = kubectl.UpdateExistingReplicationController(client, oldRc, cmdNamespace, newRc.Name, deploymentKey, oldHash, out) if err != nil { return err } } if rollback { keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc == nil { return cmdutil.UsageError(cmd, "Could not find %s to rollback.\n", newName) } } if oldName == newRc.Name { return cmdutil.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s", filename, oldName) } updater := kubectl.NewRollingUpdater(newRc.Namespace, client) // To successfully pull off a rolling update the new and old rc have to differ // by at least one selector. Every new pod should have the selector and every // old pod should not have the selector. var hasLabel bool for key, oldValue := range oldRc.Spec.Selector { if newValue, ok := newRc.Spec.Selector[key]; ok && newValue != oldValue { hasLabel = true break } } if !hasLabel { return cmdutil.UsageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s", filename, oldName) } // TODO: handle scales during rolling update if replicasDefaulted { newRc.Spec.Replicas = oldRc.Spec.Replicas } if dryrun { oldRcData := &bytes.Buffer{} newRcData := &bytes.Buffer{} if outputFormat == "" { oldRcData.WriteString(oldRc.Name) newRcData.WriteString(newRc.Name) } else { if err := f.PrintObject(cmd, mapper, oldRc, oldRcData); err != nil { return err } if err := f.PrintObject(cmd, mapper, newRc, newRcData); err != nil { return err } } fmt.Fprintf(out, "Rolling from:\n%s\nTo:\n%s\n", string(oldRcData.Bytes()), string(newRcData.Bytes())) return nil } updateCleanupPolicy := kubectl.DeleteRollingUpdateCleanupPolicy if keepOldName { updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy } config := &kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, NewRc: newRc, UpdatePeriod: period, Interval: interval, Timeout: timeout, CleanupPolicy: updateCleanupPolicy, MaxUnavailable: intstr.FromInt(0), MaxSurge: intstr.FromInt(1), } if rollback { err = kubectl.AbortRollingUpdate(config) if err != nil { return err } client.ReplicationControllers(config.NewRc.Namespace).Update(config.NewRc) } err = updater.Update(config) if err != nil { return err } message := "rolling updated" if keepOldName { newRc.Name = oldName } else { message = fmt.Sprintf("rolling updated to %q", newRc.Name) } newRc, err = client.ReplicationControllers(cmdNamespace).Get(newRc.Name) if err != nil { return err } if outputFormat != "" { return f.PrintObject(cmd, mapper, newRc, out) } kind, err := api.Scheme.ObjectKind(newRc) if err != nil { return err } _, res := meta.KindToResource(kind) cmdutil.PrintSuccess(mapper, false, out, res.Resource, oldName, message) return nil }
func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *RollingUpdateOptions) error { if len(os.Args) > 1 && os.Args[1] == "rollingupdate" { printDeprecationWarning("rolling-update", "rollingupdate") } deploymentKey, filename, image, oldName, err := validateArguments(cmd, options.Filenames, args) if err != nil { return err } period := cmdutil.GetFlagDuration(cmd, "update-period") interval := cmdutil.GetFlagDuration(cmd, "poll-interval") timeout := cmdutil.GetFlagDuration(cmd, "timeout") dryrun := cmdutil.GetFlagBool(cmd, "dry-run") outputFormat := cmdutil.GetFlagString(cmd, "output") cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } var newRc *api.ReplicationController // fetch rc oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName) if err != nil { if !errors.IsNotFound(err) || len(image) == 0 || len(args) > 1 { return err } // We're in the middle of a rename, look for an RC with a source annotation of oldName newRc, err := kubectl.FindSourceController(client, cmdNamespace, oldName) if err != nil { return err } return kubectl.Rename(client, newRc, oldName) } var keepOldName bool var replicasDefaulted bool mapper, typer := f.Object() if len(filename) != 0 { schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate")) if err != nil { return err } request := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). Schema(schema). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, filename). Do() obj, err := request.Object() if err != nil { return err } var ok bool // Handle filename input from stdin. The resource builder always returns an api.List // when creating resource(s) from a stream. if list, ok := obj.(*api.List); ok { if len(list.Items) > 1 { return cmdutil.UsageError(cmd, "%s specifies multiple items", filename) } obj = list.Items[0] } newRc, ok = obj.(*api.ReplicationController) if !ok { if _, kind, err := typer.ObjectVersionAndKind(obj); err == nil { return cmdutil.UsageError(cmd, "%s contains a %s not a ReplicationController", filename, kind) } glog.V(4).Infof("Object %#v is not a ReplicationController", obj) return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) } infos, err := request.Infos() if err != nil || len(infos) != 1 { glog.V(2).Infof("was not able to recover adequate information to discover if .spec.replicas was defaulted") } else { replicasDefaulted = isReplicasDefaulted(infos[0]) } } // If the --image option is specified, we need to create a new rc with at least one different selector // than the old rc. This selector is the hash of the rc, which will differ because the new rc has a // different image. if len(image) != 0 { keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc != nil { fmt.Fprintf(out, "Found existing update in progress (%s), resuming.\n", newRc.Name) } else { newRc, err = kubectl.CreateNewControllerFromCurrentController(client, cmdNamespace, oldName, newName, image, deploymentKey) if err != nil { return err } } // Update the existing replication controller with pointers to the 'next' controller // and adding the <deploymentKey> label if necessary to distinguish it from the 'next' controller. oldHash, err := api.HashObject(oldRc, client.Codec) if err != nil { return err } oldRc, err = kubectl.UpdateExistingReplicationController(client, oldRc, cmdNamespace, newRc.Name, deploymentKey, oldHash, out) if err != nil { return err } } if oldName == newRc.Name { return cmdutil.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s", filename, oldName) } updater := kubectl.NewRollingUpdater(newRc.Namespace, client) // To successfully pull off a rolling update the new and old rc have to differ // by at least one selector. Every new pod should have the selector and every // old pod should not have the selector. var hasLabel bool for key, oldValue := range oldRc.Spec.Selector { if newValue, ok := newRc.Spec.Selector[key]; ok && newValue != oldValue { hasLabel = true break } } if !hasLabel { return cmdutil.UsageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s", filename, oldName) } // TODO: handle scales during rolling update if replicasDefaulted { newRc.Spec.Replicas = oldRc.Spec.Replicas } if dryrun { oldRcData := &bytes.Buffer{} newRcData := &bytes.Buffer{} if outputFormat == "" { oldRcData.WriteString(oldRc.Name) newRcData.WriteString(newRc.Name) } else { if err := f.PrintObject(cmd, oldRc, oldRcData); err != nil { return err } if err := f.PrintObject(cmd, newRc, newRcData); err != nil { return err } } fmt.Fprintf(out, "Rolling from:\n%s\nTo:\n%s\n", string(oldRcData.Bytes()), string(newRcData.Bytes())) return nil } updateCleanupPolicy := kubectl.DeleteRollingUpdateCleanupPolicy if keepOldName { updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy } config := &kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, NewRc: newRc, UpdatePeriod: period, Interval: interval, Timeout: timeout, CleanupPolicy: updateCleanupPolicy, MaxUnavailable: util.NewIntOrStringFromInt(0), MaxSurge: util.NewIntOrStringFromInt(1), } if cmdutil.GetFlagBool(cmd, "rollback") { kubectl.AbortRollingUpdate(config) client.ReplicationControllers(config.NewRc.Namespace).Update(config.NewRc) } err = updater.Update(config) if err != nil { return err } message := "rolling updated" if keepOldName { newRc.Name = oldName } else { message = fmt.Sprintf("rolling updated to %q", newRc.Name) } newRc, err = client.ReplicationControllers(cmdNamespace).Get(newRc.Name) if err != nil { return err } if outputFormat != "" { return f.PrintObject(cmd, newRc, out) } _, kind, err := api.Scheme.ObjectVersionAndKind(newRc) if err != nil { return err } _, res := meta.KindToResource(kind, false) cmdutil.PrintSuccess(mapper, false, out, res, oldName, message) return nil }
func (t *thirdPartyResourceDataMapper) getResource() unversioned.GroupVersionResource { plural, _ := meta.KindToResource(t.getKind()) return plural }
func (c *AssetConfig) addHandlers(mux *http.ServeMux) error { assetHandler, err := c.buildAssetHandler() if err != nil { return err } publicURL, err := url.Parse(c.Options.PublicURL) if err != nil { return err } masterURL, err := url.Parse(c.Options.MasterPublicURL) if err != nil { return err } // Web console assets mux.Handle(publicURL.Path, http.StripPrefix(publicURL.Path, assetHandler)) originResources := sets.NewString() k8sResources := sets.NewString() versions := []unversioned.GroupVersion{} versions = append(versions, latest.Versions...) versions = append(versions, klatest.ExternalVersions...) deadOriginVersions := sets.NewString(configapi.DeadOpenShiftAPILevels...) deadKubernetesVersions := sets.NewString(configapi.DeadKubernetesAPILevels...) for _, version := range versions { for kind := range api.Scheme.KnownTypes(version) { if strings.HasSuffix(kind, "List") { continue } resource, _ := meta.KindToResource(kind, false) if latest.OriginKind(version.WithKind(kind)) { if !deadOriginVersions.Has(version.String()) { originResources.Insert(resource) } } else { if !deadKubernetesVersions.Has(version.String()) { k8sResources.Insert(resource) } } } } commonResources := sets.NewString() for _, r := range originResources.List() { if k8sResources.Has(r) { commonResources.Insert(r) } } if commonResources.Len() > 0 { return fmt.Errorf("Resources for kubernetes and origin types intersect: %v", commonResources.List()) } // Generated web console config config := assets.WebConsoleConfig{ MasterAddr: masterURL.Host, MasterPrefix: OpenShiftAPIPrefix, MasterResources: originResources.List(), KubernetesAddr: masterURL.Host, KubernetesPrefix: KubernetesAPIPrefix, KubernetesResources: k8sResources.List(), OAuthAuthorizeURI: OpenShiftOAuthAuthorizeURL(masterURL.String()), OAuthRedirectBase: c.Options.PublicURL, OAuthClientID: OpenShiftWebConsoleClientID, LogoutURI: c.Options.LogoutURL, LoggingURL: c.Options.LoggingPublicURL, MetricsURL: c.Options.MetricsPublicURL, } configPath := path.Join(publicURL.Path, "config.js") configHandler, err := assets.GeneratedConfigHandler(config) if err != nil { return err } mux.Handle(configPath, assets.GzipHandler(configHandler)) // Extension scripts extScriptsPath := path.Join(publicURL.Path, "scripts/extensions.js") extScriptsHandler, err := assets.ExtensionScriptsHandler(c.Options.ExtensionScripts, c.Options.ExtensionDevelopment) if err != nil { return err } mux.Handle(extScriptsPath, assets.GzipHandler(extScriptsHandler)) // Extension stylesheets extStylesheetsPath := path.Join(publicURL.Path, "styles/extensions.css") extStylesheetsHandler, err := assets.ExtensionStylesheetsHandler(c.Options.ExtensionStylesheets, c.Options.ExtensionDevelopment) if err != nil { return err } mux.Handle(extStylesheetsPath, assets.GzipHandler(extStylesheetsHandler)) // Extension files for _, extConfig := range c.Options.Extensions { extPath := path.Join(publicURL.Path, "extensions", extConfig.Name) + "/" extHandler := assets.AssetExtensionHandler(extConfig.SourceDirectory, extPath, extConfig.HTML5Mode) mux.Handle(extPath, http.StripPrefix(extPath, extHandler)) } return nil }
func (t *thirdPartyResourceDataMapper) isThirdPartyResource(resource string) bool { plural, _ := meta.KindToResource(t.kind, false) return resource == plural }
// Get takes the reference to scale subresource and returns the subresource or error, if one occurs. func (c *scales) Get(kind string, name string) (result *experimental.Scale, err error) { result = &experimental.Scale{} resource, _ := meta.KindToResource(kind, false) err = c.client.Get().Namespace(c.ns).Resource(resource).Name(name).SubResource("scale").Do().Into(result) return }
func testInstallThirdPartyAPIListVersion(t *testing.T, version string) { tests := []struct { items []Foo name string test string }{ { name: "foo.company.com", test: "null", }, { items: []Foo{}, name: "foo.company.com", test: "empty", }, { items: []Foo{}, name: "policy.company.com", test: "plurals", }, { items: []Foo{ { ObjectMeta: api.ObjectMeta{ Name: "test", }, TypeMeta: unversioned.TypeMeta{ Kind: "Foo", APIVersion: version, }, SomeField: "test field", OtherField: 10, }, { ObjectMeta: api.ObjectMeta{ Name: "bar", }, TypeMeta: unversioned.TypeMeta{ Kind: "Foo", APIVersion: version, }, SomeField: "test field another", OtherField: 20, }, }, name: "foo.company.com", test: "real list", }, } for _, test := range tests { func() { master, etcdserver, server, assert := initThirdParty(t, version, test.name) defer server.Close() defer etcdserver.Terminate(t) kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind( &extensions.ThirdPartyResource{ObjectMeta: api.ObjectMeta{Name: test.name}}) assert.NoError(err, test.test) plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ Group: group, Version: version, Kind: kind, }) if test.items != nil { err := createThirdPartyList(master.thirdPartyStorage, fmt.Sprintf("/ThirdPartyResourceData/%s/%s/default", group, plural.Resource), test.items) if !assert.NoError(err, test.test) { return } } resp, err := http.Get( fmt.Sprintf("%s/apis/%s/%s/namespaces/default/%s", server.URL, group, version, plural.Resource)) if !assert.NoError(err, test.test) { return } defer resp.Body.Close() assert.Equal(http.StatusOK, resp.StatusCode, test.test) data, err := ioutil.ReadAll(resp.Body) assert.NoError(err, test.test) list := FooList{} if err = json.Unmarshal(data, &list); err != nil { assert.NoError(err, "unexpected error: %v %s", err, test.test) } if test.items == nil { if len(list.Items) != 0 { assert.NoError(err, "expected no items, saw: %v %s", err, list.Items, test.test) } return } if len(list.Items) != len(test.items) { t.Fatalf("(%s) unexpected length: %d vs %d", test.name, len(list.Items), len(test.items)) } // The order of elements in LIST is not guaranteed. mapping := make(map[string]int) for ix := range test.items { mapping[test.items[ix].Name] = ix } for ix := range list.Items { // Copy things that are set dynamically on the server expectedObj := test.items[mapping[list.Items[ix].Name]] expectedObj.SelfLink = list.Items[ix].SelfLink expectedObj.ResourceVersion = list.Items[ix].ResourceVersion expectedObj.Namespace = list.Items[ix].Namespace expectedObj.UID = list.Items[ix].UID expectedObj.CreationTimestamp = list.Items[ix].CreationTimestamp // We endure the order of items by sorting them (using 'mapping') // so that this function passes. if !reflect.DeepEqual(list.Items[ix], expectedObj) { t.Errorf("(%s) expected:\n%#v\nsaw:\n%#v\n", test.name, expectedObj, list.Items[ix]) } } }() } }
// Complete calls the upstream Complete for the logs command and then resolves the // resource a user requested to view its logs and creates the appropriate logOptions // object for it. func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if err := o.KubeLogOptions.Complete(f.Factory, out, cmd, args); err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions) mapper, typer := f.Object() infos, err := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). NamespaceParam(namespace).DefaultNamespace(). ResourceNames("pods", args...). SingleResourceType().RequireObject(false). Do().Infos() if err != nil { return err } if len(infos) != 1 { return errors.New("expected a resource") } version := kcmdutil.GetFlagInt64(cmd, "version") _, resource := meta.KindToResource(infos[0].Mapping.GroupVersionKind, false) // TODO: podLogOptions should be included in our own logOptions objects. switch resource.GroupResource() { case buildapi.Resource("build"), buildapi.Resource("buildconfig"): bopts := &buildapi.BuildLogOptions{ Follow: podLogOptions.Follow, Previous: podLogOptions.Previous, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } if version != 0 { bopts.Version = &version } o.Options = bopts case deployapi.Resource("deploymentconfig"): dopts := &deployapi.DeploymentLogOptions{ Follow: podLogOptions.Follow, Previous: podLogOptions.Previous, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } if version != 0 { dopts.Version = &version } o.Options = dopts default: o.Options = nil } return nil }
func (c *AssetConfig) addHandlers(handler http.Handler) (http.Handler, error) { publicURL, err := url.Parse(c.Options.PublicURL) if err != nil { return nil, err } mux := http.NewServeMux() if handler != nil { // colocated with other routes, so pass any unrecognized routes through to // handler mux.Handle("/", handler) } else { // standalone mode, so redirect any unrecognized routes to the console if publicURL.Path != "/" { mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { http.Redirect(w, req, publicURL.Path, http.StatusFound) }) } } assetHandler, err := c.buildAssetHandler() if err != nil { return nil, err } masterURL, err := url.Parse(c.Options.MasterPublicURL) if err != nil { return nil, err } // Web console assets mux.Handle(publicURL.Path, http.StripPrefix(publicURL.Path, assetHandler)) originResources := sets.NewString() k8sResources := sets.NewString() versions := []unversioned.GroupVersion{} versions = append(versions, registered.GroupOrDie(api.GroupName).GroupVersions...) versions = append(versions, registered.GroupOrDie(kapi.GroupName).GroupVersions...) deadOriginVersions := sets.NewString(configapi.DeadOpenShiftAPILevels...) deadKubernetesVersions := sets.NewString(configapi.DeadKubernetesAPILevels...) for _, version := range versions { for kind := range kapi.Scheme.KnownTypes(version) { if strings.HasSuffix(kind, "List") { continue } resource, _ := meta.KindToResource(version.WithKind(kind)) if latest.OriginKind(version.WithKind(kind)) { if !deadOriginVersions.Has(version.String()) { originResources.Insert(resource.Resource) } } else { if !deadKubernetesVersions.Has(version.String()) { k8sResources.Insert(resource.Resource) } } } } commonResources := sets.NewString() for _, r := range originResources.List() { if k8sResources.Has(r) { commonResources.Insert(r) } } if commonResources.Len() > 0 { return nil, fmt.Errorf("Resources for kubernetes and origin types intersect: %v", commonResources.List()) } // Generated web console config and server version config := assets.WebConsoleConfig{ APIGroupAddr: masterURL.Host, APIGroupPrefix: genericapiserver.APIGroupPrefix, MasterAddr: masterURL.Host, MasterPrefix: api.Prefix, MasterResources: originResources.List(), KubernetesAddr: masterURL.Host, KubernetesPrefix: genericapiserver.DefaultLegacyAPIPrefix, KubernetesResources: k8sResources.List(), OAuthAuthorizeURI: OpenShiftOAuthAuthorizeURL(masterURL.String()), OAuthTokenURI: OpenShiftOAuthTokenURL(masterURL.String()), OAuthRedirectBase: c.Options.PublicURL, OAuthClientID: OpenShiftWebConsoleClientID, LogoutURI: c.Options.LogoutURL, LoggingURL: c.Options.LoggingPublicURL, MetricsURL: c.Options.MetricsPublicURL, LimitRequestOverrides: c.LimitRequestOverrides, } kVersionInfo := kversion.Get() oVersionInfo := oversion.Get() versionInfo := assets.WebConsoleVersion{ KubernetesVersion: kVersionInfo.GitVersion, OpenShiftVersion: oVersionInfo.GitVersion, } extensionProps := assets.WebConsoleExtensionProperties{ ExtensionProperties: extensionPropertyArray(c.Options.ExtensionProperties), } configPath := path.Join(publicURL.Path, "config.js") configHandler, err := assets.GeneratedConfigHandler(config, versionInfo, extensionProps) if err != nil { return nil, err } mux.Handle(configPath, assets.GzipHandler(configHandler)) // Extension scripts extScriptsPath := path.Join(publicURL.Path, "scripts/extensions.js") extScriptsHandler, err := assets.ExtensionScriptsHandler(c.Options.ExtensionScripts, c.Options.ExtensionDevelopment) if err != nil { return nil, err } mux.Handle(extScriptsPath, assets.GzipHandler(extScriptsHandler)) // Extension stylesheets extStylesheetsPath := path.Join(publicURL.Path, "styles/extensions.css") extStylesheetsHandler, err := assets.ExtensionStylesheetsHandler(c.Options.ExtensionStylesheets, c.Options.ExtensionDevelopment) if err != nil { return nil, err } mux.Handle(extStylesheetsPath, assets.GzipHandler(extStylesheetsHandler)) // Extension files for _, extConfig := range c.Options.Extensions { extBasePath := path.Join(publicURL.Path, "extensions", extConfig.Name) extPath := extBasePath + "/" extHandler := assets.AssetExtensionHandler(extConfig.SourceDirectory, extPath, extConfig.HTML5Mode) mux.Handle(extPath, http.StripPrefix(extBasePath, extHandler)) } return mux, nil }