Merge pull request #21910 from madhusudancs/scale-register-rc-override

Register scale subresource for replicationcontrollers in api/v1.
pull/6/head
Abhi Shah 2016-03-04 12:54:12 -08:00
commit 4e00333f9b
6 changed files with 5642 additions and 4738 deletions

View File

@ -10480,6 +10480,168 @@
}
]
},
{
"path": "/api/v1/namespaces/{namespace}/replicationcontrollers/{name}/scale",
"description": "API at /api/v1",
"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": "/api/v1/namespaces/{namespace}/replicationcontrollers/{name}/status",
"description": "API at /api/v1",
@ -17454,6 +17616,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"
}
}
},
"v1.ResourceQuotaList": {
"id": "v1.ResourceQuotaList",
"description": "ResourceQuotaList is a list of ResourceQuota items.",

View File

@ -1454,6 +1454,47 @@ Examples:<br>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_scalestatus">v1.ScaleStatus</h3>
<div class="paragraph">
<p>ScaleStatus represents the current status of a scale subresource.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">replicas</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">actual number of observed instances of the scaled object.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">integer (int32)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">selector</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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: <a href="http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors">http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_configmap">v1.ConfigMap</h3>
@ -2857,6 +2898,68 @@ The resulting set of endpoints can be viewed as:<br>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_scale">v1.Scale</h3>
<div class="paragraph">
<p>Scale represents a scaling request for a resource.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">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: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Standard object metadata; More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata</a>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectmeta">v1.ObjectMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spec</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">defines the behavior of the scale. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status</a>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_scalespec">v1.ScaleSpec</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">status</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">current status of the scale. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status</a>. Read-only.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_scalestatus">v1.ScaleStatus</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_loadbalanceringress">v1.LoadBalancerIngress</h3>
@ -5590,6 +5693,40 @@ The resulting set of endpoints can be viewed as:<br>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_scalespec">v1.ScaleSpec</h3>
<div class="paragraph">
<p>ScaleSpec describes the attributes of a scale subresource.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">replicas</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">desired number of instances for the scaled object.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">integer (int32)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_componentstatuslist">v1.ComponentStatusList</h3>
@ -7488,7 +7625,7 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-02-29 20:12:40 UTC
Last updated 2016-03-03 20:47:22 UTC
</div>
</div>
</body>

File diff suppressed because it is too large Load Diff

View File

@ -189,6 +189,11 @@ 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{
"replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"),
}
}
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
}
@ -389,7 +394,7 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
})
m.serviceNodePortAllocator = serviceNodePortRegistry
controllerStorage, controllerStatusStorage := controlleretcd.NewREST(restOptions("replicationControllers"))
controllerStorage := controlleretcd.NewStorage(restOptions("replicationControllers"))
serviceRest := service.NewStorage(m.serviceRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.ProxyTransport)
@ -407,8 +412,8 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
"podTemplates": podTemplateStorage,
"replicationControllers": controllerStorage,
"replicationControllers/status": controllerStatusStorage,
"replicationControllers": controllerStorage.Controller,
"replicationControllers/status": controllerStorage.Status,
"services": serviceRest.Service,
"services/proxy": serviceRest.Proxy,
@ -438,6 +443,9 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
"componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }),
}
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) {
m.v1ResourcesStorage["replicationControllers/scale"] = controllerStorage.Scale
}
}
// NewBootstrapController returns a controller for watching the core capabilities of the master.
@ -674,6 +682,7 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
}
storage := map[string]rest.Storage{}
if isEnabled("horizontalpodautoscalers") {
m.constructHPAResources(c, storage)
controllerStorage := expcontrolleretcd.NewStorage(

View File

@ -19,7 +19,13 @@ 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/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize"
@ -29,6 +35,24 @@ import (
"k8s.io/kubernetes/pkg/runtime"
)
// ControllerStorage includes dummy storage for Replication Controllers and for Scale subresource.
type ControllerStorage struct {
Controller *REST
Status *StatusREST
Scale *ScaleREST
}
func NewStorage(opts generic.RESTOptions) ControllerStorage {
controllerREST, statusREST := NewREST(opts)
controllerRegistry := controller.NewRegistry(controllerREST)
return ControllerStorage{
Controller: controllerREST,
Status: statusREST,
Scale: &ScaleREST{registry: controllerRegistry},
}
}
type REST struct {
*etcdgeneric.Etcd
}
@ -95,3 +119,69 @@ 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 controller.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) {
rc, err := r.registry.GetController(ctx, name)
if err != nil {
return nil, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name)
}
return scaleFromRC(rc), nil
}
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
if obj == nil {
return nil, false, errors.NewBadRequest("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 := validation.ValidateScale(scale); len(errs) > 0 {
return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs)
}
rc, err := r.registry.GetController(ctx, scale.Name)
if err != nil {
return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), scale.Name)
}
rc.Spec.Replicas = scale.Spec.Replicas
rc.ResourceVersion = scale.ResourceVersion
rc, err = r.registry.UpdateController(ctx, rc)
if err != nil {
return nil, false, err
}
return scaleFromRC(rc), false, nil
}
// scaleFromRC returns a scale subresource for a replication controller.
func scaleFromRC(rc *api.ReplicationController) *autoscaling.Scale {
return &autoscaling.Scale{
ObjectMeta: api.ObjectMeta{
Name: rc.Name,
Namespace: rc.Namespace,
UID: rc.UID,
ResourceVersion: rc.ResourceVersion,
CreationTimestamp: rc.CreationTimestamp,
},
Spec: autoscaling.ScaleSpec{
Replicas: rc.Spec.Replicas,
},
Status: autoscaling.ScaleStatus{
Replicas: rc.Status.Replicas,
Selector: labels.SelectorFromSet(rc.Spec.Selector).String(),
},
}
}

View File

@ -20,19 +20,27 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"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"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
"k8s.io/kubernetes/pkg/util"
)
func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) {
const (
namespace = api.NamespaceDefault
name = "foo"
)
func newStorage(t *testing.T) (ControllerStorage, *etcdtesting.EtcdTestServer) {
etcdStorage, server := registrytest.NewEtcdStorage(t, "")
restOptions := generic.RESTOptions{etcdStorage, generic.UndecoratedStorage, 1}
controllerStorage, statusStorage := NewREST(restOptions)
return controllerStorage, statusStorage, server
storage := NewStorage(restOptions)
return storage, server
}
// createController is a helper function that returns a controller with the updated resource version.
@ -49,8 +57,8 @@ func createController(storage *REST, rc api.ReplicationController, t *testing.T)
func validNewController() *api.ReplicationController {
return &api.ReplicationController{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
Name: name,
Namespace: namespace,
},
Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"a": "b"},
@ -77,9 +85,9 @@ func validNewController() *api.ReplicationController {
var validController = validNewController()
func TestCreate(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
controller := validNewController()
controller.ObjectMeta = api.ObjectMeta{}
test.TestCreate(
@ -97,9 +105,9 @@ func TestCreate(t *testing.T) {
}
func TestUpdate(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
test.TestUpdate(
// valid
validNewController(),
@ -129,21 +137,21 @@ func TestUpdate(t *testing.T) {
}
func TestDelete(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
test.TestDelete(validNewController())
}
func TestGenerationNumber(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
modifiedSno := *validNewController()
modifiedSno.Generation = 100
modifiedSno.Status.ObservedGeneration = 10
ctx := api.NewDefaultContext()
rc, err := createController(storage, modifiedSno, t)
ctrl, err := storage.Get(ctx, rc.Name)
rc, err := createController(storage.Controller, modifiedSno, t)
ctrl, err := storage.Controller.Get(ctx, rc.Name)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -156,11 +164,11 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number
controller.Spec.Replicas += 1
storage.Update(ctx, controller)
storage.Controller.Update(ctx, controller)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
ctrl, err = storage.Get(ctx, rc.Name)
ctrl, err = storage.Controller.Get(ctx, rc.Name)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -171,11 +179,11 @@ func TestGenerationNumber(t *testing.T) {
// Updates to status should not increment either spec or status generation numbers
controller.Status.Replicas += 1
storage.Update(ctx, controller)
storage.Controller.Update(ctx, controller)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
ctrl, err = storage.Get(ctx, rc.Name)
ctrl, err = storage.Controller.Get(ctx, rc.Name)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -186,23 +194,23 @@ func TestGenerationNumber(t *testing.T) {
}
func TestGet(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
test.TestGet(validNewController())
}
func TestList(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
test.TestList(validNewController())
}
func TestWatch(t *testing.T) {
storage, _, server := newStorage(t)
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd)
test := registrytest.New(t, storage.Controller.Etcd)
test.TestWatch(
validController,
// matching labels
@ -232,3 +240,76 @@ func TestWatch(t *testing.T) {
}
//TODO TestUpdateStatus
func TestScaleGet(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
ctx := api.WithNamespace(api.NewContext(), namespace)
rc, err := createController(storage.Controller, *validController, t)
if err != nil {
t.Fatalf("error setting new replication controller %v: %v", *validController, err)
}
want := &autoscaling.Scale{
ObjectMeta: api.ObjectMeta{
Name: name,
Namespace: namespace,
UID: rc.UID,
ResourceVersion: rc.ResourceVersion,
CreationTimestamp: rc.CreationTimestamp,
},
Spec: autoscaling.ScaleSpec{
Replicas: validController.Spec.Replicas,
},
Status: autoscaling.ScaleStatus{
Replicas: validController.Status.Replicas,
Selector: labels.SelectorFromSet(validController.Spec.Template.Labels).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 TestScaleUpdate(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
ctx := api.WithNamespace(api.NewContext(), namespace)
rc, err := createController(storage.Controller, *validController, t)
if err != nil {
t.Fatalf("error setting new replication controller %v: %v", *validController, err)
}
replicas := 12
update := autoscaling.Scale{
ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
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, rc.Spec.Replicas)
}
update.ResourceVersion = rc.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)
}
}