mirror of https://github.com/k3s-io/k3s
Merge pull request #21966 from madhusudancs/scale-deployment-replicaset
Auto commit by PR queue botpull/6/head
commit
a435537e27
|
@ -1654,6 +1654,168 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale",
|
||||
"description": "API at /apis/extensions/v1beta1",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "GET",
|
||||
"summary": "read scale of the specified Scale",
|
||||
"nickname": "readNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "PUT",
|
||||
"summary": "replace scale of the specified Scale",
|
||||
"nickname": "replaceNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "PATCH",
|
||||
"summary": "partially update scale of the specified Scale",
|
||||
"nickname": "patchNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "unversioned.Patch",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/merge-patch+json",
|
||||
"application/strategic-merge-patch+json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/status",
|
||||
"description": "API at /apis/extensions/v1beta1",
|
||||
|
@ -4954,6 +5116,168 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale",
|
||||
"description": "API at /apis/extensions/v1beta1",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "GET",
|
||||
"summary": "read scale of the specified Scale",
|
||||
"nickname": "readNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "PUT",
|
||||
"summary": "replace scale of the specified Scale",
|
||||
"nickname": "replaceNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"method": "PATCH",
|
||||
"summary": "partially update scale of the specified Scale",
|
||||
"nickname": "patchNamespacedScaleScale",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "unversioned.Patch",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "namespace",
|
||||
"description": "object name and auth scope, such as for teams and projects",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "path",
|
||||
"name": "name",
|
||||
"description": "name of the Scale",
|
||||
"required": true,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/merge-patch+json",
|
||||
"application/strategic-merge-patch+json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/status",
|
||||
"description": "API at /apis/extensions/v1beta1",
|
||||
|
@ -6910,6 +7234,61 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.Scale": {
|
||||
"id": "v1.Scale",
|
||||
"description": "Scale represents a scaling request for a resource.",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "v1.ObjectMeta",
|
||||
"description": "Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata."
|
||||
},
|
||||
"spec": {
|
||||
"$ref": "v1.ScaleSpec",
|
||||
"description": "defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status."
|
||||
},
|
||||
"status": {
|
||||
"$ref": "v1.ScaleStatus",
|
||||
"description": "current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.ScaleSpec": {
|
||||
"id": "v1.ScaleSpec",
|
||||
"description": "ScaleSpec describes the attributes of a scale subresource.",
|
||||
"properties": {
|
||||
"replicas": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "desired number of instances for the scaled object."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.ScaleStatus": {
|
||||
"id": "v1.ScaleStatus",
|
||||
"description": "ScaleStatus represents the current status of a scale subresource.",
|
||||
"required": [
|
||||
"replicas"
|
||||
],
|
||||
"properties": {
|
||||
"replicas": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "actual number of observed instances of the scaled object."
|
||||
},
|
||||
"selector": {
|
||||
"type": "string",
|
||||
"description": "label query over pods that should match the replicas count. This is same as the label selector but in the string format to avoid introspection by clients. The string will be in the same format as the query-param syntax. More info about label selectors: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.HorizontalPodAutoscalerList": {
|
||||
"id": "v1beta1.HorizontalPodAutoscalerList",
|
||||
"description": "list of horizontal pod autoscaler objects.",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 extensions
|
||||
|
||||
// TODO(madhusudancs): Fix this when Scale group issues are resolved (see issue #18528).
|
||||
// import (
|
||||
// "fmt"
|
||||
|
||||
// "k8s.io/kubernetes/pkg/api"
|
||||
// "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
// )
|
||||
|
||||
// // ScaleFromDeployment returns a scale subresource for a deployment.
|
||||
// func ScaleFromDeployment(deployment *Deployment) (*Scale, error) {
|
||||
// selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
// }
|
||||
// return &Scale{
|
||||
// ObjectMeta: api.ObjectMeta{
|
||||
// Name: deployment.Name,
|
||||
// Namespace: deployment.Namespace,
|
||||
// CreationTimestamp: deployment.CreationTimestamp,
|
||||
// },
|
||||
// Spec: ScaleSpec{
|
||||
// Replicas: deployment.Spec.Replicas,
|
||||
// },
|
||||
// Status: ScaleStatus{
|
||||
// Replicas: deployment.Status.Replicas,
|
||||
// Selector: selector.String(),
|
||||
// },
|
||||
// }, nil
|
||||
// }
|
|
@ -248,6 +248,12 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||
ParameterCodec: api.ParameterCodec,
|
||||
NegotiatedSerializer: api.Codecs,
|
||||
}
|
||||
if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) {
|
||||
apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{
|
||||
"deployments/scale": autoscalingGroupVersion.WithKind("Scale"),
|
||||
"replicasets/scale": autoscalingGroupVersion.WithKind("Scale"),
|
||||
}
|
||||
}
|
||||
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||
|
||||
extensionsGVForDiscovery := unversioned.GroupVersionForDiscovery{
|
||||
|
@ -716,9 +722,11 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
|
|||
deploymentStorage := deploymentetcd.NewStorage(restOptions("deployments"))
|
||||
storage["deployments"] = deploymentStorage.Deployment
|
||||
storage["deployments/status"] = deploymentStorage.Status
|
||||
// TODO(madhusudancs): Install scale when Scale group issues are fixed (see issue #18528).
|
||||
// storage["deployments/scale"] = deploymentStorage.Scale
|
||||
storage["deployments/rollback"] = deploymentStorage.Rollback
|
||||
|
||||
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) {
|
||||
storage["deployments/scale"] = deploymentStorage.Scale
|
||||
}
|
||||
}
|
||||
if isEnabled("jobs") {
|
||||
m.constructJobResources(c, storage)
|
||||
|
@ -736,6 +744,9 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
|
|||
replicaSetStorage := replicasetetcd.NewStorage(restOptions("replicasets"))
|
||||
storage["replicasets"] = replicaSetStorage.ReplicaSet
|
||||
storage["replicasets/status"] = replicaSetStorage.Status
|
||||
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) {
|
||||
storage["replicasets/scale"] = replicaSetStorage.Scale
|
||||
}
|
||||
}
|
||||
|
||||
return storage
|
||||
|
|
|
@ -23,6 +23,9 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
etcderr "k8s.io/kubernetes/pkg/api/errors/etcd"
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
asvalidation "k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
|
@ -50,7 +53,7 @@ func NewStorage(opts generic.RESTOptions) DeploymentStorage {
|
|||
return DeploymentStorage{
|
||||
Deployment: deploymentRest,
|
||||
Status: deploymentStatusRest,
|
||||
Scale: &ScaleREST{registry: &deploymentRegistry},
|
||||
Scale: &ScaleREST{registry: deploymentRegistry},
|
||||
Rollback: deploymentRollbackRest,
|
||||
}
|
||||
}
|
||||
|
@ -181,56 +184,80 @@ func (r *RollbackREST) setDeploymentRollback(ctx api.Context, deploymentID strin
|
|||
}
|
||||
|
||||
type ScaleREST struct {
|
||||
registry *deployment.Registry
|
||||
registry deployment.Registry
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Fix this when Scale group issues are resolved (see issue #18528).
|
||||
// ScaleREST implements Patcher
|
||||
var _ = rest.Patcher(&ScaleREST{})
|
||||
|
||||
// // ScaleREST implements Patcher
|
||||
// var _ = rest.Patcher(&ScaleREST{})
|
||||
// New creates a new Scale object
|
||||
func (r *ScaleREST) New() runtime.Object {
|
||||
return &autoscaling.Scale{}
|
||||
}
|
||||
|
||||
// // New creates a new Scale object
|
||||
// func (r *ScaleREST) New() runtime.Object {
|
||||
// return &extensions.Scale{}
|
||||
// }
|
||||
func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||
deployment, err := r.registry.GetDeployment(ctx, name)
|
||||
if err != nil {
|
||||
return nil, errors.NewNotFound(autoscaling.Resource("deployments/scale"), name)
|
||||
}
|
||||
scale, err := scaleFromDeployment(deployment)
|
||||
if err != nil {
|
||||
return nil, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
}
|
||||
return scale, nil
|
||||
}
|
||||
|
||||
// func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||
// deployment, err := (*r.registry).GetDeployment(ctx, name)
|
||||
// if err != nil {
|
||||
// return nil, errors.NewNotFound(extensions.Resource("deployments/scale"), name)
|
||||
// }
|
||||
// scale, err := extensions.ScaleFromDeployment(deployment)
|
||||
// if err != nil {
|
||||
// return nil, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
// }
|
||||
// return scale, nil
|
||||
// }
|
||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
if obj == nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||
}
|
||||
scale, ok := obj.(*autoscaling.Scale)
|
||||
if !ok {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("expected input object type to be Scale, but %T", obj))
|
||||
}
|
||||
|
||||
// func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
// if obj == nil {
|
||||
// return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||
// }
|
||||
// scale, ok := obj.(*extensions.Scale)
|
||||
// if !ok {
|
||||
// return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj))
|
||||
// }
|
||||
if errs := asvalidation.ValidateScale(scale); len(errs) > 0 {
|
||||
return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs)
|
||||
}
|
||||
|
||||
// if errs := extvalidation.ValidateScale(scale); len(errs) > 0 {
|
||||
// return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
||||
// }
|
||||
deployment, err := r.registry.GetDeployment(ctx, scale.Name)
|
||||
if err != nil {
|
||||
return nil, false, errors.NewNotFound(autoscaling.Resource("deployments/scale"), scale.Name)
|
||||
}
|
||||
deployment.Spec.Replicas = scale.Spec.Replicas
|
||||
deployment.ResourceVersion = scale.ResourceVersion
|
||||
deployment, err = r.registry.UpdateDeployment(ctx, deployment)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newScale, err := scaleFromDeployment(deployment)
|
||||
if err != nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
}
|
||||
return newScale, false, nil
|
||||
}
|
||||
|
||||
// deployment, err := (*r.registry).GetDeployment(ctx, scale.Name)
|
||||
// if err != nil {
|
||||
// return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name)
|
||||
// }
|
||||
// deployment.Spec.Replicas = scale.Spec.Replicas
|
||||
// deployment, err = (*r.registry).UpdateDeployment(ctx, deployment)
|
||||
// if err != nil {
|
||||
// return nil, false, errors.NewConflict(extensions.Resource("deployments/scale"), scale.Name, err)
|
||||
// }
|
||||
// newScale, err := extensions.ScaleFromDeployment(deployment)
|
||||
// if err != nil {
|
||||
// return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
// }
|
||||
// return newScale, false, nil
|
||||
// }
|
||||
// scaleFromDeployment returns a scale subresource for a deployment.
|
||||
func scaleFromDeployment(deployment *extensions.Deployment) (*autoscaling.Scale, error) {
|
||||
selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stored deployment object can't be represented in the form of a scale subresource because the label selector ('%v') can't be parsed: %v", deployment.Spec.Selector, err)
|
||||
}
|
||||
return &autoscaling.Scale{
|
||||
// TODO: Create a variant of ObjectMeta type that only contains the fields below.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: deployment.Name,
|
||||
Namespace: deployment.Namespace,
|
||||
UID: deployment.UID,
|
||||
ResourceVersion: deployment.ResourceVersion,
|
||||
CreationTimestamp: deployment.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: deployment.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Replicas: deployment.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
@ -32,8 +33,11 @@ import (
|
|||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
|
||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
const defaultReplicas = 100
|
||||
|
||||
func newStorage(t *testing.T) (*DeploymentStorage, *etcdtesting.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorage(t, extensions.GroupName)
|
||||
restOptions := generic.RESTOptions{etcdStorage, generic.UndecoratedStorage, 1}
|
||||
|
@ -180,73 +184,84 @@ func TestWatch(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO(madhusudancs): Fix this when Scale group issues are resolved (see issue #18528).
|
||||
func TestScaleGet(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
// func validNewScale() *extensions.Scale {
|
||||
// return &extensions.Scale{
|
||||
// ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
||||
// Spec: extensions.ScaleSpec{
|
||||
// Replicas: validDeployment.Spec.Replicas,
|
||||
// },
|
||||
// Status: extensions.ScaleStatus{
|
||||
// Replicas: validDeployment.Status.Replicas,
|
||||
// Selector: validDeployment.Spec.Template.Labels,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
var deployment extensions.Deployment
|
||||
ctx := api.WithNamespace(api.NewContext(), namespace)
|
||||
key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
||||
if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, &deployment, 0); err != nil {
|
||||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||
}
|
||||
|
||||
// var validScale = *validNewScale()
|
||||
selector, err := unversioned.LabelSelectorAsSelector(validDeployment.Spec.Selector)
|
||||
if err != nil {
|
||||
t.Errorf("invalid deployment selector %+v: %v", validDeployment.Spec.Selector, err)
|
||||
}
|
||||
want := &autoscaling.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
UID: deployment.UID,
|
||||
ResourceVersion: deployment.ResourceVersion,
|
||||
CreationTimestamp: deployment.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: validDeployment.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Replicas: validDeployment.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
},
|
||||
}
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
got := obj.(*autoscaling.Scale)
|
||||
if !api.Semantic.DeepEqual(want, got) {
|
||||
t.Errorf("unexpected scale: %s", util.ObjectDiff(want, got))
|
||||
}
|
||||
}
|
||||
|
||||
// func TestScaleGet(t *testing.T) {
|
||||
// storage, server := newStorage(t)
|
||||
// defer server.Terminate(t)
|
||||
func TestScaleUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
// ctx := api.WithNamespace(api.NewContext(), namespace)
|
||||
// key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
||||
// if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil {
|
||||
// t.Fatalf("unexpected error: %v", err)
|
||||
// }
|
||||
var deployment extensions.Deployment
|
||||
ctx := api.WithNamespace(api.NewContext(), namespace)
|
||||
key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
||||
if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, &deployment, 0); err != nil {
|
||||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||
}
|
||||
replicas := 12
|
||||
update := autoscaling.Scale{
|
||||
ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
}
|
||||
|
||||
// expect := &validScale
|
||||
// obj, err := storage.Scale.Get(ctx, name)
|
||||
// if err != nil {
|
||||
// t.Fatalf("unexpected error: %v", err)
|
||||
// }
|
||||
// scale := obj.(*extensions.Scale)
|
||||
// if e, a := expect, scale; !api.Semantic.DeepDerivative(e, a) {
|
||||
// t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a))
|
||||
// }
|
||||
// }
|
||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
||||
t.Fatalf("error updating scale %v: %v", update, err)
|
||||
}
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
scale := obj.(*autoscaling.Scale)
|
||||
if scale.Spec.Replicas != replicas {
|
||||
t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas)
|
||||
}
|
||||
|
||||
// func TestScaleUpdate(t *testing.T) {
|
||||
// storage, server := newStorage(t)
|
||||
// defer server.Terminate(t)
|
||||
update.ResourceVersion = deployment.ResourceVersion
|
||||
update.Spec.Replicas = 15
|
||||
|
||||
// ctx := api.WithNamespace(api.NewContext(), namespace)
|
||||
// key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
||||
// if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil {
|
||||
// t.Fatalf("unexpected error: %v", err)
|
||||
// }
|
||||
// replicas := 12
|
||||
// update := extensions.Scale{
|
||||
// ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
||||
// Spec: extensions.ScaleSpec{
|
||||
// Replicas: replicas,
|
||||
// },
|
||||
// }
|
||||
|
||||
// if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
||||
// t.Fatalf("unexpected error: %v", err)
|
||||
// }
|
||||
// obj, err := storage.Deployment.Get(ctx, name)
|
||||
// if err != nil {
|
||||
// t.Fatalf("unexpected error: %v", err)
|
||||
// }
|
||||
// deployment := obj.(*extensions.Deployment)
|
||||
// if deployment.Spec.Replicas != replicas {
|
||||
// t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas)
|
||||
// }
|
||||
// }
|
||||
if _, _, err = storage.Scale.Update(ctx, &update); err != nil && !errors.IsConflict(err) {
|
||||
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
|
@ -260,10 +275,10 @@ func TestStatusUpdate(t *testing.T) {
|
|||
update := extensions.Deployment{
|
||||
ObjectMeta: validDeployment.ObjectMeta,
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: 100,
|
||||
Replicas: defaultReplicas,
|
||||
},
|
||||
Status: extensions.DeploymentStatus{
|
||||
Replicas: 100,
|
||||
Replicas: defaultReplicas,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -279,8 +294,8 @@ func TestStatusUpdate(t *testing.T) {
|
|||
if deployment.Spec.Replicas != 7 {
|
||||
t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", deployment.Spec.Replicas)
|
||||
}
|
||||
if deployment.Status.Replicas != 100 {
|
||||
t.Errorf("we expected .status.replicas to be updated to 100 but it was %v", deployment.Status.Replicas)
|
||||
if deployment.Status.Replicas != defaultReplicas {
|
||||
t.Errorf("we expected .status.replicas to be updated to %d but it was %v", defaultReplicas, deployment.Status.Replicas)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,14 @@ limitations under the License.
|
|||
package etcd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
asvalidation "k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
@ -34,14 +41,17 @@ import (
|
|||
type ReplicaSetStorage struct {
|
||||
ReplicaSet *REST
|
||||
Status *StatusREST
|
||||
Scale *ScaleREST
|
||||
}
|
||||
|
||||
func NewStorage(opts generic.RESTOptions) ReplicaSetStorage {
|
||||
replicaSetRest, replicaSetStatusRest := NewREST(opts)
|
||||
replicaSetRegistry := replicaset.NewRegistry(replicaSetRest)
|
||||
|
||||
return ReplicaSetStorage{
|
||||
ReplicaSet: replicaSetRest,
|
||||
Status: replicaSetStatusRest,
|
||||
Scale: &ScaleREST{registry: replicaSetRegistry},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,3 +120,82 @@ func (r *StatusREST) New() runtime.Object {
|
|||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
return r.store.Update(ctx, obj)
|
||||
}
|
||||
|
||||
type ScaleREST struct {
|
||||
registry replicaset.Registry
|
||||
}
|
||||
|
||||
// ScaleREST implements Patcher
|
||||
var _ = rest.Patcher(&ScaleREST{})
|
||||
|
||||
// New creates a new Scale object
|
||||
func (r *ScaleREST) New() runtime.Object {
|
||||
return &autoscaling.Scale{}
|
||||
}
|
||||
|
||||
func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||
rs, err := r.registry.GetReplicaSet(ctx, name)
|
||||
if err != nil {
|
||||
return nil, errors.NewNotFound(autoscaling.Resource("replicasets/scale"), name)
|
||||
}
|
||||
scale, err := scaleFromReplicaSet(rs)
|
||||
if err != nil {
|
||||
return nil, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
}
|
||||
return scale, err
|
||||
}
|
||||
|
||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
if obj == nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||
}
|
||||
scale, ok := obj.(*autoscaling.Scale)
|
||||
if !ok {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj))
|
||||
}
|
||||
|
||||
if errs := asvalidation.ValidateScale(scale); len(errs) > 0 {
|
||||
return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs)
|
||||
}
|
||||
|
||||
rs, err := r.registry.GetReplicaSet(ctx, scale.Name)
|
||||
if err != nil {
|
||||
return nil, false, errors.NewNotFound(autoscaling.Resource("replicasets/scale"), scale.Name)
|
||||
}
|
||||
rs.Spec.Replicas = scale.Spec.Replicas
|
||||
rs.ResourceVersion = scale.ResourceVersion
|
||||
rs, err = r.registry.UpdateReplicaSet(ctx, rs)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newScale, err := scaleFromReplicaSet(rs)
|
||||
if err != nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err))
|
||||
}
|
||||
return newScale, false, err
|
||||
}
|
||||
|
||||
// scaleFromReplicaSet returns a scale subresource for a replica set.
|
||||
func scaleFromReplicaSet(rs *extensions.ReplicaSet) (*autoscaling.Scale, error) {
|
||||
selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stored replica set object can't be represented in the form of a scale subresource because the label selector ('%v') can't be parsed: %v", rs.Spec.Selector, err)
|
||||
}
|
||||
return &autoscaling.Scale{
|
||||
// TODO: Create a variant of ObjectMeta type that only contains the fields below.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: rs.Name,
|
||||
Namespace: rs.Namespace,
|
||||
UID: rs.UID,
|
||||
ResourceVersion: rs.ResourceVersion,
|
||||
CreationTimestamp: rs.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: rs.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Replicas: rs.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -20,16 +20,22 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
|
||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
const defaultReplicas = 100
|
||||
|
||||
func newStorage(t *testing.T) (*ReplicaSetStorage, *etcdtesting.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorage(t, "extensions")
|
||||
restOptions := generic.RESTOptions{etcdStorage, generic.UndecoratedStorage, 1}
|
||||
|
@ -236,3 +242,126 @@ func TestWatch(t *testing.T) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestScaleGet(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
name := "foo"
|
||||
|
||||
var rs extensions.ReplicaSet
|
||||
ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault)
|
||||
key := etcdtest.AddPrefix("/replicasets/" + api.NamespaceDefault + "/" + name)
|
||||
if err := storage.ReplicaSet.Storage.Set(ctx, key, &validReplicaSet, &rs, 0); err != nil {
|
||||
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(validReplicaSet.Spec.Selector)
|
||||
if err != nil {
|
||||
t.Errorf("invalid replicaset selector %+v: %v", validReplicaSet.Spec.Selector, err)
|
||||
}
|
||||
want := &autoscaling.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
UID: rs.UID,
|
||||
ResourceVersion: rs.ResourceVersion,
|
||||
CreationTimestamp: rs.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: validReplicaSet.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Replicas: validReplicaSet.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
},
|
||||
}
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
got := obj.(*autoscaling.Scale)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
if !api.Semantic.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected scale: %s", util.ObjectDiff(got, want))
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
name := "foo"
|
||||
|
||||
var rs extensions.ReplicaSet
|
||||
ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault)
|
||||
key := etcdtest.AddPrefix("/replicasets/" + api.NamespaceDefault + "/" + name)
|
||||
if err := storage.ReplicaSet.Storage.Set(ctx, key, &validReplicaSet, &rs, 0); err != nil {
|
||||
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
||||
}
|
||||
replicas := 12
|
||||
update := autoscaling.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
}
|
||||
|
||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
||||
t.Fatalf("error updating scale %v: %v", update, err)
|
||||
}
|
||||
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
scale := obj.(*autoscaling.Scale)
|
||||
if scale.Spec.Replicas != replicas {
|
||||
t.Errorf("wrong replicas count expected: %d got: %d", replicas, scale.Spec.Replicas)
|
||||
}
|
||||
|
||||
update.ResourceVersion = rs.ResourceVersion
|
||||
update.Spec.Replicas = 15
|
||||
|
||||
if _, _, err = storage.Scale.Update(ctx, &update); err != nil && !errors.IsConflict(err) {
|
||||
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault)
|
||||
key := etcdtest.AddPrefix("/replicasets/" + api.NamespaceDefault + "/foo")
|
||||
if err := storage.ReplicaSet.Storage.Set(ctx, key, &validReplicaSet, nil, 0); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
update := extensions.ReplicaSet{
|
||||
ObjectMeta: validReplicaSet.ObjectMeta,
|
||||
Spec: extensions.ReplicaSetSpec{
|
||||
Replicas: defaultReplicas,
|
||||
},
|
||||
Status: extensions.ReplicaSetStatus{
|
||||
Replicas: defaultReplicas,
|
||||
},
|
||||
}
|
||||
|
||||
if _, _, err := storage.Status.Update(ctx, &update); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
obj, err := storage.ReplicaSet.Get(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
rs := obj.(*extensions.ReplicaSet)
|
||||
if rs.Spec.Replicas != 7 {
|
||||
t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", rs.Spec.Replicas)
|
||||
}
|
||||
if rs.Status.Replicas != defaultReplicas {
|
||||
t.Errorf("we expected .status.replicas to be updated to %d but it was %v", defaultReplicas, rs.Status.Replicas)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue