Update ingress godeps
This commit is contained in:
parent
d43021b3f1
commit
28db8fb16d
1068 changed files with 461467 additions and 117300 deletions
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/clientcache.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/clientcache.go
generated
vendored
|
|
@ -76,19 +76,19 @@ func (c *ClientCache) ClientConfigForVersion(version *unversioned.GroupVersion)
|
|||
preferredGV = &versionCopy
|
||||
}
|
||||
|
||||
client.SetKubernetesDefaults(&config)
|
||||
negotiatedVersion, err := client.NegotiateVersion(c.defaultClient, &config, preferredGV, registered.EnabledVersions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.GroupVersion = negotiatedVersion
|
||||
client.SetKubernetesDefaults(&config)
|
||||
|
||||
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 the config we've just built.
|
||||
// `config.Version`, we should get the config we've just built.
|
||||
configCopy := config
|
||||
c.configs[*config.GroupVersion] = &configCopy
|
||||
|
||||
|
|
|
|||
236
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go
generated
vendored
236
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go
generated
vendored
|
|
@ -53,6 +53,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
|
|
@ -83,6 +85,9 @@ type Factory struct {
|
|||
// Returns interfaces for dealing with arbitrary runtime.Objects. If thirdPartyDiscovery is true, performs API calls
|
||||
// to discovery dynamic API objects registered by third parties.
|
||||
Object func(thirdPartyDiscovery bool) (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interfaces for dealing with arbitrary
|
||||
// runtime.Unstructured. This performs API calls to discover types.
|
||||
UnstructuredObject func() (meta.RESTMapper, runtime.ObjectTyper, error)
|
||||
// Returns interfaces for decoding objects - if toInternal is set, decoded objects will be converted
|
||||
// into their internal form (if possible). Eventually the internal form will be removed as an option,
|
||||
// and only versioned objects will be returned.
|
||||
|
|
@ -96,10 +101,12 @@ type Factory struct {
|
|||
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
||||
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a RESTClient for working with Unstructured objects.
|
||||
UnstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||
// Returns a Printer for formatting objects of the given type or an error.
|
||||
Printer func(mapping *meta.RESTMapping, noHeaders, withNamespace bool, wide bool, showAll bool, showLabels bool, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error)
|
||||
Printer func(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error)
|
||||
// Returns a Scaler for changing the size of the specified RESTMapping type or an error
|
||||
Scaler func(mapping *meta.RESTMapping) (kubectl.Scaler, error)
|
||||
// Returns a Reaper for gracefully shutting down resources.
|
||||
|
|
@ -158,13 +165,19 @@ const (
|
|||
RunPodV1GeneratorName = "run-pod/v1"
|
||||
ServiceV1GeneratorName = "service/v1"
|
||||
ServiceV2GeneratorName = "service/v2"
|
||||
ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
|
||||
ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
|
||||
ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
|
||||
ServiceAccountV1GeneratorName = "serviceaccount/v1"
|
||||
HorizontalPodAutoscalerV1Beta1GeneratorName = "horizontalpodautoscaler/v1beta1"
|
||||
HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"
|
||||
DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
|
||||
DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1"
|
||||
JobV1Beta1GeneratorName = "job/v1beta1"
|
||||
JobV1GeneratorName = "job/v1"
|
||||
ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1"
|
||||
NamespaceV1GeneratorName = "namespace/v1"
|
||||
ResourceQuotaV1GeneratorName = "resourcequotas/v1"
|
||||
SecretV1GeneratorName = "secret/v1"
|
||||
SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
|
||||
SecretForTLSV1GeneratorName = "secret-for-tls/v1"
|
||||
|
|
@ -178,12 +191,25 @@ func DefaultGenerators(cmdName string) map[string]kubectl.Generator {
|
|||
ServiceV1GeneratorName: kubectl.ServiceGeneratorV1{},
|
||||
ServiceV2GeneratorName: kubectl.ServiceGeneratorV2{},
|
||||
}
|
||||
generators["service-clusterip"] = map[string]kubectl.Generator{
|
||||
ServiceClusterIPGeneratorV1Name: kubectl.ServiceClusterIPGeneratorV1{},
|
||||
}
|
||||
generators["service-nodeport"] = map[string]kubectl.Generator{
|
||||
ServiceNodePortGeneratorV1Name: kubectl.ServiceNodePortGeneratorV1{},
|
||||
}
|
||||
generators["service-loadbalancer"] = map[string]kubectl.Generator{
|
||||
ServiceLoadBalancerGeneratorV1Name: kubectl.ServiceLoadBalancerGeneratorV1{},
|
||||
}
|
||||
generators["deployment"] = map[string]kubectl.Generator{
|
||||
DeploymentBasicV1Beta1GeneratorName: kubectl.DeploymentBasicGeneratorV1{},
|
||||
}
|
||||
generators["run"] = map[string]kubectl.Generator{
|
||||
RunV1GeneratorName: kubectl.BasicReplicationController{},
|
||||
RunPodV1GeneratorName: kubectl.BasicPod{},
|
||||
DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
|
||||
JobV1Beta1GeneratorName: kubectl.JobV1Beta1{},
|
||||
JobV1GeneratorName: kubectl.JobV1{},
|
||||
RunV1GeneratorName: kubectl.BasicReplicationController{},
|
||||
RunPodV1GeneratorName: kubectl.BasicPod{},
|
||||
DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
|
||||
JobV1Beta1GeneratorName: kubectl.JobV1Beta1{},
|
||||
JobV1GeneratorName: kubectl.JobV1{},
|
||||
ScheduledJobV2Alpha1GeneratorName: kubectl.ScheduledJobV2Alpha1{},
|
||||
}
|
||||
generators["autoscale"] = map[string]kubectl.Generator{
|
||||
HorizontalPodAutoscalerV1Beta1GeneratorName: kubectl.HorizontalPodAutoscalerV1Beta1{},
|
||||
|
|
@ -192,6 +218,11 @@ func DefaultGenerators(cmdName string) map[string]kubectl.Generator {
|
|||
generators["namespace"] = map[string]kubectl.Generator{
|
||||
NamespaceV1GeneratorName: kubectl.NamespaceGeneratorV1{},
|
||||
}
|
||||
|
||||
generators["quota"] = map[string]kubectl.Generator{
|
||||
ResourceQuotaV1GeneratorName: kubectl.ResourceQuotaGeneratorV1{},
|
||||
}
|
||||
|
||||
generators["secret"] = map[string]kubectl.Generator{
|
||||
SecretV1GeneratorName: kubectl.SecretGeneratorV1{},
|
||||
}
|
||||
|
|
@ -310,29 +341,66 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
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
|
||||
// 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,
|
||||
ResourcePriority: []unversioned.GroupVersionResource{
|
||||
{Group: api.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
|
||||
{Group: autoscaling.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
|
||||
{Group: extensions.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
|
||||
{Group: federation.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
|
||||
},
|
||||
KindPriority: []unversioned.GroupVersionKind{
|
||||
{Group: api.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
|
||||
{Group: autoscaling.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
|
||||
{Group: extensions.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
|
||||
{Group: federation.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
|
||||
},
|
||||
}
|
||||
// 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
|
||||
},
|
||||
UnstructuredObject: func() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
cfg, err := clients.ClientConfigForVersion(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
groupResources, err := discovery.GetAPIGroupResources(dc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Register unknown APIs as third party for now to make
|
||||
// validation happy. TODO perhaps make a dynamic schema
|
||||
// validator to avoid this.
|
||||
for _, group := range groupResources {
|
||||
for _, version := range group.Group.Versions {
|
||||
gv := unversioned.GroupVersion{Group: group.Group.Name, Version: version.Version}
|
||||
if !registered.IsRegisteredVersion(gv) {
|
||||
registered.AddThirdPartyAPIGroupVersions(gv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructured)
|
||||
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
|
||||
return kubectl.ShortcutExpander{RESTMapper: mapper}, typer, nil
|
||||
},
|
||||
Client: func() (*client.Client, error) {
|
||||
return clients.ClientForVersion(nil)
|
||||
},
|
||||
|
|
@ -340,49 +408,46 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
return clients.ClientConfigForVersion(nil)
|
||||
},
|
||||
ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
gvk := mapping.GroupVersionKind
|
||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||
c, err := clients.ClientForVersion(&mappingVersion)
|
||||
cfg, err := clientConfig.ClientConfig()
|
||||
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 policy.GroupName:
|
||||
return c.PolicyClient.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
|
||||
case federation.GroupName:
|
||||
return clients.FederationClientForVersion(&mappingVersion)
|
||||
case rbac.GroupName:
|
||||
return c.RbacClient.RESTClient, nil
|
||||
case certificates.GroupName:
|
||||
return c.CertificatesClient.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.NegotiatedSerializer = thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, gvk.Kind, gv, gv)
|
||||
return restclient.RESTClientFor(cfg)
|
||||
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)
|
||||
},
|
||||
UnstructuredClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
cfg, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := restclient.SetKubernetesDefaults(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.APIPath = "/apis"
|
||||
if mapping.GroupVersionKind.Group == api.GroupName {
|
||||
cfg.APIPath = "/api"
|
||||
}
|
||||
gv := mapping.GroupVersionKind.GroupVersion()
|
||||
cfg.ContentConfig = dynamic.ContentConfig()
|
||||
cfg.GroupVersion = &gv
|
||||
return restclient.RESTClientFor(cfg)
|
||||
},
|
||||
Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) {
|
||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||
|
|
@ -417,8 +482,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
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
|
||||
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)
|
||||
|
|
@ -1017,7 +1082,7 @@ func getSchemaAndValidate(c schemaClient, data []byte, prefix, groupVersion, cac
|
|||
}
|
||||
err = schema.ValidateBytes(data)
|
||||
if _, ok := err.(validation.TypeNotFoundError); ok && !firstSeen {
|
||||
// As a temporay hack, kubectl would re-get the schema if validation
|
||||
// As a temporary hack, kubectl would re-get the schema if validation
|
||||
// fails for type not found reason.
|
||||
// TODO: runtime-config settings needs to make into the file's name
|
||||
schemaData, err = downloadSchemaAndStore(c, cacheDir, fullDir, cacheFile, prefix, groupVersion)
|
||||
|
|
@ -1059,32 +1124,28 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
|
|||
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 {
|
||||
switch gvk.Group {
|
||||
case 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 {
|
||||
case 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 {
|
||||
case apps.GroupName:
|
||||
if c.c.AppsClient == nil {
|
||||
return errors.New("unable to validate: no autoscaling client")
|
||||
return errors.New("unable to validate: no apps client")
|
||||
}
|
||||
return getSchemaAndValidate(c.c.AppsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c)
|
||||
}
|
||||
|
||||
if gvk.Group == batch.GroupName {
|
||||
case 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 {
|
||||
case rbac.GroupName:
|
||||
if c.c.RbacClient == nil {
|
||||
return errors.New("unable to validate: no rbac client")
|
||||
}
|
||||
|
|
@ -1094,19 +1155,18 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
|
|||
// Don't attempt to validate third party objects
|
||||
return nil
|
||||
}
|
||||
if gvk.Group == extensions.GroupName {
|
||||
switch gvk.Group {
|
||||
case 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 {
|
||||
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)
|
||||
}
|
||||
if gvk.Group == certificates.GroupName {
|
||||
case certificates.GroupName:
|
||||
if c.c.CertificatesClient == nil {
|
||||
return errors.New("unable to validate: no certificates client")
|
||||
}
|
||||
|
|
@ -1117,7 +1177,7 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
|
|||
|
||||
// DefaultClientConfig creates a clientcmd.ClientConfig with the following hierarchy:
|
||||
// 1. Use the kubeconfig builder. The number of merges and overrides here gets a little crazy. Stay with me.
|
||||
// 1. Merge together the kubeconfig itself. This is done with the following hierarchy rules:
|
||||
// 1. Merge the kubeconfig itself. This is done with the following hierarchy rules:
|
||||
// 1. CommandLineLocation - this parsed from the command line, so it must be late bound. If you specify this,
|
||||
// then no other kubeconfig files are merged. This file must exist.
|
||||
// 2. If $KUBECONFIG is set, then it is treated as a list of files that should be merged.
|
||||
|
|
@ -1205,14 +1265,16 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version.IsEmpty() {
|
||||
if version.Empty() && mapping != nil {
|
||||
version = mapping.GroupVersionKind.GroupVersion()
|
||||
}
|
||||
if version.IsEmpty() {
|
||||
if version.Empty() {
|
||||
return nil, fmt.Errorf("you must specify an output-version when using this output format")
|
||||
}
|
||||
|
||||
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
||||
if mapping != nil {
|
||||
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
||||
}
|
||||
|
||||
} else {
|
||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||
|
|
@ -1220,7 +1282,15 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
|
|||
if err != nil {
|
||||
columnLabel = []string{}
|
||||
}
|
||||
printer, err = f.Printer(mapping, GetFlagBool(cmd, "no-headers"), withNamespace, GetWideFlag(cmd), GetFlagBool(cmd, "show-all"), GetFlagBool(cmd, "show-labels"), isWatch(cmd), columnLabel)
|
||||
printer, err = f.Printer(mapping, kubectl.PrintOptions{
|
||||
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
||||
WithNamespace: withNamespace,
|
||||
Wide: GetWideFlag(cmd),
|
||||
ShowAll: GetFlagBool(cmd, "show-all"),
|
||||
ShowLabels: GetFlagBool(cmd, "show-labels"),
|
||||
AbsoluteTimestamps: isWatch(cmd),
|
||||
ColumnLabels: columnLabel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
143
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/helpers.go
generated
vendored
143
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/helpers.go
generated
vendored
|
|
@ -19,6 +19,7 @@ package util
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -27,7 +28,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
kerrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
|
|
@ -38,6 +39,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||
|
||||
"github.com/evanphx/json-patch"
|
||||
|
|
@ -48,6 +51,7 @@ import (
|
|||
|
||||
const (
|
||||
ApplyAnnotationsFlag = "save-config"
|
||||
DefaultErrorExitCode = 1
|
||||
)
|
||||
|
||||
type debugError interface {
|
||||
|
|
@ -59,10 +63,10 @@ type debugError interface {
|
|||
// souce is the filename or URL to the template file(*.json or *.yaml), or stdin to use to handle the resource.
|
||||
func AddSourceToErr(verb string, source string, err error) error {
|
||||
if source != "" {
|
||||
if statusError, ok := err.(errors.APIStatus); ok {
|
||||
if statusError, ok := err.(kerrors.APIStatus); ok {
|
||||
status := statusError.Status()
|
||||
status.Message = fmt.Sprintf("error when %s %q: %v", verb, source, status.Message)
|
||||
return &errors.StatusError{ErrStatus: status}
|
||||
return &kerrors.StatusError{ErrStatus: status}
|
||||
}
|
||||
return fmt.Errorf("error when %s %q: %v", verb, source, err)
|
||||
}
|
||||
|
|
@ -72,9 +76,9 @@ func AddSourceToErr(verb string, source string, err error) error {
|
|||
var fatalErrHandler = fatal
|
||||
|
||||
// BehaviorOnFatal allows you to override the default behavior when a fatal
|
||||
// error occurs, which is call os.Exit(1). You can pass 'panic' as a function
|
||||
// error occurs, which is to call os.Exit(code). You can pass 'panic' as a function
|
||||
// here if you prefer the panic() over os.Exit(1).
|
||||
func BehaviorOnFatal(f func(string)) {
|
||||
func BehaviorOnFatal(f func(string, int)) {
|
||||
fatalErrHandler = f
|
||||
}
|
||||
|
||||
|
|
@ -84,19 +88,21 @@ func DefaultBehaviorOnFatal() {
|
|||
fatalErrHandler = fatal
|
||||
}
|
||||
|
||||
// fatal prints the message and then exits. If V(2) or greater, glog.Fatal
|
||||
// fatal prints the message if set and then exits. If V(2) or greater, glog.Fatal
|
||||
// is invoked for extended information.
|
||||
func fatal(msg string) {
|
||||
// add newline if needed
|
||||
if !strings.HasSuffix(msg, "\n") {
|
||||
msg += "\n"
|
||||
}
|
||||
func fatal(msg string, code int) {
|
||||
if len(msg) > 0 {
|
||||
// add newline if needed
|
||||
if !strings.HasSuffix(msg, "\n") {
|
||||
msg += "\n"
|
||||
}
|
||||
|
||||
if glog.V(2) {
|
||||
glog.FatalDepth(2, msg)
|
||||
if glog.V(2) {
|
||||
glog.FatalDepth(2, msg)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, msg)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, msg)
|
||||
os.Exit(1)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// CheckErr prints a user friendly error to STDERR and exits with a non-zero
|
||||
|
|
@ -113,56 +119,65 @@ func checkErrWithPrefix(prefix string, err error) {
|
|||
checkErr(prefix, err, fatalErrHandler)
|
||||
}
|
||||
|
||||
func checkErr(pref string, err error, handleErr func(string)) {
|
||||
if err == nil {
|
||||
// checkErr formats a given error as a string and calls the passed handleErr
|
||||
// func with that string and an kubectl exit code.
|
||||
func checkErr(prefix string, err error, handleErr func(string, int)) {
|
||||
switch {
|
||||
case err == nil:
|
||||
return
|
||||
}
|
||||
|
||||
if errors.IsInvalid(err) {
|
||||
details := err.(*errors.StatusError).Status().Details
|
||||
prefix := fmt.Sprintf("%sThe %s %q is invalid.\n", pref, details.Kind, details.Name)
|
||||
errs := statusCausesToAggrError(details.Causes)
|
||||
handleErr(MultilineError(prefix, errs))
|
||||
}
|
||||
|
||||
if meta.IsNoResourceMatchError(err) {
|
||||
noMatch := err.(*meta.NoResourceMatchError)
|
||||
|
||||
switch {
|
||||
case len(noMatch.PartialResource.Group) > 0 && len(noMatch.PartialResource.Version) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q and version %q", pref, noMatch.PartialResource.Resource, noMatch.PartialResource.Group, noMatch.PartialResource.Version))
|
||||
case len(noMatch.PartialResource.Group) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q", pref, noMatch.PartialResource.Resource, noMatch.PartialResource.Group))
|
||||
case len(noMatch.PartialResource.Version) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in version %q", pref, noMatch.PartialResource.Resource, noMatch.PartialResource.Version))
|
||||
default:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q", pref, noMatch.PartialResource.Resource))
|
||||
case kerrors.IsInvalid(err):
|
||||
details := err.(*kerrors.StatusError).Status().Details
|
||||
s := fmt.Sprintf("%sThe %s %q is invalid", prefix, details.Kind, details.Name)
|
||||
if len(details.Causes) > 0 {
|
||||
errs := statusCausesToAggrError(details.Causes)
|
||||
handleErr(MultilineError(s+": ", errs), DefaultErrorExitCode)
|
||||
} else {
|
||||
handleErr(s, DefaultErrorExitCode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// handle multiline errors
|
||||
if clientcmd.IsConfigurationInvalid(err) {
|
||||
handleErr(MultilineError(fmt.Sprintf("%sError in configuration: ", pref), err))
|
||||
}
|
||||
if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) > 0 {
|
||||
handleErr(MultipleErrors(pref, agg.Errors()))
|
||||
}
|
||||
|
||||
msg, ok := StandardErrorMessage(err)
|
||||
if !ok {
|
||||
msg = err.Error()
|
||||
if !strings.HasPrefix(msg, "error: ") {
|
||||
msg = fmt.Sprintf("error: %s", msg)
|
||||
case clientcmd.IsConfigurationInvalid(err):
|
||||
handleErr(MultilineError(fmt.Sprintf("%sError in configuration: ", prefix), err), DefaultErrorExitCode)
|
||||
default:
|
||||
switch err := err.(type) {
|
||||
case *meta.NoResourceMatchError:
|
||||
switch {
|
||||
case len(err.PartialResource.Group) > 0 && len(err.PartialResource.Version) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q and version %q", prefix, err.PartialResource.Resource, err.PartialResource.Group, err.PartialResource.Version), DefaultErrorExitCode)
|
||||
case len(err.PartialResource.Group) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q", prefix, err.PartialResource.Resource, err.PartialResource.Group), DefaultErrorExitCode)
|
||||
case len(err.PartialResource.Version) > 0:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in version %q", prefix, err.PartialResource.Resource, err.PartialResource.Version), DefaultErrorExitCode)
|
||||
default:
|
||||
handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q", prefix, err.PartialResource.Resource), DefaultErrorExitCode)
|
||||
}
|
||||
case utilerrors.Aggregate:
|
||||
handleErr(MultipleErrors(prefix, err.Errors()), DefaultErrorExitCode)
|
||||
case utilexec.ExitError:
|
||||
// do not print anything, only terminate with given error
|
||||
handleErr("", err.ExitStatus())
|
||||
default: // for any other error type
|
||||
msg, ok := StandardErrorMessage(err)
|
||||
if !ok {
|
||||
msg = err.Error()
|
||||
if !strings.HasPrefix(msg, "error: ") {
|
||||
msg = fmt.Sprintf("error: %s", msg)
|
||||
}
|
||||
}
|
||||
handleErr(msg, DefaultErrorExitCode)
|
||||
}
|
||||
}
|
||||
handleErr(fmt.Sprintf("%s%s", pref, msg))
|
||||
}
|
||||
|
||||
func statusCausesToAggrError(scs []unversioned.StatusCause) utilerrors.Aggregate {
|
||||
errs := make([]error, len(scs))
|
||||
for i, sc := range scs {
|
||||
errs[i] = fmt.Errorf("%s: %s", sc.Field, sc.Message)
|
||||
errs := make([]error, 0, len(scs))
|
||||
errorMsgs := sets.NewString()
|
||||
for _, sc := range scs {
|
||||
// check for duplicate error messages and skip them
|
||||
msg := fmt.Sprintf("%s: %s", sc.Field, sc.Message)
|
||||
if errorMsgs.Has(msg) {
|
||||
continue
|
||||
}
|
||||
errorMsgs.Insert(msg)
|
||||
errs = append(errs, errors.New(msg))
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
|
@ -177,7 +192,7 @@ func StandardErrorMessage(err error) (string, bool) {
|
|||
if debugErr, ok := err.(debugError); ok {
|
||||
glog.V(4).Infof(debugErr.DebugError())
|
||||
}
|
||||
status, isStatus := err.(errors.APIStatus)
|
||||
status, isStatus := err.(kerrors.APIStatus)
|
||||
switch {
|
||||
case isStatus:
|
||||
switch s := status.Status(); {
|
||||
|
|
@ -186,7 +201,7 @@ func StandardErrorMessage(err error) (string, bool) {
|
|||
default:
|
||||
return fmt.Sprintf("Error from server: %s", err.Error()), true
|
||||
}
|
||||
case errors.IsUnexpectedObjectError(err):
|
||||
case kerrors.IsUnexpectedObjectError(err):
|
||||
return fmt.Sprintf("Server returned an unexpected response: %s", err.Error()), true
|
||||
}
|
||||
switch t := err.(type) {
|
||||
|
|
@ -365,7 +380,7 @@ func ReadConfigDataFromReader(reader io.Reader, source string) ([]byte, error) {
|
|||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf(`Read from %s but no data found`, source)
|
||||
return nil, fmt.Errorf("Read from %s but no data found", source)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
|
|
@ -437,7 +452,7 @@ func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtim
|
|||
|
||||
// AddCmdRecordFlag adds --record flag to command
|
||||
func AddRecordFlag(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation.")
|
||||
cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.")
|
||||
}
|
||||
|
||||
func GetRecordFlag(cmd *cobra.Command) bool {
|
||||
|
|
@ -491,7 +506,7 @@ func ContainsChangeCause(info *resource.Info) bool {
|
|||
|
||||
// ShouldRecord checks if we should record current change cause
|
||||
func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
|
||||
return GetRecordFlag(cmd) || ContainsChangeCause(info)
|
||||
return GetRecordFlag(cmd) || (ContainsChangeCause(info) && !cmd.Flags().Changed("record"))
|
||||
}
|
||||
|
||||
// GetThirdPartyGroupVersions returns the thirdparty "group/versions"s and
|
||||
|
|
@ -505,7 +520,7 @@ func GetThirdPartyGroupVersions(discovery discovery.DiscoveryInterface) ([]unver
|
|||
groupList, err := discovery.ServerGroups()
|
||||
if err != nil {
|
||||
// On forbidden or not found, just return empty lists.
|
||||
if errors.IsForbidden(err) || errors.IsNotFound(err) {
|
||||
if kerrors.IsForbidden(err) || kerrors.IsNotFound(err) {
|
||||
return result, gvks, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/printing.go
generated
vendored
2
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/printing.go
generated
vendored
|
|
@ -47,7 +47,7 @@ func AddOutputFlagsForMutation(cmd *cobra.Command) {
|
|||
|
||||
// AddOutputFlags adds output related flags to a command.
|
||||
func AddOutputFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
|
||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
|
||||
}
|
||||
|
||||
// AddNoHeadersFlags adds no-headers flags to a command.
|
||||
|
|
|
|||
6
vendor/k8s.io/kubernetes/pkg/kubectl/custom_column_printer.go
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/kubectl/custom_column_printer.go
generated
vendored
|
|
@ -105,7 +105,7 @@ func splitOnWhitespace(line string) []string {
|
|||
|
||||
// NewCustomColumnsPrinterFromTemplate creates a custom columns printer from a template stream. The template is expected
|
||||
// to consist of two lines, whitespace separated. The first line is the header line, the second line is the jsonpath field spec
|
||||
// For example the template below:
|
||||
// For example, the template below:
|
||||
// NAME API_VERSION
|
||||
// {metadata.name} {apiVersion}
|
||||
func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runtime.Decoder) (*CustomColumnsPrinter, error) {
|
||||
|
|
@ -155,6 +155,10 @@ type CustomColumnsPrinter struct {
|
|||
NoHeaders bool
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
|
||||
|
||||
|
|
|
|||
107
vendor/k8s.io/kubernetes/pkg/kubectl/deployment.go
generated
vendored
Normal file
107
vendor/k8s.io/kubernetes/pkg/kubectl/deployment.go
generated
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeploymentGeneratorV1 supports stable generation of a deployment
|
||||
type DeploymentBasicGeneratorV1 struct {
|
||||
Name string
|
||||
Images []string
|
||||
}
|
||||
|
||||
// Ensure it supports the generator pattern that uses parameters specified during construction
|
||||
var _ StructuredGenerator = &DeploymentBasicGeneratorV1{}
|
||||
|
||||
func (DeploymentBasicGeneratorV1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"name", true},
|
||||
{"image", true},
|
||||
}
|
||||
}
|
||||
|
||||
func (s DeploymentBasicGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
|
||||
err := ValidateParams(s.ParamNames(), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name, isString := params["name"].(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf("expected string, saw %v for 'name'", name)
|
||||
}
|
||||
imageStrings, isArray := params["image"].([]string)
|
||||
if !isArray {
|
||||
return nil, fmt.Errorf("expected []string, found :%v", imageStrings)
|
||||
}
|
||||
delegate := &DeploymentBasicGeneratorV1{Name: name, Images: imageStrings}
|
||||
return delegate.StructuredGenerate()
|
||||
}
|
||||
|
||||
// StructuredGenerate outputs a deployment object using the configured fields
|
||||
func (s *DeploymentBasicGeneratorV1) StructuredGenerate() (runtime.Object, error) {
|
||||
if err := s.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podSpec := api.PodSpec{Containers: []api.Container{}}
|
||||
for _, imageString := range s.Images {
|
||||
imageSplit := strings.Split(imageString, "/")
|
||||
name := imageSplit[len(imageSplit)-1]
|
||||
podSpec.Containers = append(podSpec.Containers, api.Container{Name: name, Image: imageString})
|
||||
}
|
||||
|
||||
// setup default label and selector
|
||||
labels := map[string]string{}
|
||||
labels["app"] = s.Name
|
||||
selector := unversioned.LabelSelector{MatchLabels: labels}
|
||||
deployment := extensions.Deployment{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: s.Name,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: 1,
|
||||
Selector: &selector,
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: podSpec,
|
||||
},
|
||||
},
|
||||
}
|
||||
return &deployment, nil
|
||||
}
|
||||
|
||||
// validate validates required fields are set to support structured generation
|
||||
func (s *DeploymentBasicGeneratorV1) validate() error {
|
||||
if len(s.Name) == 0 {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
if len(s.Images) == 0 {
|
||||
return fmt.Errorf("at least one image must be specified")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
288
vendor/k8s.io/kubernetes/pkg/kubectl/describe.go
generated
vendored
288
vendor/k8s.io/kubernetes/pkg/kubectl/describe.go
generated
vendored
|
|
@ -28,7 +28,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/federation/apis/federation"
|
||||
fed_clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
|
@ -38,6 +37,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
|
|
@ -48,8 +48,11 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Describer generates output for the named resource or an error
|
||||
|
|
@ -101,16 +104,18 @@ func describerMap(c *client.Client) map[unversioned.GroupKind]Describer {
|
|||
api.Kind("Endpoints"): &EndpointsDescriber{c},
|
||||
api.Kind("ConfigMap"): &ConfigMapDescriber{c},
|
||||
|
||||
extensions.Kind("ReplicaSet"): &ReplicaSetDescriber{c},
|
||||
extensions.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
|
||||
extensions.Kind("NetworkPolicy"): &NetworkPolicyDescriber{c},
|
||||
autoscaling.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
|
||||
extensions.Kind("DaemonSet"): &DaemonSetDescriber{c},
|
||||
extensions.Kind("Deployment"): &DeploymentDescriber{adapter.FromUnversionedClient(c)},
|
||||
extensions.Kind("Job"): &JobDescriber{c},
|
||||
batch.Kind("Job"): &JobDescriber{c},
|
||||
apps.Kind("PetSet"): &PetSetDescriber{c},
|
||||
extensions.Kind("Ingress"): &IngressDescriber{c},
|
||||
extensions.Kind("ReplicaSet"): &ReplicaSetDescriber{c},
|
||||
extensions.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
|
||||
extensions.Kind("NetworkPolicy"): &NetworkPolicyDescriber{c},
|
||||
autoscaling.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
|
||||
extensions.Kind("DaemonSet"): &DaemonSetDescriber{c},
|
||||
extensions.Kind("Deployment"): &DeploymentDescriber{adapter.FromUnversionedClient(c)},
|
||||
extensions.Kind("Job"): &JobDescriber{c},
|
||||
extensions.Kind("Ingress"): &IngressDescriber{c},
|
||||
batch.Kind("Job"): &JobDescriber{c},
|
||||
batch.Kind("ScheduledJob"): &ScheduledJobDescriber{adapter.FromUnversionedClient(c)},
|
||||
apps.Kind("PetSet"): &PetSetDescriber{c},
|
||||
certificates.Kind("CertificateSigningRequest"): &CertificateSigningRequestDescriber{c},
|
||||
}
|
||||
|
||||
return m
|
||||
|
|
@ -541,6 +546,7 @@ func describePod(pod *api.Pod, events *api.EventList) (string, error) {
|
|||
}
|
||||
describeVolumes(pod.Spec.Volumes, out, "")
|
||||
fmt.Fprintf(out, "QoS Class:\t%s\n", qos.GetPodQOS(pod))
|
||||
printTolerationsInAnnotationMultiline(out, "Tolerations", pod.Annotations)
|
||||
if events != nil {
|
||||
DescribeEvents(events, out)
|
||||
}
|
||||
|
|
@ -598,8 +604,12 @@ func describeVolumes(volumes []api.Volume, out io.Writer, space string) {
|
|||
printPersistentVolumeClaimVolumeSource(volume.VolumeSource.PersistentVolumeClaim, out)
|
||||
case volume.VolumeSource.RBD != nil:
|
||||
printRBDVolumeSource(volume.VolumeSource.RBD, out)
|
||||
case volume.VolumeSource.Quobyte != nil:
|
||||
printQuobyteVolumeSource(volume.VolumeSource.Quobyte, out)
|
||||
case volume.VolumeSource.DownwardAPI != nil:
|
||||
printDownwardAPIVolumeSource(volume.VolumeSource.DownwardAPI, out)
|
||||
case volume.VolumeSource.AzureDisk != nil:
|
||||
printAzureDiskVolumeSource(volume.VolumeSource.AzureDisk, out)
|
||||
default:
|
||||
fmt.Fprintf(out, " <unknown>\n")
|
||||
}
|
||||
|
|
@ -659,6 +669,14 @@ func printNFSVolumeSource(nfs *api.NFSVolumeSource, out io.Writer) {
|
|||
nfs.Server, nfs.Path, nfs.ReadOnly)
|
||||
}
|
||||
|
||||
func printQuobyteVolumeSource(quobyte *api.QuobyteVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tQuobyte (a Quobyte mount on the host that shares a pod's lifetime)\n"+
|
||||
" Registry:\t%v\n"+
|
||||
" Volume:\t%v\n"+
|
||||
" ReadOnly:\t%v\n",
|
||||
quobyte.Registry, quobyte.Volume, quobyte.ReadOnly)
|
||||
}
|
||||
|
||||
func printISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
|
||||
" TargetPortal:\t%v\n"+
|
||||
|
|
@ -710,6 +728,16 @@ func printDownwardAPIVolumeSource(d *api.DownwardAPIVolumeSource, out io.Writer)
|
|||
}
|
||||
}
|
||||
|
||||
func printAzureDiskVolumeSource(d *api.AzureDiskVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tAzureDisk (an Azure Data Disk mount on the host and bind mount to the pod)\n"+
|
||||
" DiskName:\t%v\n"+
|
||||
" DiskURI:\t%v\n"+
|
||||
" FSType:\t%v\n"+
|
||||
" CachingMode:\t%v\n"+
|
||||
" ReadOnly:\t%v\n",
|
||||
d.DiskName, d.DataDiskURI, *d.FSType, *d.CachingMode, *d.ReadOnly)
|
||||
}
|
||||
|
||||
type PersistentVolumeDescriber struct {
|
||||
client.Interface
|
||||
}
|
||||
|
|
@ -759,6 +787,8 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSe
|
|||
printGlusterfsVolumeSource(pv.Spec.Glusterfs, out)
|
||||
case pv.Spec.RBD != nil:
|
||||
printRBDVolumeSource(pv.Spec.RBD, out)
|
||||
case pv.Spec.Quobyte != nil:
|
||||
printQuobyteVolumeSource(pv.Spec.Quobyte, out)
|
||||
}
|
||||
|
||||
if events != nil {
|
||||
|
|
@ -931,7 +961,11 @@ func describeContainers(label string, containers []api.Container, containerStatu
|
|||
if err != nil {
|
||||
valueFrom = ""
|
||||
}
|
||||
fmt.Fprintf(out, " %s:\t%s (%s)\n", e.Name, valueFrom, e.ValueFrom.ResourceFieldRef.Resource)
|
||||
resource := e.ValueFrom.ResourceFieldRef.Resource
|
||||
if valueFrom == "0" && (resource == "limits.cpu" || resource == "limits.memory") {
|
||||
valueFrom = "node allocatable"
|
||||
}
|
||||
fmt.Fprintf(out, " %s:\t%s (%s)\n", e.Name, valueFrom, resource)
|
||||
case e.ValueFrom.SecretKeyRef != nil:
|
||||
fmt.Fprintf(out, " %s:\t<set to the key '%s' in secret '%s'>\n", e.Name, e.ValueFrom.SecretKeyRef.Key, e.ValueFrom.SecretKeyRef.Name)
|
||||
case e.ValueFrom.ConfigMapKeyRef != nil:
|
||||
|
|
@ -1019,6 +1053,14 @@ func describeStatus(stateName string, state api.ContainerState, out io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
func printBoolPtr(value *bool) string {
|
||||
if value != nil {
|
||||
return printBool(*value)
|
||||
}
|
||||
|
||||
return "<unset>"
|
||||
}
|
||||
|
||||
func printBool(value bool) string {
|
||||
if value {
|
||||
return "True"
|
||||
|
|
@ -1148,18 +1190,18 @@ func describeReplicaSet(rs *extensions.ReplicaSet, events *api.EventList, runnin
|
|||
|
||||
// JobDescriber generates information about a job and the pods it has created.
|
||||
type JobDescriber struct {
|
||||
client *client.Client
|
||||
client.Interface
|
||||
}
|
||||
|
||||
func (d *JobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
job, err := d.client.Extensions().Jobs(namespace).Get(name)
|
||||
job, err := d.Batch().Jobs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var events *api.EventList
|
||||
if describerSettings.ShowEvents {
|
||||
events, _ = d.client.Events(namespace).Search(job)
|
||||
events, _ = d.Events(namespace).Search(job)
|
||||
}
|
||||
|
||||
return describeJob(job, events)
|
||||
|
|
@ -1194,6 +1236,92 @@ func describeJob(job *batch.Job, events *api.EventList) (string, error) {
|
|||
})
|
||||
}
|
||||
|
||||
// ScheduledJobDescriber generates information about a scheduled job and the jobs it has created.
|
||||
type ScheduledJobDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ScheduledJobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
scheduledJob, err := d.Batch().ScheduledJobs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var events *api.EventList
|
||||
if describerSettings.ShowEvents {
|
||||
events, _ = d.Core().Events(namespace).Search(scheduledJob)
|
||||
}
|
||||
|
||||
return describeScheduledJob(scheduledJob, events)
|
||||
}
|
||||
|
||||
func describeScheduledJob(scheduledJob *batch.ScheduledJob, events *api.EventList) (string, error) {
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", scheduledJob.Name)
|
||||
fmt.Fprintf(out, "Namespace:\t%s\n", scheduledJob.Namespace)
|
||||
fmt.Fprintf(out, "Schedule:\t%s\n", scheduledJob.Spec.Schedule)
|
||||
fmt.Fprintf(out, "Concurrency Policy:\t%s\n", scheduledJob.Spec.ConcurrencyPolicy)
|
||||
fmt.Fprintf(out, "Suspend:\t%s\n", printBoolPtr(scheduledJob.Spec.Suspend))
|
||||
if scheduledJob.Spec.StartingDeadlineSeconds != nil {
|
||||
fmt.Fprintf(out, "Starting Deadline Seconds:\t%ds\n", *scheduledJob.Spec.StartingDeadlineSeconds)
|
||||
} else {
|
||||
fmt.Fprintf(out, "Starting Deadline Seconds:\t<unset>\n")
|
||||
}
|
||||
describeJobTemplate(scheduledJob.Spec.JobTemplate, out)
|
||||
printLabelsMultiline(out, "Labels", scheduledJob.Labels)
|
||||
if scheduledJob.Status.LastScheduleTime != nil {
|
||||
fmt.Fprintf(out, "Last Schedule Time:\t%s\n", scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z))
|
||||
} else {
|
||||
fmt.Fprintf(out, "Last Schedule Time:\t<unset>\n")
|
||||
}
|
||||
printActiveJobs(out, "Active Jobs", scheduledJob.Status.Active)
|
||||
if events != nil {
|
||||
DescribeEvents(events, out)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func describeJobTemplate(jobTemplate batch.JobTemplateSpec, out io.Writer) {
|
||||
fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&jobTemplate.Spec.Template.Spec))
|
||||
if jobTemplate.Spec.Selector != nil {
|
||||
selector, _ := unversioned.LabelSelectorAsSelector(jobTemplate.Spec.Selector)
|
||||
fmt.Fprintf(out, "Selector:\t%s\n", selector)
|
||||
} else {
|
||||
fmt.Fprintf(out, "Selector:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.Parallelism != nil {
|
||||
fmt.Fprintf(out, "Parallelism:\t%d\n", *jobTemplate.Spec.Parallelism)
|
||||
} else {
|
||||
fmt.Fprintf(out, "Parallelism:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.Completions != nil {
|
||||
fmt.Fprintf(out, "Completions:\t%d\n", *jobTemplate.Spec.Completions)
|
||||
} else {
|
||||
fmt.Fprintf(out, "Completions:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.ActiveDeadlineSeconds != nil {
|
||||
fmt.Fprintf(out, "Active Deadline Seconds:\t%ds\n", *jobTemplate.Spec.ActiveDeadlineSeconds)
|
||||
}
|
||||
describeVolumes(jobTemplate.Spec.Template.Spec.Volumes, out, "")
|
||||
}
|
||||
|
||||
func printActiveJobs(out io.Writer, title string, jobs []api.ObjectReference) {
|
||||
fmt.Fprintf(out, "%s:\t", title)
|
||||
if len(jobs) == 0 {
|
||||
fmt.Fprintln(out, "<none>")
|
||||
return
|
||||
}
|
||||
|
||||
for i, job := range jobs {
|
||||
if i != 0 {
|
||||
fmt.Fprint(out, ", ")
|
||||
}
|
||||
fmt.Fprintf(out, "%s", job.Name)
|
||||
}
|
||||
fmt.Fprintln(out, "")
|
||||
}
|
||||
|
||||
// DaemonSetDescriber generates information about a daemon set and the pods it has created.
|
||||
type DaemonSetDescriber struct {
|
||||
client.Interface
|
||||
|
|
@ -1446,6 +1574,12 @@ func describeService(service *api.Service, endpoints *api.Endpoints, events *api
|
|||
fmt.Fprintf(out, "Selector:\t%s\n", labels.FormatLabels(service.Spec.Selector))
|
||||
fmt.Fprintf(out, "Type:\t%s\n", service.Spec.Type)
|
||||
fmt.Fprintf(out, "IP:\t%s\n", service.Spec.ClusterIP)
|
||||
if len(service.Spec.ExternalIPs) > 0 {
|
||||
fmt.Fprintf(out, "External IPs:\t%v\n", strings.Join(service.Spec.ExternalIPs, ","))
|
||||
}
|
||||
if service.Spec.ExternalName != "" {
|
||||
fmt.Fprintf(out, "External Name:\t%s\n", service.Spec.ExternalName)
|
||||
}
|
||||
if len(service.Status.LoadBalancer.Ingress) > 0 {
|
||||
list := buildIngressString(service.Status.LoadBalancer.Ingress)
|
||||
fmt.Fprintf(out, "LoadBalancer Ingress:\t%s\n", list)
|
||||
|
|
@ -1787,6 +1921,74 @@ func (p *PetSetDescriber) Describe(namespace, name string, describerSettings Des
|
|||
})
|
||||
}
|
||||
|
||||
type CertificateSigningRequestDescriber struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
csr, err := p.client.Certificates().CertificateSigningRequests().Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cr, err := utilcertificates.ParseCertificateRequestObject(csr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error parsing CSR: %v", err)
|
||||
}
|
||||
status, err := extractCSRStatus(csr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
printListHelper := func(out io.Writer, prefix, name string, values []string) {
|
||||
if len(values) == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(out, prefix+name+":\t")
|
||||
fmt.Fprintf(out, strings.Join(values, "\n"+prefix+"\t"))
|
||||
fmt.Fprintf(out, "\n")
|
||||
}
|
||||
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", csr.Name)
|
||||
fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(csr.Labels))
|
||||
fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(csr.Annotations))
|
||||
fmt.Fprintf(out, "CreationTimestamp:\t%s\n", csr.CreationTimestamp.Time.Format(time.RFC1123Z))
|
||||
fmt.Fprintf(out, "Requesting User:\t%s\n", csr.Spec.Username)
|
||||
fmt.Fprintf(out, "Status:\t%s\n", status)
|
||||
|
||||
fmt.Fprintf(out, "Subject:\n")
|
||||
fmt.Fprintf(out, "\tCommon Name:\t%s\n", cr.Subject.CommonName)
|
||||
fmt.Fprintf(out, "\tSerial Number:\t%s\n", cr.Subject.SerialNumber)
|
||||
printListHelper(out, "\t", "Organization", cr.Subject.Organization)
|
||||
printListHelper(out, "\t", "Organizational Unit", cr.Subject.OrganizationalUnit)
|
||||
printListHelper(out, "\t", "Country", cr.Subject.Country)
|
||||
printListHelper(out, "\t", "Locality", cr.Subject.Locality)
|
||||
printListHelper(out, "\t", "Province", cr.Subject.Province)
|
||||
printListHelper(out, "\t", "StreetAddress", cr.Subject.StreetAddress)
|
||||
printListHelper(out, "\t", "PostalCode", cr.Subject.PostalCode)
|
||||
|
||||
if len(cr.DNSNames)+len(cr.EmailAddresses)+len(cr.IPAddresses) > 0 {
|
||||
fmt.Fprintf(out, "Subject Alternative Names:\n")
|
||||
printListHelper(out, "\t", "DNS Names", cr.DNSNames)
|
||||
printListHelper(out, "\t", "Email Addresses", cr.EmailAddresses)
|
||||
var ipaddrs []string
|
||||
for _, ipaddr := range cr.IPAddresses {
|
||||
ipaddrs = append(ipaddrs, ipaddr.String())
|
||||
}
|
||||
printListHelper(out, "\t", "IP Addresses", ipaddrs)
|
||||
}
|
||||
|
||||
if describerSettings.ShowEvents {
|
||||
events, _ := p.client.Events(namespace).Search(csr)
|
||||
if events != nil {
|
||||
DescribeEvents(events, out)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// HorizontalPodAutoscalerDescriber generates information about a horizontal pod autoscaler.
|
||||
type HorizontalPodAutoscalerDescriber struct {
|
||||
client *client.Client
|
||||
|
|
@ -2366,14 +2568,64 @@ func printTaintsMultilineWithIndent(out io.Writer, initialIndent, title, innerIn
|
|||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
effects := []api.TaintEffect{api.TaintEffectNoSchedule, api.TaintEffectPreferNoSchedule}
|
||||
|
||||
for i, key := range keys {
|
||||
for _, taint := range taints {
|
||||
if taint.Key == key {
|
||||
for _, effect := range effects {
|
||||
for _, taint := range taints {
|
||||
if taint.Key == key && taint.Effect == effect {
|
||||
if i != 0 {
|
||||
fmt.Fprint(out, initialIndent)
|
||||
fmt.Fprint(out, innerIndent)
|
||||
}
|
||||
fmt.Fprintf(out, "%s=%s:%s\n", taint.Key, taint.Value, taint.Effect)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// printTolerationsMultiline prints multiple tolerations with a proper alignment.
|
||||
func printTolerationsInAnnotationMultiline(out io.Writer, title string, annotations map[string]string) {
|
||||
tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
|
||||
if err != nil {
|
||||
tolerations = []api.Toleration{}
|
||||
}
|
||||
printTolerationsMultilineWithIndent(out, "", title, "\t", tolerations)
|
||||
}
|
||||
|
||||
// printTolerationsMultilineWithIndent prints multiple tolerations with a user-defined alignment.
|
||||
func printTolerationsMultilineWithIndent(out io.Writer, initialIndent, title, innerIndent string, tolerations []api.Toleration) {
|
||||
fmt.Fprintf(out, "%s%s:%s", initialIndent, title, innerIndent)
|
||||
|
||||
if tolerations == nil || len(tolerations) == 0 {
|
||||
fmt.Fprintln(out, "<none>")
|
||||
return
|
||||
}
|
||||
|
||||
// to print tolerations in the sorted order
|
||||
keys := make([]string, 0, len(tolerations))
|
||||
for _, toleration := range tolerations {
|
||||
keys = append(keys, toleration.Key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i, key := range keys {
|
||||
for _, toleration := range tolerations {
|
||||
if toleration.Key == key {
|
||||
if i != 0 {
|
||||
fmt.Fprint(out, initialIndent)
|
||||
fmt.Fprint(out, innerIndent)
|
||||
}
|
||||
fmt.Fprintf(out, "%s=%s:%s\n", taint.Key, taint.Value, taint.Effect)
|
||||
fmt.Fprintf(out, "%s=%s", toleration.Key, toleration.Value)
|
||||
if len(toleration.Operator) != 0 {
|
||||
fmt.Fprintf(out, ":%s", toleration.Operator)
|
||||
}
|
||||
if len(toleration.Effect) != 0 {
|
||||
fmt.Fprintf(out, ":%s", toleration.Effect)
|
||||
}
|
||||
fmt.Fprintf(out, "\n")
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
vendor/k8s.io/kubernetes/pkg/kubectl/history.go
generated
vendored
59
vendor/k8s.io/kubernetes/pkg/kubectl/history.go
generated
vendored
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package kubectl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
|
|
@ -34,9 +35,9 @@ const (
|
|||
ChangeCauseAnnotation = "kubernetes.io/change-cause"
|
||||
)
|
||||
|
||||
// HistoryViewer provides an interface for resources that can be rolled back.
|
||||
// HistoryViewer provides an interface for resources have historical information.
|
||||
type HistoryViewer interface {
|
||||
History(namespace, name string) (HistoryInfo, error)
|
||||
ViewHistory(namespace, name string, revision int64) (string, error)
|
||||
}
|
||||
|
||||
func HistoryViewerFor(kind unversioned.GroupKind, c clientset.Interface) (HistoryViewer, error) {
|
||||
|
|
@ -47,68 +48,68 @@ func HistoryViewerFor(kind unversioned.GroupKind, c clientset.Interface) (Histor
|
|||
return nil, fmt.Errorf("no history viewer has been implemented for %q", kind)
|
||||
}
|
||||
|
||||
// HistoryInfo stores the mapping from revision to podTemplate;
|
||||
// note that change-cause annotation should be copied to podTemplate
|
||||
type HistoryInfo struct {
|
||||
RevisionToTemplate map[int64]*api.PodTemplateSpec
|
||||
}
|
||||
|
||||
type DeploymentHistoryViewer struct {
|
||||
c clientset.Interface
|
||||
}
|
||||
|
||||
// History returns a revision-to-replicaset map as the revision history of a deployment
|
||||
func (h *DeploymentHistoryViewer) History(namespace, name string) (HistoryInfo, error) {
|
||||
historyInfo := HistoryInfo{
|
||||
RevisionToTemplate: make(map[int64]*api.PodTemplateSpec),
|
||||
}
|
||||
// ViewHistory returns a revision-to-replicaset map as the revision history of a deployment
|
||||
func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) {
|
||||
deployment, err := h.c.Extensions().Deployments(namespace).Get(name)
|
||||
if err != nil {
|
||||
return historyInfo, fmt.Errorf("failed to retrieve deployment %s: %v", name, err)
|
||||
return "", fmt.Errorf("failed to retrieve deployment %s: %v", name, err)
|
||||
}
|
||||
_, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c)
|
||||
if err != nil {
|
||||
return historyInfo, fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", name, err)
|
||||
return "", fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", name, err)
|
||||
}
|
||||
allRSs := allOldRSs
|
||||
if newRS != nil {
|
||||
allRSs = append(allRSs, newRS)
|
||||
}
|
||||
|
||||
historyInfo := make(map[int64]*api.PodTemplateSpec)
|
||||
for _, rs := range allRSs {
|
||||
v, err := deploymentutil.Revision(rs)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
historyInfo.RevisionToTemplate[v] = &rs.Spec.Template
|
||||
historyInfo[v] = &rs.Spec.Template
|
||||
changeCause := getChangeCause(rs)
|
||||
if historyInfo.RevisionToTemplate[v].Annotations == nil {
|
||||
historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string)
|
||||
if historyInfo[v].Annotations == nil {
|
||||
historyInfo[v].Annotations = make(map[string]string)
|
||||
}
|
||||
if len(changeCause) > 0 {
|
||||
historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause
|
||||
historyInfo[v].Annotations[ChangeCauseAnnotation] = changeCause
|
||||
}
|
||||
}
|
||||
return historyInfo, nil
|
||||
}
|
||||
|
||||
// PrintRolloutHistory prints a formatted table of the input revision history of the deployment
|
||||
func PrintRolloutHistory(historyInfo HistoryInfo, resource, name string) (string, error) {
|
||||
if len(historyInfo.RevisionToTemplate) == 0 {
|
||||
return fmt.Sprintf("No rollout history found in %s %q", resource, name), nil
|
||||
if len(historyInfo) == 0 {
|
||||
return "No rollout history found.", nil
|
||||
}
|
||||
|
||||
if revision > 0 {
|
||||
// Print details of a specific revision
|
||||
template, ok := historyInfo[revision]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unable to find the specified revision")
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
DescribePodTemplate(template, buf)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// Sort the revisionToChangeCause map by revision
|
||||
revisions := make([]int64, 0, len(historyInfo.RevisionToTemplate))
|
||||
for r := range historyInfo.RevisionToTemplate {
|
||||
revisions := make([]int64, 0, len(historyInfo))
|
||||
for r := range historyInfo {
|
||||
revisions = append(revisions, r)
|
||||
}
|
||||
sliceutil.SortInts64(revisions)
|
||||
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "%s %q:\n", resource, name)
|
||||
fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n")
|
||||
for _, r := range revisions {
|
||||
// Find the change-cause of revision r
|
||||
changeCause := historyInfo.RevisionToTemplate[r].Annotations[ChangeCauseAnnotation]
|
||||
changeCause := historyInfo[r].Annotations[ChangeCauseAnnotation]
|
||||
if len(changeCause) == 0 {
|
||||
changeCause = "<none>"
|
||||
}
|
||||
|
|
|
|||
21
vendor/k8s.io/kubernetes/pkg/kubectl/kubectl.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/kubectl/kubectl.go
generated
vendored
|
|
@ -30,12 +30,6 @@ import (
|
|||
|
||||
const (
|
||||
kubectlAnnotationPrefix = "kubectl.kubernetes.io/"
|
||||
// TODO: auto-generate this
|
||||
PossibleResourceTypes = `Possible resource types include (case insensitive): pods (aka 'po'), services (aka 'svc'), deployments,
|
||||
replicasets (aka 'rs'), replicationcontrollers (aka 'rc'), nodes (aka 'no'), events (aka 'ev'), limitranges (aka 'limits'),
|
||||
persistentvolumes (aka 'pv'), persistentvolumeclaims (aka 'pvc'), resourcequotas (aka 'quota'), namespaces (aka 'ns'),
|
||||
serviceaccounts (aka 'sa'), ingresses (aka 'ing'), horizontalpodautoscalers (aka 'hpa'), daemonsets (aka 'ds'), configmaps,
|
||||
componentstatuses (aka 'cs), endpoints (aka 'ep'), petsets (alpha feature, may be unstable) and secrets.`
|
||||
)
|
||||
|
||||
type NamespaceInfo struct {
|
||||
|
|
@ -127,14 +121,18 @@ func (e ShortcutExpander) ResourceFor(resource unversioned.GroupVersionResource)
|
|||
return e.RESTMapper.ResourceFor(expandResourceShortcut(resource))
|
||||
}
|
||||
|
||||
func (e ShortcutExpander) ResourceSingularizer(resource string) (string, error) {
|
||||
return e.RESTMapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
|
||||
}
|
||||
|
||||
func (e ShortcutExpander) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
||||
return e.RESTMapper.RESTMapping(gk, versions...)
|
||||
}
|
||||
|
||||
func (e ShortcutExpander) RESTMappings(gk unversioned.GroupKind) ([]*meta.RESTMapping, error) {
|
||||
return e.RESTMapper.RESTMappings(gk)
|
||||
}
|
||||
|
||||
func (e ShortcutExpander) ResourceSingularizer(resource string) (string, error) {
|
||||
return e.RESTMapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
|
||||
}
|
||||
|
||||
func (e ShortcutExpander) AliasesForResource(resource string) ([]string, bool) {
|
||||
return e.RESTMapper.AliasesForResource(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
|
||||
}
|
||||
|
|
@ -144,7 +142,10 @@ var shortForms = map[string]string{
|
|||
// Please keep this alphabetized
|
||||
// If you add an entry here, please also take a look at pkg/kubectl/cmd/cmd.go
|
||||
// and add an entry to valid_resources when appropriate.
|
||||
"cm": "configmaps",
|
||||
"cs": "componentstatuses",
|
||||
"csr": "certificatesigningrequests",
|
||||
"deploy": "deployments",
|
||||
"ds": "daemonsets",
|
||||
"ep": "endpoints",
|
||||
"ev": "events",
|
||||
|
|
|
|||
4
vendor/k8s.io/kubernetes/pkg/kubectl/proxy_server.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/kubectl/proxy_server.go
generated
vendored
|
|
@ -35,7 +35,7 @@ import (
|
|||
const (
|
||||
DefaultHostAcceptRE = "^localhost$,^127\\.0\\.0\\.1$,^\\[::1\\]$"
|
||||
DefaultPathAcceptRE = "^/.*"
|
||||
DefaultPathRejectRE = "^/api/.*/exec,^/api/.*/run,^/api/.*/attach"
|
||||
DefaultPathRejectRE = "^/api/.*/pods/.*/exec,^/api/.*/pods/.*/attach"
|
||||
DefaultMethodRejectRE = "POST,PUT,PATCH"
|
||||
)
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ type FilterServer struct {
|
|||
delegate http.Handler
|
||||
}
|
||||
|
||||
// Splits a comma separated list of regexps into a array of Regexp objects.
|
||||
// Splits a comma separated list of regexps into an array of Regexp objects.
|
||||
func MakeRegexpArray(str string) ([]*regexp.Regexp, error) {
|
||||
parts := strings.Split(str, ",")
|
||||
result := make([]*regexp.Regexp, len(parts))
|
||||
|
|
|
|||
125
vendor/k8s.io/kubernetes/pkg/kubectl/quota.go
generated
vendored
Normal file
125
vendor/k8s.io/kubernetes/pkg/kubectl/quota.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// ResourceQuotaGeneratorV1 supports stable generation of a resource quota
|
||||
type ResourceQuotaGeneratorV1 struct {
|
||||
// The name of a quota object.
|
||||
Name string
|
||||
|
||||
// The hard resource limit string before parsing.
|
||||
Hard string
|
||||
|
||||
// The scopes of a quota object before parsing.
|
||||
Scopes string
|
||||
}
|
||||
|
||||
// ParamNames returns the set of supported input parameters when using the parameter injection generator pattern
|
||||
func (g ResourceQuotaGeneratorV1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"name", true},
|
||||
{"hard", true},
|
||||
{"scopes", false},
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure it supports the generator pattern that uses parameter injection
|
||||
var _ Generator = &ResourceQuotaGeneratorV1{}
|
||||
|
||||
// Ensure it supports the generator pattern that uses parameters specified during construction
|
||||
var _ StructuredGenerator = &ResourceQuotaGeneratorV1{}
|
||||
|
||||
func (g ResourceQuotaGeneratorV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||
err := ValidateParams(g.ParamNames(), genericParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := map[string]string{}
|
||||
for key, value := range genericParams {
|
||||
strVal, isString := value.(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
|
||||
}
|
||||
params[key] = strVal
|
||||
}
|
||||
|
||||
delegate := &ResourceQuotaGeneratorV1{}
|
||||
delegate.Name = params["name"]
|
||||
delegate.Hard = params["hard"]
|
||||
delegate.Scopes = params["scopes"]
|
||||
return delegate.StructuredGenerate()
|
||||
}
|
||||
|
||||
// StructuredGenerate outputs a ResourceQuota object using the configured fields
|
||||
func (g *ResourceQuotaGeneratorV1) StructuredGenerate() (runtime.Object, error) {
|
||||
if err := g.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceList, err := populateResourceList(g.Hard)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scopes, err := parseScopes(g.Scopes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceQuota := &api.ResourceQuota{}
|
||||
resourceQuota.Name = g.Name
|
||||
resourceQuota.Spec.Hard = resourceList
|
||||
resourceQuota.Spec.Scopes = scopes
|
||||
return resourceQuota, nil
|
||||
}
|
||||
|
||||
// validate validates required fields are set to support structured generation
|
||||
func (r *ResourceQuotaGeneratorV1) validate() error {
|
||||
if len(r.Name) == 0 {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseScopes(spec string) ([]api.ResourceQuotaScope, error) {
|
||||
// empty input gets a nil response to preserve generator test expected behaviors
|
||||
if spec == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
scopes := strings.Split(spec, ",")
|
||||
result := make([]api.ResourceQuotaScope, 0, len(scopes))
|
||||
for _, scope := range scopes {
|
||||
// intentionally do not verify the scope against the valid scope list. This is done by the apiserver anyway.
|
||||
|
||||
if scope == "" {
|
||||
return nil, fmt.Errorf("invalid resource quota scope \"\"")
|
||||
}
|
||||
|
||||
result = append(result, api.ResourceQuotaScope(scope))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
15
vendor/k8s.io/kubernetes/pkg/kubectl/resource/builder.go
generated
vendored
15
vendor/k8s.io/kubernetes/pkg/kubectl/resource/builder.go
generated
vendored
|
|
@ -212,6 +212,10 @@ func (b *Builder) ResourceNames(resource string, names ...string) *Builder {
|
|||
b.resourceTuples = append(b.resourceTuples, tuple)
|
||||
continue
|
||||
}
|
||||
if len(resource) == 0 {
|
||||
b.errs = append(b.errs, fmt.Errorf("the argument %q must be RESOURCE/NAME", name))
|
||||
continue
|
||||
}
|
||||
|
||||
// Use the given default type to create a resource tuple
|
||||
b.resourceTuples = append(b.resourceTuples, resourceTuple{Resource: resource, Name: name})
|
||||
|
|
@ -333,7 +337,7 @@ func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string
|
|||
}
|
||||
case len(args) == 0:
|
||||
default:
|
||||
b.errs = append(b.errs, fmt.Errorf("when passing arguments, must be resource or resource and name"))
|
||||
b.errs = append(b.errs, fmt.Errorf("arguments must consist of a resource or a resource and name"))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
|
@ -362,7 +366,12 @@ func hasCombinedTypeArgs(args []string) (bool, error) {
|
|||
case hasSlash > 0 && hasSlash == len(args):
|
||||
return true, nil
|
||||
case hasSlash > 0 && hasSlash != len(args):
|
||||
return true, fmt.Errorf("when passing arguments in resource/name form, all arguments must include the resource")
|
||||
baseCmd := "cmd"
|
||||
if len(os.Args) > 0 {
|
||||
baseCmdSlice := strings.Split(os.Args[0], "/")
|
||||
baseCmd = baseCmdSlice[len(baseCmdSlice)-1]
|
||||
}
|
||||
return true, fmt.Errorf("there is no need to specify a resource type as a separate argument when passing arguments in resource/name form (e.g. '%s get resource/<resource_name>' instead of '%s get resource resource/<resource_name>'", baseCmd, baseCmd)
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -449,7 +458,7 @@ func (b *Builder) mappingFor(resourceArg string) (*meta.RESTMapping, error) {
|
|||
if fullySpecifiedGVR != nil {
|
||||
gvk, _ = b.mapper.KindFor(*fullySpecifiedGVR)
|
||||
}
|
||||
if gvk.IsEmpty() {
|
||||
if gvk.Empty() {
|
||||
var err error
|
||||
gvk, err = b.mapper.KindFor(groupResource.WithVersion(""))
|
||||
if err != nil {
|
||||
|
|
|
|||
17
vendor/k8s.io/kubernetes/pkg/kubectl/resource/mapper.go
generated
vendored
17
vendor/k8s.io/kubernetes/pkg/kubectl/resource/mapper.go
generated
vendored
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -54,20 +53,8 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
|
||||
}
|
||||
var obj runtime.Object
|
||||
var versioned runtime.Object
|
||||
if isThirdParty, gvkOut, err := thirdpartyresourcedata.IsThirdPartyObject(data, gvk); err != nil {
|
||||
return nil, err
|
||||
} else if isThirdParty {
|
||||
obj, err = runtime.Decode(thirdpartyresourcedata.NewDecoder(nil, gvkOut.Kind), data)
|
||||
versioned = obj
|
||||
gvk = gvkOut
|
||||
} else {
|
||||
obj, versioned = versions.Last(), versions.First()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode %q: %v [%v]", source, err, gvk)
|
||||
}
|
||||
|
||||
obj, versioned := versions.Last(), versions.First()
|
||||
mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
|
||||
|
|
|
|||
8
vendor/k8s.io/kubernetes/pkg/kubectl/resource/result.go
generated
vendored
8
vendor/k8s.io/kubernetes/pkg/kubectl/resource/result.go
generated
vendored
|
|
@ -250,7 +250,7 @@ func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder
|
|||
|
||||
// objects that are not part of api.Scheme must be converted to JSON
|
||||
// TODO: convert to map[string]interface{}, attach to runtime.Unknown?
|
||||
if !version.IsEmpty() {
|
||||
if !version.Empty() {
|
||||
if _, _, err := api.Scheme.ObjectKinds(info.Object); runtime.IsNotRegisteredError(err) {
|
||||
// TODO: ideally this would encode to version, but we don't expose multiple codecs here.
|
||||
data, err := runtime.Encode(encoder, info.Object)
|
||||
|
|
@ -274,13 +274,13 @@ func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder
|
|||
|
||||
// tryConvert attempts to convert the given object to the provided versions in order. This function assumes
|
||||
// the object is in internal version.
|
||||
func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
|
||||
func tryConvert(converter runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
|
||||
var last error
|
||||
for _, version := range versions {
|
||||
if version.IsEmpty() {
|
||||
if version.Empty() {
|
||||
return object, nil
|
||||
}
|
||||
obj, err := convertor.ConvertToVersion(object, version)
|
||||
obj, err := converter.ConvertToVersion(object, version)
|
||||
if err != nil {
|
||||
last = err
|
||||
continue
|
||||
|
|
|
|||
16
vendor/k8s.io/kubernetes/pkg/kubectl/resource/visitor.go
generated
vendored
16
vendor/k8s.io/kubernetes/pkg/kubectl/resource/visitor.go
generated
vendored
|
|
@ -207,10 +207,6 @@ func ValidateSchema(data []byte, schema validation.Schema) error {
|
|||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
data, err := yaml.ToJSON(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting to YAML: %v", err)
|
||||
}
|
||||
if err := schema.ValidateBytes(data); err != nil {
|
||||
return fmt.Errorf("error validating data: %v; %s", err, stopValidateMessage)
|
||||
}
|
||||
|
|
@ -389,7 +385,7 @@ func (v FlattenListVisitor) Visit(fn VisitorFunc) error {
|
|||
|
||||
// If we have a GroupVersionKind on the list, prioritize that when asking for info on the objects contained in the list
|
||||
var preferredGVKs []unversioned.GroupVersionKind
|
||||
if info.Mapping != nil && !info.Mapping.GroupVersionKind.IsEmpty() {
|
||||
if info.Mapping != nil && !info.Mapping.GroupVersionKind.Empty() {
|
||||
preferredGVKs = append(preferredGVKs, info.Mapping.GroupVersionKind)
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +427,7 @@ func FileVisitorForSTDIN(mapper *Mapper, schema validation.Schema) Visitor {
|
|||
}
|
||||
|
||||
// ExpandPathsToFileVisitors will return a slice of FileVisitors that will handle files from the provided path.
|
||||
// After FileVisitors open the files, they will pass a io.Reader to a StreamVisitor to do the reading. (stdin
|
||||
// After FileVisitors open the files, they will pass an io.Reader to a StreamVisitor to do the reading. (stdin
|
||||
// is also taken care of). Paths argument also accepts a single file, and will return a single visitor
|
||||
func ExpandPathsToFileVisitors(mapper *Mapper, paths string, recursive bool, extensions []string, schema validation.Schema) ([]Visitor, error) {
|
||||
var visitors []Visitor
|
||||
|
|
@ -622,13 +618,7 @@ func RetrieveLatest(info *Info, err error) error {
|
|||
if info.Namespaced() && len(info.Namespace) == 0 {
|
||||
return fmt.Errorf("no namespace set on resource %s %q", info.Mapping.Resource, info.Name)
|
||||
}
|
||||
obj, err := NewHelper(info.Client, info.Mapping).Get(info.Namespace, info.Name, info.Export)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.Object = obj
|
||||
info.ResourceVersion, _ = info.Mapping.MetadataAccessor.ResourceVersion(obj)
|
||||
return nil
|
||||
return info.Get()
|
||||
}
|
||||
|
||||
// RetrieveLazy updates the object if it has not been loaded yet.
|
||||
|
|
|
|||
529
vendor/k8s.io/kubernetes/pkg/kubectl/resource_printer.go
generated
vendored
529
vendor/k8s.io/kubernetes/pkg/kubectl/resource_printer.go
generated
vendored
|
|
@ -39,6 +39,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
|
@ -127,6 +128,7 @@ func GetPrinter(format, formatArgument string, noHeaders bool) (ResourcePrinter,
|
|||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||
}
|
||||
defer file.Close()
|
||||
if printer, err = NewCustomColumnsPrinterFromTemplate(file, api.Codecs.UniversalDecoder()); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
|
@ -145,6 +147,9 @@ type ResourcePrinter interface {
|
|||
// Print receives a runtime object, formats it and prints it to a writer.
|
||||
PrintObj(runtime.Object, io.Writer) error
|
||||
HandledResources() []string
|
||||
//Can be used to print out warning/clarifications if needed
|
||||
//after all objects were printed
|
||||
FinishPrint(io.Writer, string) error
|
||||
}
|
||||
|
||||
// ResourcePrinterFunc is a function that can print objects
|
||||
|
|
@ -160,42 +165,41 @@ func (fn ResourcePrinterFunc) HandledResources() []string {
|
|||
return []string{}
|
||||
}
|
||||
|
||||
func (fn ResourcePrinterFunc) FinishPrint(io.Writer, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VersionedPrinter takes runtime objects and ensures they are converted to a given API version
|
||||
// prior to being passed to a nested printer.
|
||||
type VersionedPrinter struct {
|
||||
printer ResourcePrinter
|
||||
convertor runtime.ObjectConvertor
|
||||
converter runtime.ObjectConvertor
|
||||
versions []unversioned.GroupVersion
|
||||
}
|
||||
|
||||
// NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
|
||||
func NewVersionedPrinter(printer ResourcePrinter, convertor runtime.ObjectConvertor, versions ...unversioned.GroupVersion) ResourcePrinter {
|
||||
func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...unversioned.GroupVersion) ResourcePrinter {
|
||||
return &VersionedPrinter{
|
||||
printer: printer,
|
||||
convertor: convertor,
|
||||
converter: converter,
|
||||
versions: versions,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *VersionedPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj implements ResourcePrinter
|
||||
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
if len(p.versions) == 0 {
|
||||
return fmt.Errorf("no version specified, object cannot be converted")
|
||||
}
|
||||
for _, version := range p.versions {
|
||||
if version.IsEmpty() {
|
||||
continue
|
||||
}
|
||||
converted, err := p.convertor.ConvertToVersion(obj, version)
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.printer.PrintObj(converted, w)
|
||||
converted, err := p.converter.ConvertToVersion(obj, unversioned.GroupVersions(p.versions))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("the object cannot be converted to any of the versions: %v", p.versions)
|
||||
return p.printer.PrintObj(converted, w)
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
|
|
@ -209,6 +213,10 @@ type NamePrinter struct {
|
|||
Typer runtime.ObjectTyper
|
||||
}
|
||||
|
||||
func (p *NamePrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
|
@ -257,6 +265,10 @@ func (p *NamePrinter) HandledResources() []string {
|
|||
type JSONPrinter struct {
|
||||
}
|
||||
|
||||
func (p *JSONPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
|
||||
func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
switch obj := obj.(type) {
|
||||
|
|
@ -265,14 +277,12 @@ func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
|||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(obj)
|
||||
data, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dst := bytes.Buffer{}
|
||||
err = json.Indent(&dst, data, "", " ")
|
||||
dst.WriteByte('\n')
|
||||
_, err = w.Write(dst.Bytes())
|
||||
data = append(data, '\n')
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +296,11 @@ func (p *JSONPrinter) HandledResources() []string {
|
|||
// to the given version first.
|
||||
type YAMLPrinter struct {
|
||||
version string
|
||||
convertor runtime.ObjectConvertor
|
||||
converter runtime.ObjectConvertor
|
||||
}
|
||||
|
||||
func (p *YAMLPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj prints the data as YAML.
|
||||
|
|
@ -317,6 +331,7 @@ func (p *YAMLPrinter) HandledResources() []string {
|
|||
type handlerEntry struct {
|
||||
columns []string
|
||||
printFunc reflect.Value
|
||||
args []reflect.Value
|
||||
}
|
||||
|
||||
type PrintOptions struct {
|
||||
|
|
@ -327,7 +342,7 @@ type PrintOptions struct {
|
|||
ShowAll bool
|
||||
ShowLabels bool
|
||||
AbsoluteTimestamps bool
|
||||
KindName string
|
||||
Kind string
|
||||
ColumnLabels []string
|
||||
}
|
||||
|
||||
|
|
@ -336,31 +351,45 @@ type PrintOptions struct {
|
|||
// will only be printed if the object type changes. This makes it useful for printing items
|
||||
// received from watches.
|
||||
type HumanReadablePrinter struct {
|
||||
handlerMap map[reflect.Type]*handlerEntry
|
||||
Options PrintOptions
|
||||
lastType reflect.Type
|
||||
handlerMap map[reflect.Type]*handlerEntry
|
||||
options PrintOptions
|
||||
lastType reflect.Type
|
||||
hiddenObjNum int
|
||||
}
|
||||
|
||||
// NewHumanReadablePrinter creates a HumanReadablePrinter.
|
||||
func NewHumanReadablePrinter(noHeaders, withNamespace bool, wide bool, showAll bool, showLabels bool, absoluteTimestamps bool, columnLabels []string) *HumanReadablePrinter {
|
||||
func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
|
||||
printer := &HumanReadablePrinter{
|
||||
handlerMap: make(map[reflect.Type]*handlerEntry),
|
||||
Options: PrintOptions{
|
||||
NoHeaders: noHeaders,
|
||||
WithNamespace: withNamespace,
|
||||
WithKind: false,
|
||||
KindName: "",
|
||||
Wide: wide,
|
||||
ShowAll: showAll,
|
||||
ShowLabels: showLabels,
|
||||
AbsoluteTimestamps: absoluteTimestamps,
|
||||
ColumnLabels: columnLabels,
|
||||
},
|
||||
options: options,
|
||||
}
|
||||
printer.addDefaultHandlers()
|
||||
return printer
|
||||
}
|
||||
|
||||
// formatResourceName receives a resource kind, name, and boolean specifying
|
||||
// whether or not to update the current name to "kind/name"
|
||||
func formatResourceName(kind, name string, withKind bool) string {
|
||||
if !withKind || kind == "" {
|
||||
return name
|
||||
}
|
||||
|
||||
return kind + "/" + name
|
||||
}
|
||||
|
||||
// GetResourceKind returns the type currently set for a resource
|
||||
func (h *HumanReadablePrinter) GetResourceKind() string {
|
||||
return h.options.Kind
|
||||
}
|
||||
|
||||
// EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true
|
||||
// and "Kind" to the string arg it receives, pre-pending this string
|
||||
// to the "NAME" column in an output of resources.
|
||||
func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) {
|
||||
h.options.WithKind = true
|
||||
h.options.Kind = kind
|
||||
}
|
||||
|
||||
// Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
|
||||
// See validatePrintHandlerFunc for required method signature.
|
||||
func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{}) error {
|
||||
|
|
@ -369,6 +398,7 @@ func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{})
|
|||
glog.Errorf("Unable to add print handler: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
objType := printFuncValue.Type().In(0)
|
||||
h.handlerMap[objType] = &handlerEntry{
|
||||
columns: columns,
|
||||
|
|
@ -416,13 +446,22 @@ func (h *HumanReadablePrinter) HandledResources() []string {
|
|||
return keys
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) FinishPrint(output io.Writer, res string) error {
|
||||
if !h.options.NoHeaders && !h.options.ShowAll && h.hiddenObjNum > 0 {
|
||||
_, err := fmt.Fprintf(output, " info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", h.hiddenObjNum, res)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: When adding a new resource type here, please update the list
|
||||
// pkg/kubectl/cmd/get.go to reflect the new resource type.
|
||||
var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
|
||||
var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
|
||||
var replicationControllerColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
|
||||
var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
|
||||
var replicationControllerColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
|
||||
var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "READY", "AGE"}
|
||||
var jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"}
|
||||
var scheduledJobColumns = []string{"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST-SCHEDULE"}
|
||||
var serviceColumns = []string{"NAME", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
|
||||
var ingressColumns = []string{"NAME", "HOSTS", "ADDRESS", "PORTS", "AGE"}
|
||||
var petSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
|
||||
|
|
@ -443,6 +482,7 @@ var roleColumns = []string{"NAME", "AGE"}
|
|||
var roleBindingColumns = []string{"NAME", "AGE"}
|
||||
var clusterRoleColumns = []string{"NAME", "AGE"}
|
||||
var clusterRoleBindingColumns = []string{"NAME", "AGE"}
|
||||
var storageClassColumns = []string{"NAME", "TYPE"}
|
||||
|
||||
// TODO: consider having 'KIND' for third party resource data
|
||||
var thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
|
||||
|
|
@ -451,13 +491,44 @@ var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print
|
|||
var deploymentColumns = []string{"NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE"}
|
||||
var configMapColumns = []string{"NAME", "DATA", "AGE"}
|
||||
var podSecurityPolicyColumns = []string{"NAME", "PRIV", "CAPS", "VOLUMEPLUGINS", "SELINUX", "RUNASUSER"}
|
||||
var clusterColumns = []string{"NAME", "STATUS", "VERSION", "AGE"}
|
||||
var clusterColumns = []string{"NAME", "STATUS", "AGE"}
|
||||
var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"}
|
||||
var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"}
|
||||
|
||||
func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
|
||||
reason := string(pod.Status.Phase)
|
||||
// if not printing all pods, skip terminated pods (default)
|
||||
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
|
||||
h.hiddenObjNum++
|
||||
return nil
|
||||
}
|
||||
if err := printPodBase(pod, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
|
||||
for _, pod := range podList.Items {
|
||||
reason := string(pod.Status.Phase)
|
||||
// if not printing all pods, skip terminated pods (default)
|
||||
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
|
||||
h.hiddenObjNum++
|
||||
continue
|
||||
}
|
||||
|
||||
if err := printPodBase(&pod, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addDefaultHandlers adds print handlers for default Kubernetes types.
|
||||
func (h *HumanReadablePrinter) addDefaultHandlers() {
|
||||
h.Handler(podColumns, printPod)
|
||||
h.Handler(podColumns, printPodList)
|
||||
h.Handler(podColumns, h.printPodList)
|
||||
h.Handler(podColumns, h.printPod)
|
||||
h.Handler(podTemplateColumns, printPodTemplate)
|
||||
h.Handler(podTemplateColumns, printPodTemplateList)
|
||||
h.Handler(replicationControllerColumns, printReplicationController)
|
||||
|
|
@ -468,6 +539,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||
h.Handler(daemonSetColumns, printDaemonSetList)
|
||||
h.Handler(jobColumns, printJob)
|
||||
h.Handler(jobColumns, printJobList)
|
||||
h.Handler(scheduledJobColumns, printScheduledJob)
|
||||
h.Handler(scheduledJobColumns, printScheduledJobList)
|
||||
h.Handler(serviceColumns, printService)
|
||||
h.Handler(serviceColumns, printServiceList)
|
||||
h.Handler(ingressColumns, printIngress)
|
||||
|
|
@ -520,6 +593,10 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||
h.Handler(clusterRoleColumns, printClusterRoleList)
|
||||
h.Handler(clusterRoleBindingColumns, printClusterRoleBinding)
|
||||
h.Handler(clusterRoleBindingColumns, printClusterRoleBindingList)
|
||||
h.Handler(certificateSigningRequestColumns, printCertificateSigningRequest)
|
||||
h.Handler(certificateSigningRequestColumns, printCertificateSigningRequestList)
|
||||
h.Handler(storageClassColumns, printStorageClass)
|
||||
h.Handler(storageClassColumns, printStorageClassList)
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||
|
|
@ -596,28 +673,15 @@ func translateTimestamp(timestamp unversioned.Time) string {
|
|||
return shortHumanDuration(time.Now().Sub(timestamp.Time))
|
||||
}
|
||||
|
||||
func printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
|
||||
return printPodBase(pod, w, options)
|
||||
}
|
||||
|
||||
func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
|
||||
name := pod.Name
|
||||
name := formatResourceName(options.Kind, pod.Name, options.WithKind)
|
||||
namespace := pod.Namespace
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
restarts := 0
|
||||
totalContainers := len(pod.Spec.Containers)
|
||||
readyContainers := 0
|
||||
|
||||
reason := string(pod.Status.Phase)
|
||||
// if not printing all pods, skip terminated pods (default)
|
||||
if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) {
|
||||
return nil
|
||||
}
|
||||
if pod.Status.Reason != "" {
|
||||
reason = pod.Status.Reason
|
||||
}
|
||||
|
|
@ -715,23 +779,10 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
|
||||
for _, pod := range podList.Items {
|
||||
if err := printPodBase(&pod, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error {
|
||||
name := pod.Name
|
||||
namespace := pod.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, pod.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := pod.Namespace
|
||||
|
||||
containers := pod.Template.Spec.Containers
|
||||
|
||||
|
|
@ -770,14 +821,10 @@ func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options Pri
|
|||
|
||||
// TODO(AdoHe): try to put wide output in a single method
|
||||
func printReplicationController(controller *api.ReplicationController, w io.Writer, options PrintOptions) error {
|
||||
name := controller.Name
|
||||
name := formatResourceName(options.Kind, controller.Name, options.WithKind)
|
||||
|
||||
namespace := controller.Namespace
|
||||
containers := controller.Spec.Template.Spec.Containers
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -787,10 +834,12 @@ func printReplicationController(controller *api.ReplicationController, w io.Writ
|
|||
|
||||
desiredReplicas := controller.Spec.Replicas
|
||||
currentReplicas := controller.Status.Replicas
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
|
||||
readyReplicas := controller.Status.ReadyReplicas
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
|
||||
name,
|
||||
desiredReplicas,
|
||||
currentReplicas,
|
||||
readyReplicas,
|
||||
translateTimestamp(controller.CreationTimestamp),
|
||||
); err != nil {
|
||||
return err
|
||||
|
|
@ -824,14 +873,10 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr
|
|||
}
|
||||
|
||||
func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOptions) error {
|
||||
name := rs.Name
|
||||
name := formatResourceName(options.Kind, rs.Name, options.WithKind)
|
||||
|
||||
namespace := rs.Namespace
|
||||
containers := rs.Spec.Template.Spec.Containers
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -841,10 +886,12 @@ func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOption
|
|||
|
||||
desiredReplicas := rs.Spec.Replicas
|
||||
currentReplicas := rs.Status.Replicas
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
|
||||
readyReplicas := rs.Status.ReadyReplicas
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s",
|
||||
name,
|
||||
desiredReplicas,
|
||||
currentReplicas,
|
||||
readyReplicas,
|
||||
translateTimestamp(rs.CreationTimestamp),
|
||||
); err != nil {
|
||||
return err
|
||||
|
|
@ -877,11 +924,8 @@ func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options P
|
|||
}
|
||||
|
||||
func printCluster(c *federation.Cluster, w io.Writer, options PrintOptions) error {
|
||||
name := c.Name
|
||||
kind := options.KindName
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
name := formatResourceName(options.Kind, c.Name, options.WithKind)
|
||||
|
||||
var statuses []string
|
||||
for _, condition := range c.Status.Conditions {
|
||||
if condition.Status == api.ConditionTrue {
|
||||
|
|
@ -913,14 +957,10 @@ func printClusterList(list *federation.ClusterList, w io.Writer, options PrintOp
|
|||
}
|
||||
|
||||
func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
|
||||
name := job.Name
|
||||
name := formatResourceName(options.Kind, job.Name, options.WithKind)
|
||||
|
||||
namespace := job.Namespace
|
||||
containers := job.Spec.Template.Spec.Containers
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -979,6 +1019,42 @@ func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func printScheduledJob(scheduledJob *batch.ScheduledJob, w io.Writer, options PrintOptions) error {
|
||||
name := scheduledJob.Name
|
||||
namespace := scheduledJob.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
lastScheduleTime := "<none>"
|
||||
if scheduledJob.Status.LastScheduleTime != nil {
|
||||
lastScheduleTime = scheduledJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z)
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\n",
|
||||
name,
|
||||
scheduledJob.Spec.Schedule,
|
||||
printBoolPtr(scheduledJob.Spec.Suspend),
|
||||
len(scheduledJob.Status.Active),
|
||||
lastScheduleTime,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printScheduledJobList(list *batch.ScheduledJobList, w io.Writer, options PrintOptions) error {
|
||||
for _, scheduledJob := range list.Items {
|
||||
if err := printScheduledJob(&scheduledJob, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadBalancerStatusStringer behaves mostly like a string interface and converts the given status to a string.
|
||||
// `wide` indicates whether the returned value is meant for --o=wide output. If not, it's clipped to 16 bytes.
|
||||
func loadBalancerStatusStringer(s api.LoadBalancerStatus, wide bool) string {
|
||||
|
|
@ -1020,6 +1096,8 @@ func getServiceExternalIP(svc *api.Service, wide bool) string {
|
|||
return lbIps
|
||||
}
|
||||
return "<pending>"
|
||||
case api.ServiceTypeExternalName:
|
||||
return svc.Spec.ExternalName
|
||||
}
|
||||
return "<unknown>"
|
||||
}
|
||||
|
|
@ -1034,16 +1112,12 @@ func makePortString(ports []api.ServicePort) string {
|
|||
}
|
||||
|
||||
func printService(svc *api.Service, w io.Writer, options PrintOptions) error {
|
||||
name := svc.Name
|
||||
name := formatResourceName(options.Kind, svc.Name, options.WithKind)
|
||||
|
||||
namespace := svc.Namespace
|
||||
|
||||
internalIP := svc.Spec.ClusterIP
|
||||
externalIP := getServiceExternalIP(svc, options.Wide)
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1118,13 +1192,9 @@ func formatPorts(tls []extensions.IngressTLS) string {
|
|||
}
|
||||
|
||||
func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions) error {
|
||||
name := ingress.Name
|
||||
namespace := ingress.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, ingress.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := ingress.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1161,14 +1231,10 @@ func printIngressList(ingressList *extensions.IngressList, w io.Writer, options
|
|||
}
|
||||
|
||||
func printPetSet(ps *apps.PetSet, w io.Writer, options PrintOptions) error {
|
||||
name := ps.Name
|
||||
name := formatResourceName(options.Kind, ps.Name, options.WithKind)
|
||||
|
||||
namespace := ps.Namespace
|
||||
containers := ps.Spec.Template.Spec.Containers
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1213,13 +1279,9 @@ func printPetSetList(petSetList *apps.PetSetList, w io.Writer, options PrintOpti
|
|||
}
|
||||
|
||||
func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error {
|
||||
name := ds.Name
|
||||
namespace := ds.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, ds.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := ds.Namespace
|
||||
|
||||
containers := ds.Spec.Template.Spec.Containers
|
||||
|
||||
|
|
@ -1273,13 +1335,9 @@ func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options Pri
|
|||
}
|
||||
|
||||
func printEndpoints(endpoints *api.Endpoints, w io.Writer, options PrintOptions) error {
|
||||
name := endpoints.Name
|
||||
namespace := endpoints.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, endpoints.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := endpoints.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1306,12 +1364,8 @@ func printEndpointsList(list *api.EndpointsList, w io.Writer, options PrintOptio
|
|||
}
|
||||
|
||||
func printNamespace(item *api.Namespace, w io.Writer, options PrintOptions) error {
|
||||
name := item.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, item.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
if options.WithNamespace {
|
||||
return fmt.Errorf("namespace is not namespaced")
|
||||
}
|
||||
|
|
@ -1336,13 +1390,9 @@ func printNamespaceList(list *api.NamespaceList, w io.Writer, options PrintOptio
|
|||
}
|
||||
|
||||
func printSecret(item *api.Secret, w io.Writer, options PrintOptions) error {
|
||||
name := item.Name
|
||||
namespace := item.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, item.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := item.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1370,13 +1420,9 @@ func printSecretList(list *api.SecretList, w io.Writer, options PrintOptions) er
|
|||
}
|
||||
|
||||
func printServiceAccount(item *api.ServiceAccount, w io.Writer, options PrintOptions) error {
|
||||
name := item.Name
|
||||
namespace := item.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, item.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := item.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1404,12 +1450,8 @@ func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options
|
|||
}
|
||||
|
||||
func printNode(node *api.Node, w io.Writer, options PrintOptions) error {
|
||||
name := node.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, node.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
if options.WithNamespace {
|
||||
return fmt.Errorf("node is not namespaced")
|
||||
}
|
||||
|
|
@ -1457,12 +1499,8 @@ func printNodeList(list *api.NodeList, w io.Writer, options PrintOptions) error
|
|||
}
|
||||
|
||||
func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options PrintOptions) error {
|
||||
name := pv.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, pv.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
if options.WithNamespace {
|
||||
return fmt.Errorf("persistentVolume is not namespaced")
|
||||
}
|
||||
|
|
@ -1506,13 +1544,9 @@ func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, opti
|
|||
}
|
||||
|
||||
func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, options PrintOptions) error {
|
||||
name := pvc.Name
|
||||
namespace := pvc.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, pvc.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := pvc.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1550,13 +1584,9 @@ func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Wr
|
|||
}
|
||||
|
||||
func printEvent(event *api.Event, w io.Writer, options PrintOptions) error {
|
||||
name := event.InvolvedObject.Name
|
||||
namespace := event.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, event.InvolvedObject.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := event.Namespace
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
return err
|
||||
|
|
@ -1622,12 +1652,8 @@ func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options PrintOpt
|
|||
|
||||
// printObjectMeta prints the object metadata of a given resource.
|
||||
func printObjectMeta(meta api.ObjectMeta, w io.Writer, options PrintOptions, namespaced bool) error {
|
||||
name := meta.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, meta.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
if namespaced && options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", meta.Namespace); err != nil {
|
||||
return err
|
||||
|
|
@ -1718,13 +1744,70 @@ func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer,
|
|||
return nil
|
||||
}
|
||||
|
||||
func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintOptions) error {
|
||||
name := item.Name
|
||||
kind := options.KindName
|
||||
func printCertificateSigningRequest(csr *certificates.CertificateSigningRequest, w io.Writer, options PrintOptions) error {
|
||||
name := formatResourceName(options.Kind, csr.Name, options.WithKind)
|
||||
meta := csr.ObjectMeta
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
status, err := extractCSRStatus(csr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(
|
||||
w, "%s\t%s\t%s\t%s",
|
||||
name,
|
||||
translateTimestamp(meta.CreationTimestamp),
|
||||
csr.Spec.Username,
|
||||
status,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, AppendLabels(meta.Labels, options.ColumnLabels)); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprint(w, AppendAllLabels(options.ShowLabels, meta.Labels))
|
||||
return err
|
||||
}
|
||||
|
||||
func extractCSRStatus(csr *certificates.CertificateSigningRequest) (string, error) {
|
||||
var approved, denied bool
|
||||
for _, c := range csr.Status.Conditions {
|
||||
switch c.Type {
|
||||
case certificates.CertificateApproved:
|
||||
approved = true
|
||||
case certificates.CertificateDenied:
|
||||
denied = true
|
||||
default:
|
||||
return "", fmt.Errorf("unknown csr conditon %q", c)
|
||||
}
|
||||
}
|
||||
var status string
|
||||
// must be in order of presidence
|
||||
if denied {
|
||||
status += "Denied"
|
||||
} else if approved {
|
||||
status += "Approved"
|
||||
} else {
|
||||
status += "Pending"
|
||||
}
|
||||
if len(csr.Status.Certificate) > 0 {
|
||||
status += ",Issued"
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, w io.Writer, options PrintOptions) error {
|
||||
for i := range list.Items {
|
||||
if err := printCertificateSigningRequest(&list.Items[i], w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintOptions) error {
|
||||
name := formatResourceName(options.Kind, item.Name, options.WithKind)
|
||||
|
||||
if options.WithNamespace {
|
||||
return fmt.Errorf("componentStatus is not namespaced")
|
||||
}
|
||||
|
|
@ -1765,12 +1848,7 @@ func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, option
|
|||
}
|
||||
|
||||
func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, options PrintOptions) error {
|
||||
name := rsrc.Name
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
|
||||
|
||||
versions := make([]string, len(rsrc.Versions))
|
||||
for ix := range rsrc.Versions {
|
||||
|
|
@ -1802,12 +1880,7 @@ func truncate(str string, maxLen int) string {
|
|||
}
|
||||
|
||||
func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.Writer, options PrintOptions) error {
|
||||
name := rsrc.Name
|
||||
kind := options.KindName
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
|
||||
|
||||
l := labels.FormatLabels(rsrc.Labels)
|
||||
truncateCols := 50
|
||||
|
|
@ -1831,12 +1904,8 @@ func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList
|
|||
}
|
||||
|
||||
func printDeployment(deployment *extensions.Deployment, w io.Writer, options PrintOptions) error {
|
||||
name := deployment.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, deployment.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", deployment.Namespace); err != nil {
|
||||
return err
|
||||
|
|
@ -1869,12 +1938,8 @@ func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options P
|
|||
|
||||
func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error {
|
||||
namespace := hpa.Namespace
|
||||
name := hpa.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, hpa.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
reference := fmt.Sprintf("%s/%s",
|
||||
hpa.Spec.ScaleTargetRef.Kind,
|
||||
hpa.Spec.ScaleTargetRef.Name)
|
||||
|
|
@ -1926,13 +1991,9 @@ func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerL
|
|||
}
|
||||
|
||||
func printConfigMap(configMap *api.ConfigMap, w io.Writer, options PrintOptions) error {
|
||||
name := configMap.Name
|
||||
namespace := configMap.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, configMap.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := configMap.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -1959,12 +2020,8 @@ func printConfigMapList(list *api.ConfigMapList, w io.Writer, options PrintOptio
|
|||
}
|
||||
|
||||
func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, options PrintOptions) error {
|
||||
name := item.Name
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, item.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
_, err := fmt.Fprintf(w, "%s\t%t\t%v\t%s\t%s\t%s\t%s\t%t\t%v\n", name, item.Spec.Privileged,
|
||||
item.Spec.AllowedCapabilities, item.Spec.SELinux.Rule,
|
||||
item.Spec.RunAsUser.Rule, item.Spec.FSGroup.Rule, item.Spec.SupplementalGroups.Rule, item.Spec.ReadOnlyRootFilesystem, item.Spec.Volumes)
|
||||
|
|
@ -1982,13 +2039,9 @@ func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Wri
|
|||
}
|
||||
|
||||
func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, options PrintOptions) error {
|
||||
name := networkPolicy.Name
|
||||
namespace := networkPolicy.Namespace
|
||||
kind := options.KindName
|
||||
name := formatResourceName(options.Kind, networkPolicy.Name, options.WithKind)
|
||||
|
||||
if options.WithKind {
|
||||
name = kind + "/" + name
|
||||
}
|
||||
namespace := networkPolicy.Namespace
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
|
|
@ -2014,6 +2067,32 @@ func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, opt
|
|||
return nil
|
||||
}
|
||||
|
||||
func printStorageClass(sc *extensions.StorageClass, w io.Writer, options PrintOptions) error {
|
||||
name := sc.Name
|
||||
provtype := sc.Provisioner
|
||||
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t", name, provtype); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, AppendLabels(sc.Labels, options.ColumnLabels)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, sc.Labels)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printStorageClassList(scList *extensions.StorageClassList, w io.Writer, options PrintOptions) error {
|
||||
for _, sc := range scList.Items {
|
||||
if err := printStorageClass(&sc, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AppendLabels(itemLabels map[string]string, columnLabels []string) string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
|
|
@ -2135,18 +2214,18 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
|
|||
}
|
||||
t := reflect.TypeOf(obj)
|
||||
if handler := h.handlerMap[t]; handler != nil {
|
||||
if !h.Options.NoHeaders && t != h.lastType {
|
||||
headers := append(handler.columns, formatWideHeaders(h.Options.Wide, t)...)
|
||||
headers = append(headers, formatLabelHeaders(h.Options.ColumnLabels)...)
|
||||
if !h.options.NoHeaders && t != h.lastType {
|
||||
headers := append(handler.columns, formatWideHeaders(h.options.Wide, t)...)
|
||||
headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
|
||||
// LABELS is always the last column.
|
||||
headers = append(headers, formatShowLabelsHeader(h.Options.ShowLabels, t)...)
|
||||
if h.Options.WithNamespace {
|
||||
headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
|
||||
if h.options.WithNamespace {
|
||||
headers = append(withNamespacePrefixColumns, headers...)
|
||||
}
|
||||
h.printHeader(headers, w)
|
||||
h.lastType = t
|
||||
}
|
||||
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(w), reflect.ValueOf(h.Options)}
|
||||
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(w), reflect.ValueOf(h.options)}
|
||||
resultValue := handler.printFunc.Call(args)[0]
|
||||
if resultValue.IsNil() {
|
||||
return nil
|
||||
|
|
@ -2175,6 +2254,10 @@ func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (p *TemplatePrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj formats the obj with the Go Template.
|
||||
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
data, err := json.Marshal(obj)
|
||||
|
|
@ -2322,6 +2405,10 @@ func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
|
|||
return &JSONPathPrinter{tmpl, j}, nil
|
||||
}
|
||||
|
||||
func (j *JSONPathPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj formats the obj with the JSONPath Template.
|
||||
func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
var queryObj interface{} = obj
|
||||
|
|
|
|||
31
vendor/k8s.io/kubernetes/pkg/kubectl/rolling_updater.go
generated
vendored
31
vendor/k8s.io/kubernetes/pkg/kubectl/rolling_updater.go
generated
vendored
|
|
@ -214,7 +214,7 @@ func (r *RollingUpdater) Update(config *RollingUpdaterConfig) error {
|
|||
if desired > 0 && maxUnavailable == 0 && maxSurge == 0 {
|
||||
return fmt.Errorf("one of maxSurge or maxUnavailable must be specified")
|
||||
}
|
||||
// The minumum pods which must remain available througout the update
|
||||
// The minimum pods which must remain available throughout the update
|
||||
// calculated for internal convenience.
|
||||
minAvailable := int32(integer.IntMax(0, int(desired-maxUnavailable)))
|
||||
// If the desired new scale is 0, then the max unavailable is necessarily
|
||||
|
|
@ -513,14 +513,14 @@ func (r *RollingUpdater) cleanupWithClients(oldRc, newRc *api.ReplicationControl
|
|||
case DeleteRollingUpdateCleanupPolicy:
|
||||
// delete old rc
|
||||
fmt.Fprintf(config.Out, "Update succeeded. Deleting %s\n", oldRc.Name)
|
||||
return r.c.ReplicationControllers(r.ns).Delete(oldRc.Name)
|
||||
return r.c.ReplicationControllers(r.ns).Delete(oldRc.Name, nil)
|
||||
case RenameRollingUpdateCleanupPolicy:
|
||||
// delete old rc
|
||||
fmt.Fprintf(config.Out, "Update succeeded. Deleting old controller: %s\n", oldRc.Name)
|
||||
if err := r.c.ReplicationControllers(r.ns).Delete(oldRc.Name); err != nil {
|
||||
if err := r.c.ReplicationControllers(r.ns).Delete(oldRc.Name, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(config.Out, "Renaming %s to %s\n", newRc.Name, oldRc.Name)
|
||||
fmt.Fprintf(config.Out, "Renaming %s to %s\n", oldRc.Name, newRc.Name)
|
||||
return Rename(r.c, newRc, oldRc.Name)
|
||||
case PreserveRollingUpdateCleanupPolicy:
|
||||
return nil
|
||||
|
|
@ -533,13 +533,28 @@ func Rename(c client.ReplicationControllersNamespacer, rc *api.ReplicationContro
|
|||
oldName := rc.Name
|
||||
rc.Name = newName
|
||||
rc.ResourceVersion = ""
|
||||
|
||||
_, err := c.ReplicationControllers(rc.Namespace).Create(rc)
|
||||
// First delete the oldName RC and orphan its pods.
|
||||
trueVar := true
|
||||
err := c.ReplicationControllers(rc.Namespace).Delete(oldName, &api.DeleteOptions{OrphanDependents: &trueVar})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
err = wait.Poll(5*time.Second, 60*time.Second, func() (bool, error) {
|
||||
_, err := c.ReplicationControllers(rc.Namespace).Get(oldName)
|
||||
if err == nil {
|
||||
return false, nil
|
||||
} else if errors.IsNotFound(err) {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.ReplicationControllers(rc.Namespace).Delete(oldName)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
// Then create the same RC with the new name.
|
||||
_, err = c.ReplicationControllers(rc.Namespace).Create(rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
141
vendor/k8s.io/kubernetes/pkg/kubectl/run.go
generated
vendored
141
vendor/k8s.io/kubernetes/pkg/kubectl/run.go
generated
vendored
|
|
@ -27,6 +27,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
|
||||
batchv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/validation"
|
||||
|
|
@ -41,6 +42,7 @@ func (DeploymentV1Beta1) ParamNames() []GeneratorParam {
|
|||
{"name", true},
|
||||
{"replicas", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
|
|
@ -89,7 +91,8 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
|
||||
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +219,7 @@ func (JobV1Beta1) ParamNames() []GeneratorParam {
|
|||
{"default-name", false},
|
||||
{"name", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
|
|
@ -261,7 +265,8 @@ func (JobV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
|
||||
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -311,6 +316,7 @@ func (JobV1) ParamNames() []GeneratorParam {
|
|||
{"default-name", false},
|
||||
{"name", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
|
|
@ -356,7 +362,8 @@ func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = updateV1PodContainers(params, args, envs, podSpec); err != nil {
|
||||
imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
|
||||
if err = updateV1PodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +401,106 @@ func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, err
|
|||
return &job, nil
|
||||
}
|
||||
|
||||
type ScheduledJobV2Alpha1 struct{}
|
||||
|
||||
func (ScheduledJobV2Alpha1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"labels", false},
|
||||
{"default-name", false},
|
||||
{"name", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
{"leave-stdin-open", false},
|
||||
{"tty", false},
|
||||
{"command", false},
|
||||
{"args", false},
|
||||
{"env", false},
|
||||
{"requests", false},
|
||||
{"limits", false},
|
||||
{"restart", false},
|
||||
{"schedule", true},
|
||||
}
|
||||
}
|
||||
|
||||
func (ScheduledJobV2Alpha1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||
args, err := getArgs(genericParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
envs, err := getV1Envs(genericParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params, err := getParams(genericParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name, err := getName(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels, err := getLabels(params, true, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podSpec, err := makeV1PodSpec(params, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
|
||||
if err = updateV1PodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
leaveStdinOpen, err := GetBool(params, "leave-stdin-open", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
podSpec.Containers[0].StdinOnce = !leaveStdinOpen && podSpec.Containers[0].Stdin
|
||||
|
||||
if err := updateV1PodPorts(params, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restartPolicy := v1.RestartPolicy(params["restart"])
|
||||
if len(restartPolicy) == 0 {
|
||||
restartPolicy = v1.RestartPolicyNever
|
||||
}
|
||||
podSpec.RestartPolicy = restartPolicy
|
||||
|
||||
scheduledJob := batchv2alpha1.ScheduledJob{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: batchv2alpha1.ScheduledJobSpec{
|
||||
Schedule: params["schedule"],
|
||||
ConcurrencyPolicy: batchv2alpha1.AllowConcurrent,
|
||||
JobTemplate: batchv2alpha1.JobTemplateSpec{
|
||||
Spec: batchv2alpha1.JobSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: *podSpec,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &scheduledJob, nil
|
||||
}
|
||||
|
||||
type BasicReplicationController struct{}
|
||||
|
||||
func (BasicReplicationController) ParamNames() []GeneratorParam {
|
||||
|
|
@ -403,6 +510,7 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
|
|||
{"name", true},
|
||||
{"replicas", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
|
|
@ -591,7 +699,8 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
|
||||
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -618,7 +727,7 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
|
|||
return &controller, nil
|
||||
}
|
||||
|
||||
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, podSpec *api.PodSpec) error {
|
||||
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, imagePullPolicy api.PullPolicy, podSpec *api.PodSpec) error {
|
||||
if len(args) > 0 {
|
||||
command, err := GetBool(params, "command", false)
|
||||
if err != nil {
|
||||
|
|
@ -634,10 +743,15 @@ func updatePodContainers(params map[string]string, args []string, envs []api.Env
|
|||
if len(envs) > 0 {
|
||||
podSpec.Containers[0].Env = envs
|
||||
}
|
||||
|
||||
if len(imagePullPolicy) > 0 {
|
||||
// imagePullPolicy should be valid here since we have verified it before.
|
||||
podSpec.Containers[0].ImagePullPolicy = imagePullPolicy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateV1PodContainers(params map[string]string, args []string, envs []v1.EnvVar, podSpec *v1.PodSpec) error {
|
||||
func updateV1PodContainers(params map[string]string, args []string, envs []v1.EnvVar, imagePullPolicy v1.PullPolicy, podSpec *v1.PodSpec) error {
|
||||
if len(args) > 0 {
|
||||
command, err := GetBool(params, "command", false)
|
||||
if err != nil {
|
||||
|
|
@ -653,6 +767,11 @@ func updateV1PodContainers(params map[string]string, args []string, envs []v1.En
|
|||
if len(envs) > 0 {
|
||||
podSpec.Containers[0].Env = envs
|
||||
}
|
||||
|
||||
if len(imagePullPolicy) > 0 {
|
||||
// imagePullPolicy should be valid here since we have verified it before.
|
||||
podSpec.Containers[0].ImagePullPolicy = imagePullPolicy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -732,6 +851,7 @@ func (BasicPod) ParamNames() []GeneratorParam {
|
|||
{"default-name", false},
|
||||
{"name", true},
|
||||
{"image", true},
|
||||
{"image-pull-policy", false},
|
||||
{"port", false},
|
||||
{"hostport", false},
|
||||
{"stdin", false},
|
||||
|
|
@ -795,6 +915,8 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
|||
if len(restartPolicy) == 0 {
|
||||
restartPolicy = api.RestartPolicyAlways
|
||||
}
|
||||
// TODO: Figure out why we set ImagePullPolicy here, whether we can make it
|
||||
// consistent with the other places imagePullPolicy is set using flag.
|
||||
pod := api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
|
|
@ -816,7 +938,8 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
|||
RestartPolicy: restartPolicy,
|
||||
},
|
||||
}
|
||||
if err = updatePodContainers(params, args, envs, &pod.Spec); err != nil {
|
||||
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
|
||||
if err = updatePodContainers(params, args, envs, imagePullPolicy, &pod.Spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -835,7 +958,7 @@ func parseEnvs(envArray []string) ([]api.EnvVar, error) {
|
|||
}
|
||||
name := env[:pos]
|
||||
value := env[pos+1:]
|
||||
if len(name) == 0 || len(value) == 0 {
|
||||
if len(name) == 0 {
|
||||
return nil, fmt.Errorf("invalid env: %v", env)
|
||||
}
|
||||
if len(validation.IsCIdentifier(name)) != 0 {
|
||||
|
|
@ -856,7 +979,7 @@ func parseV1Envs(envArray []string) ([]v1.EnvVar, error) {
|
|||
}
|
||||
name := env[:pos]
|
||||
value := env[pos+1:]
|
||||
if len(name) == 0 || len(validation.IsCIdentifier(name)) != 0 || len(value) == 0 {
|
||||
if len(name) == 0 || len(validation.IsCIdentifier(name)) != 0 {
|
||||
return nil, fmt.Errorf("invalid env: %v", env)
|
||||
}
|
||||
envVar := v1.EnvVar{Name: name, Value: value}
|
||||
|
|
|
|||
203
vendor/k8s.io/kubernetes/pkg/kubectl/scale.go
generated
vendored
203
vendor/k8s.io/kubernetes/pkg/kubectl/scale.go
generated
vendored
|
|
@ -24,10 +24,13 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// Scaler provides an interface for resources that can be scaled.
|
||||
|
|
@ -36,9 +39,9 @@ type Scaler interface {
|
|||
// retries in the event of resource version mismatch (if retry is not nil),
|
||||
// and optionally waits until the status of the resource matches newSize (if wait is not nil)
|
||||
Scale(namespace, name string, newSize uint, preconditions *ScalePrecondition, retry, wait *RetryParams) error
|
||||
// ScaleSimple does a simple one-shot attempt at scaling - not useful on it's own, but
|
||||
// ScaleSimple does a simple one-shot attempt at scaling - not useful on its own, but
|
||||
// a necessary building block for Scale
|
||||
ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error
|
||||
ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (updatedResourceVersion string, err error)
|
||||
}
|
||||
|
||||
func ScalerFor(kind unversioned.GroupKind, c client.Interface) (Scaler, error) {
|
||||
|
|
@ -49,6 +52,8 @@ func ScalerFor(kind unversioned.GroupKind, c client.Interface) (Scaler, error) {
|
|||
return &ReplicaSetScaler{c.Extensions()}, nil
|
||||
case extensions.Kind("Job"), batch.Kind("Job"):
|
||||
return &JobScaler{c.Batch()}, nil // Either kind of job can be scaled with Batch interface.
|
||||
case apps.Kind("PetSet"):
|
||||
return &PetSetScaler{c.Apps()}, nil
|
||||
case extensions.Kind("Deployment"):
|
||||
return &DeploymentScaler{c.Extensions()}, nil
|
||||
}
|
||||
|
|
@ -108,9 +113,12 @@ func NewRetryParams(interval, timeout time.Duration) *RetryParams {
|
|||
}
|
||||
|
||||
// ScaleCondition is a closure around Scale that facilitates retries via util.wait
|
||||
func ScaleCondition(r Scaler, precondition *ScalePrecondition, namespace, name string, count uint) wait.ConditionFunc {
|
||||
func ScaleCondition(r Scaler, precondition *ScalePrecondition, namespace, name string, count uint, updatedResourceVersion *string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := r.ScaleSimple(namespace, name, precondition, count)
|
||||
rv, err := r.ScaleSimple(namespace, name, precondition, count)
|
||||
if updatedResourceVersion != nil {
|
||||
*updatedResourceVersion = rv
|
||||
}
|
||||
switch e, _ := err.(ScaleError); err.(type) {
|
||||
case nil:
|
||||
return true, nil
|
||||
|
|
@ -124,6 +132,17 @@ func ScaleCondition(r Scaler, precondition *ScalePrecondition, namespace, name s
|
|||
}
|
||||
}
|
||||
|
||||
// ValidatePetSet ensures that the preconditions match. Returns nil if they are valid, an error otherwise.
|
||||
func (precondition *ScalePrecondition) ValidatePetSet(ps *apps.PetSet) error {
|
||||
if precondition.Size != -1 && int(ps.Spec.Replicas) != precondition.Size {
|
||||
return PreconditionError{"replicas", strconv.Itoa(precondition.Size), strconv.Itoa(int(ps.Spec.Replicas))}
|
||||
}
|
||||
if len(precondition.ResourceVersion) != 0 && ps.ResourceVersion != precondition.ResourceVersion {
|
||||
return PreconditionError{"resource version", precondition.ResourceVersion, ps.ResourceVersion}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateReplicationController ensures that the preconditions match. Returns nil if they are valid, an error otherwise
|
||||
func (precondition *ScalePrecondition) ValidateReplicationController(controller *api.ReplicationController) error {
|
||||
if precondition.Size != -1 && int(controller.Spec.Replicas) != precondition.Size {
|
||||
|
|
@ -139,24 +158,27 @@ type ReplicationControllerScaler struct {
|
|||
c client.Interface
|
||||
}
|
||||
|
||||
func (scaler *ReplicationControllerScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error {
|
||||
// ScaleSimple does a simple one-shot attempt at scaling. It returns the
|
||||
// resourceVersion of the replication controller if the update is successful.
|
||||
func (scaler *ReplicationControllerScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) {
|
||||
controller, err := scaler.c.ReplicationControllers(namespace).Get(name)
|
||||
if err != nil {
|
||||
return ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
return "", ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
}
|
||||
if preconditions != nil {
|
||||
if err := preconditions.ValidateReplicationController(controller); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
controller.Spec.Replicas = int32(newSize)
|
||||
if _, err := scaler.c.ReplicationControllers(namespace).Update(controller); err != nil {
|
||||
updatedRC, err := scaler.c.ReplicationControllers(namespace).Update(controller)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
return ScaleError{ScaleUpdateConflictFailure, controller.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateConflictFailure, controller.ResourceVersion, err}
|
||||
}
|
||||
return ScaleError{ScaleUpdateFailure, controller.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateFailure, controller.ResourceVersion, err}
|
||||
}
|
||||
return nil
|
||||
return updatedRC.ObjectMeta.ResourceVersion, nil
|
||||
}
|
||||
|
||||
// Scale updates a ReplicationController to a new size, with optional precondition check (if preconditions is not nil),
|
||||
|
|
@ -170,20 +192,51 @@ func (scaler *ReplicationControllerScaler) Scale(namespace, name string, newSize
|
|||
// Make it try only once, immediately
|
||||
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
|
||||
}
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize)
|
||||
if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
var updatedResourceVersion string
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize, &updatedResourceVersion)
|
||||
if err := wait.PollImmediate(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
if waitForReplicas != nil {
|
||||
rc, err := scaler.c.ReplicationControllers(namespace).Get(name)
|
||||
checkRC := func(rc *api.ReplicationController) bool {
|
||||
if uint(rc.Spec.Replicas) != newSize {
|
||||
// the size is changed by other party. Don't need to wait for the new change to complete.
|
||||
return true
|
||||
}
|
||||
return rc.Status.ObservedGeneration >= rc.Generation && rc.Status.Replicas == rc.Spec.Replicas
|
||||
}
|
||||
// If number of replicas doesn't change, then the update may not event
|
||||
// be sent to underlying databse (we don't send no-op changes).
|
||||
// In such case, <updatedResourceVersion> will have value of the most
|
||||
// recent update (which may be far in the past) so we may get "too old
|
||||
// RV" error from watch or potentially no ReplicationController events
|
||||
// will be deliver, since it may already be in the expected state.
|
||||
// To protect from these two, we first issue Get() to ensure that we
|
||||
// are not already in the expected state.
|
||||
currentRC, err := scaler.c.ReplicationControllers(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wait.Poll(waitForReplicas.Interval, waitForReplicas.Timeout, client.ControllerHasDesiredReplicas(scaler.c, rc))
|
||||
if err == wait.ErrWaitTimeout {
|
||||
return fmt.Errorf("timed out waiting for %q to be synced", name)
|
||||
if !checkRC(currentRC) {
|
||||
watchOptions := api.ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("metadata.name", name),
|
||||
ResourceVersion: updatedResourceVersion,
|
||||
}
|
||||
watcher, err := scaler.c.ReplicationControllers(namespace).Watch(watchOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = watch.Until(waitForReplicas.Timeout, watcher, func(event watch.Event) (bool, error) {
|
||||
if event.Type != watch.Added && event.Type != watch.Modified {
|
||||
return false, nil
|
||||
}
|
||||
return checkRC(event.Object.(*api.ReplicationController)), nil
|
||||
})
|
||||
if err == wait.ErrWaitTimeout {
|
||||
return fmt.Errorf("timed out waiting for %q to be synced", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -203,24 +256,27 @@ type ReplicaSetScaler struct {
|
|||
c client.ExtensionsInterface
|
||||
}
|
||||
|
||||
func (scaler *ReplicaSetScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error {
|
||||
// ScaleSimple does a simple one-shot attempt at scaling. It returns the
|
||||
// resourceVersion of the replicaset if the update is successful.
|
||||
func (scaler *ReplicaSetScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) {
|
||||
rs, err := scaler.c.ReplicaSets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
return "", ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
}
|
||||
if preconditions != nil {
|
||||
if err := preconditions.ValidateReplicaSet(rs); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
rs.Spec.Replicas = int32(newSize)
|
||||
if _, err := scaler.c.ReplicaSets(namespace).Update(rs); err != nil {
|
||||
updatedRS, err := scaler.c.ReplicaSets(namespace).Update(rs)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
return ScaleError{ScaleUpdateConflictFailure, rs.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateConflictFailure, rs.ResourceVersion, err}
|
||||
}
|
||||
return ScaleError{ScaleUpdateFailure, rs.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateFailure, rs.ResourceVersion, err}
|
||||
}
|
||||
return nil
|
||||
return updatedRS.ObjectMeta.ResourceVersion, nil
|
||||
}
|
||||
|
||||
// Scale updates a ReplicaSet to a new size, with optional precondition check (if preconditions is
|
||||
|
|
@ -234,7 +290,7 @@ func (scaler *ReplicaSetScaler) Scale(namespace, name string, newSize uint, prec
|
|||
// Make it try only once, immediately
|
||||
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
|
||||
}
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize)
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize, nil)
|
||||
if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -244,6 +300,7 @@ func (scaler *ReplicaSetScaler) Scale(namespace, name string, newSize uint, prec
|
|||
return err
|
||||
}
|
||||
err = wait.Poll(waitForReplicas.Interval, waitForReplicas.Timeout, client.ReplicaSetHasDesiredReplicas(scaler.c, rs))
|
||||
|
||||
if err == wait.ErrWaitTimeout {
|
||||
return fmt.Errorf("timed out waiting for %q to be synced", name)
|
||||
}
|
||||
|
|
@ -266,30 +323,85 @@ func (precondition *ScalePrecondition) ValidateJob(job *batch.Job) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type PetSetScaler struct {
|
||||
c client.AppsInterface
|
||||
}
|
||||
|
||||
// ScaleSimple does a simple one-shot attempt at scaling. It returns the
|
||||
// resourceVersion of the petset if the update is successful.
|
||||
func (scaler *PetSetScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) {
|
||||
ps, err := scaler.c.PetSets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return "", ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
}
|
||||
if preconditions != nil {
|
||||
if err := preconditions.ValidatePetSet(ps); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
ps.Spec.Replicas = int(newSize)
|
||||
updatedPetSet, err := scaler.c.PetSets(namespace).Update(ps)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
return "", ScaleError{ScaleUpdateConflictFailure, ps.ResourceVersion, err}
|
||||
}
|
||||
return "", ScaleError{ScaleUpdateFailure, ps.ResourceVersion, err}
|
||||
}
|
||||
return updatedPetSet.ResourceVersion, nil
|
||||
}
|
||||
|
||||
func (scaler *PetSetScaler) Scale(namespace, name string, newSize uint, preconditions *ScalePrecondition, retry, waitForReplicas *RetryParams) error {
|
||||
if preconditions == nil {
|
||||
preconditions = &ScalePrecondition{-1, ""}
|
||||
}
|
||||
if retry == nil {
|
||||
// Make it try only once, immediately
|
||||
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
|
||||
}
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize, nil)
|
||||
if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
if waitForReplicas != nil {
|
||||
job, err := scaler.c.PetSets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = wait.Poll(waitForReplicas.Interval, waitForReplicas.Timeout, client.PetSetHasDesiredPets(scaler.c, job))
|
||||
if err == wait.ErrWaitTimeout {
|
||||
return fmt.Errorf("timed out waiting for %q to be synced", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type JobScaler struct {
|
||||
c client.BatchInterface
|
||||
}
|
||||
|
||||
// ScaleSimple is responsible for updating job's parallelism.
|
||||
func (scaler *JobScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error {
|
||||
// ScaleSimple is responsible for updating job's parallelism. It returns the
|
||||
// resourceVersion of the job if the update is successful.
|
||||
func (scaler *JobScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) {
|
||||
job, err := scaler.c.Jobs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
return "", ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
}
|
||||
if preconditions != nil {
|
||||
if err := preconditions.ValidateJob(job); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
parallelism := int32(newSize)
|
||||
job.Spec.Parallelism = ¶llelism
|
||||
if _, err := scaler.c.Jobs(namespace).Update(job); err != nil {
|
||||
udpatedJob, err := scaler.c.Jobs(namespace).Update(job)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
return ScaleError{ScaleUpdateConflictFailure, job.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateConflictFailure, job.ResourceVersion, err}
|
||||
}
|
||||
return ScaleError{ScaleUpdateFailure, job.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateFailure, job.ResourceVersion, err}
|
||||
}
|
||||
return nil
|
||||
return udpatedJob.ObjectMeta.ResourceVersion, nil
|
||||
}
|
||||
|
||||
// Scale updates a Job to a new size, with optional precondition check (if preconditions is not nil),
|
||||
|
|
@ -303,7 +415,7 @@ func (scaler *JobScaler) Scale(namespace, name string, newSize uint, preconditio
|
|||
// Make it try only once, immediately
|
||||
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
|
||||
}
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize)
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize, nil)
|
||||
if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -336,28 +448,31 @@ type DeploymentScaler struct {
|
|||
c client.ExtensionsInterface
|
||||
}
|
||||
|
||||
// ScaleSimple is responsible for updating a deployment's desired replicas count.
|
||||
func (scaler *DeploymentScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error {
|
||||
// ScaleSimple is responsible for updating a deployment's desired replicas
|
||||
// count. It returns the resourceVersion of the deployment if the update is
|
||||
// successful.
|
||||
func (scaler *DeploymentScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) {
|
||||
deployment, err := scaler.c.Deployments(namespace).Get(name)
|
||||
if err != nil {
|
||||
return ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
return "", ScaleError{ScaleGetFailure, "Unknown", err}
|
||||
}
|
||||
if preconditions != nil {
|
||||
if err := preconditions.ValidateDeployment(deployment); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Fix this when Scale group issues are resolved (see issue #18528).
|
||||
// For now I'm falling back to regular Deployment update operation.
|
||||
deployment.Spec.Replicas = int32(newSize)
|
||||
if _, err := scaler.c.Deployments(namespace).Update(deployment); err != nil {
|
||||
updatedDeployment, err := scaler.c.Deployments(namespace).Update(deployment)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
return ScaleError{ScaleUpdateConflictFailure, deployment.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateConflictFailure, deployment.ResourceVersion, err}
|
||||
}
|
||||
return ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err}
|
||||
return "", ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err}
|
||||
}
|
||||
return nil
|
||||
return updatedDeployment.ObjectMeta.ResourceVersion, nil
|
||||
}
|
||||
|
||||
// Scale updates a deployment to a new size, with optional precondition check (if preconditions is not nil),
|
||||
|
|
@ -370,7 +485,7 @@ func (scaler *DeploymentScaler) Scale(namespace, name string, newSize uint, prec
|
|||
// Make it try only once, immediately
|
||||
retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond}
|
||||
}
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize)
|
||||
cond := ScaleCondition(scaler, preconditions, namespace, name, newSize, nil)
|
||||
if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
16
vendor/k8s.io/kubernetes/pkg/kubectl/service.go
generated
vendored
16
vendor/k8s.io/kubernetes/pkg/kubectl/service.go
generated
vendored
|
|
@ -72,6 +72,7 @@ func paramNames() []GeneratorParam {
|
|||
{"target-port", false},
|
||||
{"port-name", false},
|
||||
{"session-affinity", false},
|
||||
{"cluster-ip", false},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,11 +181,11 @@ func generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
|||
Ports: ports,
|
||||
},
|
||||
}
|
||||
targetPortString, found := params["target-port"]
|
||||
if !found {
|
||||
targetPortString, found = params["container-port"]
|
||||
targetPortString := params["target-port"]
|
||||
if len(targetPortString) == 0 {
|
||||
targetPortString = params["container-port"]
|
||||
}
|
||||
if found && len(targetPortString) > 0 {
|
||||
if len(targetPortString) > 0 {
|
||||
var targetPort intstr.IntOrString
|
||||
if portNum, err := strconv.Atoi(targetPortString); err != nil {
|
||||
targetPort = intstr.FromString(targetPortString)
|
||||
|
|
@ -225,5 +226,12 @@ func generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
|||
return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"])
|
||||
}
|
||||
}
|
||||
if len(params["cluster-ip"]) != 0 {
|
||||
if params["cluster-ip"] == "None" {
|
||||
service.Spec.ClusterIP = api.ClusterIPNone
|
||||
} else {
|
||||
service.Spec.ClusterIP = params["cluster-ip"]
|
||||
}
|
||||
}
|
||||
return &service, nil
|
||||
}
|
||||
|
|
|
|||
207
vendor/k8s.io/kubernetes/pkg/kubectl/service_basic.go
generated
vendored
Normal file
207
vendor/k8s.io/kubernetes/pkg/kubectl/service_basic.go
generated
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
)
|
||||
|
||||
type ServiceCommonGeneratorV1 struct {
|
||||
Name string
|
||||
TCP []string
|
||||
Type api.ServiceType
|
||||
ClusterIP string
|
||||
}
|
||||
|
||||
type ServiceClusterIPGeneratorV1 struct {
|
||||
ServiceCommonGeneratorV1
|
||||
}
|
||||
|
||||
type ServiceNodePortGeneratorV1 struct {
|
||||
ServiceCommonGeneratorV1
|
||||
}
|
||||
|
||||
type ServiceLoadBalancerGeneratorV1 struct {
|
||||
ServiceCommonGeneratorV1
|
||||
}
|
||||
|
||||
func (ServiceClusterIPGeneratorV1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"name", true},
|
||||
{"tcp", true},
|
||||
{"clusterip", false},
|
||||
}
|
||||
}
|
||||
func (ServiceNodePortGeneratorV1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"name", true},
|
||||
{"tcp", true},
|
||||
}
|
||||
}
|
||||
func (ServiceLoadBalancerGeneratorV1) ParamNames() []GeneratorParam {
|
||||
return []GeneratorParam{
|
||||
{"name", true},
|
||||
{"tcp", true},
|
||||
}
|
||||
}
|
||||
|
||||
func parsePorts(portString string) (int32, intstr.IntOrString, error) {
|
||||
portStringSlice := strings.Split(portString, ":")
|
||||
|
||||
port, err := strconv.Atoi(portStringSlice[0])
|
||||
if err != nil {
|
||||
return 0, intstr.FromInt(0), err
|
||||
}
|
||||
if len(portStringSlice) == 1 {
|
||||
return int32(port), intstr.FromInt(int(port)), nil
|
||||
}
|
||||
|
||||
var targetPort intstr.IntOrString
|
||||
if portNum, err := strconv.Atoi(portStringSlice[1]); err != nil {
|
||||
targetPort = intstr.FromString(portStringSlice[1])
|
||||
} else {
|
||||
targetPort = intstr.FromInt(portNum)
|
||||
}
|
||||
return int32(port), targetPort, nil
|
||||
}
|
||||
|
||||
func (s ServiceCommonGeneratorV1) GenerateCommon(params map[string]interface{}) error {
|
||||
name, isString := params["name"].(string)
|
||||
if !isString {
|
||||
return fmt.Errorf("expected string, saw %v for 'name'", name)
|
||||
}
|
||||
tcpStrings, isArray := params["tcp"].([]string)
|
||||
if !isArray {
|
||||
return fmt.Errorf("expected []string, found :%v", tcpStrings)
|
||||
}
|
||||
clusterip, isString := params["clusterip"].(string)
|
||||
if !isString {
|
||||
return fmt.Errorf("expected string, saw %v for 'clusterip'", clusterip)
|
||||
}
|
||||
s.Name = name
|
||||
s.TCP = tcpStrings
|
||||
s.ClusterIP = clusterip
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s ServiceLoadBalancerGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
|
||||
err := ValidateParams(s.ParamNames(), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delegate := &ServiceCommonGeneratorV1{Type: api.ServiceTypeLoadBalancer, ClusterIP: ""}
|
||||
err = delegate.GenerateCommon(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.StructuredGenerate()
|
||||
}
|
||||
|
||||
func (s ServiceNodePortGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
|
||||
err := ValidateParams(s.ParamNames(), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delegate := &ServiceCommonGeneratorV1{Type: api.ServiceTypeNodePort, ClusterIP: ""}
|
||||
err = delegate.GenerateCommon(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.StructuredGenerate()
|
||||
}
|
||||
|
||||
func (s ServiceClusterIPGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
|
||||
err := ValidateParams(s.ParamNames(), params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delegate := &ServiceCommonGeneratorV1{Type: api.ServiceTypeClusterIP, ClusterIP: ""}
|
||||
err = delegate.GenerateCommon(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.StructuredGenerate()
|
||||
}
|
||||
|
||||
// validate validates required fields are set to support structured generation
|
||||
func (s ServiceCommonGeneratorV1) validate() error {
|
||||
if len(s.Name) == 0 {
|
||||
return fmt.Errorf("name must be specified")
|
||||
}
|
||||
if len(s.Type) == 0 {
|
||||
return fmt.Errorf("type must be specified")
|
||||
}
|
||||
if s.ClusterIP == api.ClusterIPNone && s.Type != api.ServiceTypeClusterIP {
|
||||
return fmt.Errorf("ClusterIP=None can only be used with ClusterIP service type")
|
||||
}
|
||||
if s.ClusterIP == api.ClusterIPNone && len(s.TCP) > 0 {
|
||||
return fmt.Errorf("can not map ports with clusterip=None")
|
||||
}
|
||||
if s.ClusterIP != api.ClusterIPNone && len(s.TCP) == 0 {
|
||||
return fmt.Errorf("at least one tcp port specifier must be provided")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) {
|
||||
err := s.validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ports := []api.ServicePort{}
|
||||
for _, tcpString := range s.TCP {
|
||||
port, targetPort, err := parsePorts(tcpString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
portName := strings.Replace(tcpString, ":", "-", -1)
|
||||
ports = append(ports, api.ServicePort{
|
||||
Name: portName,
|
||||
Port: port,
|
||||
TargetPort: targetPort,
|
||||
Protocol: api.Protocol("TCP"),
|
||||
})
|
||||
}
|
||||
|
||||
// setup default label and selector
|
||||
labels := map[string]string{}
|
||||
labels["app"] = s.Name
|
||||
selector := map[string]string{}
|
||||
selector["app"] = s.Name
|
||||
|
||||
service := api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: s.Name,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceType(s.Type),
|
||||
Selector: selector,
|
||||
Ports: ports,
|
||||
},
|
||||
}
|
||||
if len(s.ClusterIP) > 0 {
|
||||
service.Spec.ClusterIP = s.ClusterIP
|
||||
}
|
||||
return &service, nil
|
||||
}
|
||||
4
vendor/k8s.io/kubernetes/pkg/kubectl/sorting_printer.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/kubectl/sorting_printer.go
generated
vendored
|
|
@ -40,6 +40,10 @@ type SortingPrinter struct {
|
|||
Decoder runtime.Decoder
|
||||
}
|
||||
|
||||
func (s *SortingPrinter) FinishPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
if !meta.IsListType(obj) {
|
||||
return s.Delegate.PrintObj(obj, out)
|
||||
|
|
|
|||
83
vendor/k8s.io/kubernetes/pkg/kubectl/stop.go
generated
vendored
83
vendor/k8s.io/kubernetes/pkg/kubectl/stop.go
generated
vendored
|
|
@ -25,6 +25,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
|
|
@ -32,6 +33,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
|
|
@ -81,6 +83,9 @@ func ReaperFor(kind unversioned.GroupKind, c client.Interface) (Reaper, error) {
|
|||
case extensions.Kind("Job"), batch.Kind("Job"):
|
||||
return &JobReaper{c, Interval, Timeout}, nil
|
||||
|
||||
case apps.Kind("PetSet"):
|
||||
return &PetSetReaper{c, Interval, Timeout}, nil
|
||||
|
||||
case extensions.Kind("Deployment"):
|
||||
return &DeploymentReaper{c, Interval, Timeout}, nil
|
||||
|
||||
|
|
@ -118,6 +123,10 @@ type PodReaper struct {
|
|||
type ServiceReaper struct {
|
||||
client.Interface
|
||||
}
|
||||
type PetSetReaper struct {
|
||||
client.Interface
|
||||
pollInterval, timeout time.Duration
|
||||
}
|
||||
|
||||
type objInterface interface {
|
||||
Delete(name string) error
|
||||
|
|
@ -201,7 +210,9 @@ func (reaper *ReplicationControllerReaper) Stop(namespace, name string, timeout
|
|||
return err
|
||||
}
|
||||
}
|
||||
return rc.Delete(name)
|
||||
falseVar := false
|
||||
deleteOptions := &api.DeleteOptions{OrphanDependents: &falseVar}
|
||||
return rc.Delete(name, deleteOptions)
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Implement it when controllerRef is implemented - https://github.com/kubernetes/kubernetes/issues/2210
|
||||
|
|
@ -273,10 +284,9 @@ func (reaper *ReplicaSetReaper) Stop(namespace, name string, timeout time.Durati
|
|||
}
|
||||
}
|
||||
|
||||
if err := rsc.Delete(name, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
falseVar := false
|
||||
deleteOptions := &api.DeleteOptions{OrphanDependents: &falseVar}
|
||||
return rsc.Delete(name, deleteOptions)
|
||||
}
|
||||
|
||||
func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error {
|
||||
|
|
@ -290,7 +300,7 @@ func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duratio
|
|||
// daemon pods. Once it's done deleting the daemon pods, it's safe to delete
|
||||
// the DaemonSet.
|
||||
ds.Spec.Template.Spec.NodeSelector = map[string]string{
|
||||
string(util.NewUUID()): string(util.NewUUID()),
|
||||
string(uuid.NewUUID()): string(uuid.NewUUID()),
|
||||
}
|
||||
// force update to avoid version conflict
|
||||
ds.ResourceVersion = ""
|
||||
|
|
@ -305,6 +315,7 @@ func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duratio
|
|||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return updatedDS.Status.CurrentNumberScheduled+updatedDS.Status.NumberMisscheduled == 0, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
|
|
@ -313,6 +324,53 @@ func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duratio
|
|||
return reaper.Extensions().DaemonSets(namespace).Delete(name)
|
||||
}
|
||||
|
||||
func (reaper *PetSetReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error {
|
||||
petsets := reaper.Apps().PetSets(namespace)
|
||||
scaler, err := ScalerFor(apps.Kind("PetSet"), *reaper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps, err := petsets.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if timeout == 0 {
|
||||
numPets := ps.Spec.Replicas
|
||||
timeout = Timeout + time.Duration(10*numPets)*time.Second
|
||||
}
|
||||
retry := NewRetryParams(reaper.pollInterval, reaper.timeout)
|
||||
waitForPetSet := NewRetryParams(reaper.pollInterval, reaper.timeout)
|
||||
if err = scaler.Scale(namespace, name, 0, nil, retry, waitForPetSet); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: This shouldn't be needed, see corresponding TODO in PetSetHasDesiredPets.
|
||||
// PetSet should track generation number.
|
||||
pods := reaper.Pods(namespace)
|
||||
selector, _ := unversioned.LabelSelectorAsSelector(ps.Spec.Selector)
|
||||
options := api.ListOptions{LabelSelector: selector}
|
||||
podList, err := pods.List(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errList := []error{}
|
||||
for _, pod := range podList.Items {
|
||||
if err := pods.Delete(pod.Name, gracePeriod); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errList) > 0 {
|
||||
return utilerrors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
// TODO: Cleanup volumes? We don't want to accidentally delete volumes from
|
||||
// stop, so just leave this up to the the petset.
|
||||
return petsets.Delete(name, nil)
|
||||
}
|
||||
|
||||
func (reaper *JobReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error {
|
||||
jobs := reaper.Batch().Jobs(namespace)
|
||||
pods := reaper.Pods(namespace)
|
||||
|
|
@ -397,9 +455,10 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
|
|||
for _, rc := range rsList.Items {
|
||||
if err := rsReaper.Stop(rc.Namespace, rc.Name, timeout, gracePeriod); err != nil {
|
||||
scaleGetErr, ok := err.(*ScaleError)
|
||||
if !errors.IsNotFound(err) || ok && !errors.IsNotFound(scaleGetErr.ActualError) {
|
||||
errList = append(errList, err)
|
||||
if errors.IsNotFound(err) || (ok && errors.IsNotFound(scaleGetErr.ActualError)) {
|
||||
continue
|
||||
}
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if len(errList) > 0 {
|
||||
|
|
@ -407,7 +466,7 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
|
|||
}
|
||||
|
||||
// Delete deployment at the end.
|
||||
// Note: We delete deployment at the end so that if removing RSs fails, we atleast have the deployment to retry.
|
||||
// Note: We delete deployment at the end so that if removing RSs fails, we at least have the deployment to retry.
|
||||
return deployments.Delete(name, nil)
|
||||
}
|
||||
|
||||
|
|
@ -424,7 +483,11 @@ func (reaper *DeploymentReaper) updateDeploymentWithRetries(namespace, name stri
|
|||
if deployment, err = deployments.Update(deployment); err == nil {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
// Retry only on update conflict.
|
||||
if errors.IsConflict(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
})
|
||||
return deployment, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue