Commit 4e00333f authored by Abhi Shah's avatar Abhi Shah

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

Register scale subresource for replicationcontrollers in api/v1.
parents df05c5ae fa079409
...@@ -10481,6 +10481,168 @@ ...@@ -10481,6 +10481,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", "path": "/api/v1/namespaces/{namespace}/replicationcontrollers/{name}/status",
"description": "API at /api/v1", "description": "API at /api/v1",
"operations": [ "operations": [
...@@ -17454,6 +17616,61 @@ ...@@ -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": { "v1.ResourceQuotaList": {
"id": "v1.ResourceQuotaList", "id": "v1.ResourceQuotaList",
"description": "ResourceQuotaList is a list of ResourceQuota items.", "description": "ResourceQuotaList is a list of ResourceQuota items.",
......
...@@ -1456,6 +1456,47 @@ Examples:<br> ...@@ -1456,6 +1456,47 @@ Examples:<br>
</div> </div>
<div class="sect2"> <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> <h3 id="_v1_configmap">v1.ConfigMap</h3>
<div class="paragraph"> <div class="paragraph">
<p>ConfigMap holds configuration data for pods to consume.</p> <p>ConfigMap holds configuration data for pods to consume.</p>
...@@ -2859,6 +2900,68 @@ The resulting set of endpoints can be viewed as:<br> ...@@ -2859,6 +2900,68 @@ The resulting set of endpoints can be viewed as:<br>
</div> </div>
<div class="sect2"> <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> <h3 id="_v1_loadbalanceringress">v1.LoadBalancerIngress</h3>
<div class="paragraph"> <div class="paragraph">
<p>LoadBalancerIngress represents the status of a load-balancer ingress point: traffic intended for the service should be sent to an ingress point.</p> <p>LoadBalancerIngress represents the status of a load-balancer ingress point: traffic intended for the service should be sent to an ingress point.</p>
...@@ -5592,6 +5695,40 @@ The resulting set of endpoints can be viewed as:<br> ...@@ -5592,6 +5695,40 @@ The resulting set of endpoints can be viewed as:<br>
</div> </div>
<div class="sect2"> <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> <h3 id="_v1_componentstatuslist">v1.ComponentStatusList</h3>
<div class="paragraph"> <div class="paragraph">
<p>Status of all the conditions for the component as a list of ComponentStatus objects.</p> <p>Status of all the conditions for the component as a list of ComponentStatus objects.</p>
...@@ -7488,7 +7625,7 @@ The resulting set of endpoints can be viewed as:<br> ...@@ -7488,7 +7625,7 @@ The resulting set of endpoints can be viewed as:<br>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2016-02-29 20:12:40 UTC Last updated 2016-03-03 20:47:22 UTC
</div> </div>
</div> </div>
</body> </body>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -189,6 +189,11 @@ func (m *Master) InstallAPIs(c *Config) { ...@@ -189,6 +189,11 @@ func (m *Master) InstallAPIs(c *Config) {
ParameterCodec: api.ParameterCodec, ParameterCodec: api.ParameterCodec,
NegotiatedSerializer: api.Codecs, 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) apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
} }
...@@ -389,7 +394,7 @@ func (m *Master) initV1ResourcesStorage(c *Config) { ...@@ -389,7 +394,7 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
}) })
m.serviceNodePortAllocator = serviceNodePortRegistry 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) serviceRest := service.NewStorage(m.serviceRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.ProxyTransport)
...@@ -407,8 +412,8 @@ func (m *Master) initV1ResourcesStorage(c *Config) { ...@@ -407,8 +412,8 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
"podTemplates": podTemplateStorage, "podTemplates": podTemplateStorage,
"replicationControllers": controllerStorage, "replicationControllers": controllerStorage.Controller,
"replicationControllers/status": controllerStatusStorage, "replicationControllers/status": controllerStorage.Status,
"services": serviceRest.Service, "services": serviceRest.Service,
"services/proxy": serviceRest.Proxy, "services/proxy": serviceRest.Proxy,
...@@ -438,6 +443,9 @@ func (m *Master) initV1ResourcesStorage(c *Config) { ...@@ -438,6 +443,9 @@ func (m *Master) initV1ResourcesStorage(c *Config) {
"componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }), "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. // 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 { ...@@ -674,6 +682,7 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
} }
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
if isEnabled("horizontalpodautoscalers") { if isEnabled("horizontalpodautoscalers") {
m.constructHPAResources(c, storage) m.constructHPAResources(c, storage)
controllerStorage := expcontrolleretcd.NewStorage( controllerStorage := expcontrolleretcd.NewStorage(
......
...@@ -19,7 +19,13 @@ limitations under the License. ...@@ -19,7 +19,13 @@ limitations under the License.
package etcd package etcd
import ( import (
"fmt"
"k8s.io/kubernetes/pkg/api" "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/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/cachesize"
...@@ -29,6 +35,24 @@ import ( ...@@ -29,6 +35,24 @@ import (
"k8s.io/kubernetes/pkg/runtime" "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 { type REST struct {
*etcdgeneric.Etcd *etcdgeneric.Etcd
} }
...@@ -95,3 +119,69 @@ func (r *StatusREST) New() runtime.Object { ...@@ -95,3 +119,69 @@ func (r *StatusREST) New() runtime.Object {
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj) 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(),
},
}
}
...@@ -20,19 +20,27 @@ import ( ...@@ -20,19 +20,27 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" 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, "") etcdStorage, server := registrytest.NewEtcdStorage(t, "")
restOptions := generic.RESTOptions{etcdStorage, generic.UndecoratedStorage, 1} restOptions := generic.RESTOptions{etcdStorage, generic.UndecoratedStorage, 1}
controllerStorage, statusStorage := NewREST(restOptions) storage := NewStorage(restOptions)
return controllerStorage, statusStorage, server return storage, server
} }
// createController is a helper function that returns a controller with the updated resource version. // 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) ...@@ -49,8 +57,8 @@ func createController(storage *REST, rc api.ReplicationController, t *testing.T)
func validNewController() *api.ReplicationController { func validNewController() *api.ReplicationController {
return &api.ReplicationController{ return &api.ReplicationController{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: name,
Namespace: api.NamespaceDefault, Namespace: namespace,
}, },
Spec: api.ReplicationControllerSpec{ Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"a": "b"}, Selector: map[string]string{"a": "b"},
...@@ -77,9 +85,9 @@ func validNewController() *api.ReplicationController { ...@@ -77,9 +85,9 @@ func validNewController() *api.ReplicationController {
var validController = validNewController() var validController = validNewController()
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
controller := validNewController() controller := validNewController()
controller.ObjectMeta = api.ObjectMeta{} controller.ObjectMeta = api.ObjectMeta{}
test.TestCreate( test.TestCreate(
...@@ -97,9 +105,9 @@ func TestCreate(t *testing.T) { ...@@ -97,9 +105,9 @@ func TestCreate(t *testing.T) {
} }
func TestUpdate(t *testing.T) { func TestUpdate(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
test.TestUpdate( test.TestUpdate(
// valid // valid
validNewController(), validNewController(),
...@@ -129,21 +137,21 @@ func TestUpdate(t *testing.T) { ...@@ -129,21 +137,21 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
test.TestDelete(validNewController()) test.TestDelete(validNewController())
} }
func TestGenerationNumber(t *testing.T) { func TestGenerationNumber(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
modifiedSno := *validNewController() modifiedSno := *validNewController()
modifiedSno.Generation = 100 modifiedSno.Generation = 100
modifiedSno.Status.ObservedGeneration = 10 modifiedSno.Status.ObservedGeneration = 10
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()
rc, err := createController(storage, modifiedSno, t) rc, err := createController(storage.Controller, modifiedSno, t)
ctrl, err := storage.Get(ctx, rc.Name) ctrl, err := storage.Controller.Get(ctx, rc.Name)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -156,11 +164,11 @@ func TestGenerationNumber(t *testing.T) { ...@@ -156,11 +164,11 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number // Updates to spec should increment the generation number
controller.Spec.Replicas += 1 controller.Spec.Replicas += 1
storage.Update(ctx, controller) storage.Controller.Update(ctx, controller)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
ctrl, err = storage.Get(ctx, rc.Name) ctrl, err = storage.Controller.Get(ctx, rc.Name)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -171,11 +179,11 @@ func TestGenerationNumber(t *testing.T) { ...@@ -171,11 +179,11 @@ func TestGenerationNumber(t *testing.T) {
// Updates to status should not increment either spec or status generation numbers // Updates to status should not increment either spec or status generation numbers
controller.Status.Replicas += 1 controller.Status.Replicas += 1
storage.Update(ctx, controller) storage.Controller.Update(ctx, controller)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
ctrl, err = storage.Get(ctx, rc.Name) ctrl, err = storage.Controller.Get(ctx, rc.Name)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -186,23 +194,23 @@ func TestGenerationNumber(t *testing.T) { ...@@ -186,23 +194,23 @@ func TestGenerationNumber(t *testing.T) {
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
test.TestGet(validNewController()) test.TestGet(validNewController())
} }
func TestList(t *testing.T) { func TestList(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
test.TestList(validNewController()) test.TestList(validNewController())
} }
func TestWatch(t *testing.T) { func TestWatch(t *testing.T) {
storage, _, server := newStorage(t) storage, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
test := registrytest.New(t, storage.Etcd) test := registrytest.New(t, storage.Controller.Etcd)
test.TestWatch( test.TestWatch(
validController, validController,
// matching labels // matching labels
...@@ -232,3 +240,76 @@ func TestWatch(t *testing.T) { ...@@ -232,3 +240,76 @@ func TestWatch(t *testing.T) {
} }
//TODO TestUpdateStatus //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)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment