mirror of https://github.com/k3s-io/k3s
Merge pull request #22724 from madhusudancs/scale-hpa-stopgap-1.2
Auto commit by PR queue botpull/6/head
commit
108f722657
|
@ -1659,7 +1659,7 @@
|
|||
"description": "API at /apis/extensions/v1beta1",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "GET",
|
||||
"summary": "read scale of the specified Scale",
|
||||
"nickname": "readNamespacedScaleScale",
|
||||
|
@ -1693,7 +1693,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -1705,7 +1705,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "PUT",
|
||||
"summary": "replace scale of the specified Scale",
|
||||
"nickname": "replaceNamespacedScaleScale",
|
||||
|
@ -1719,7 +1719,7 @@
|
|||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
|
@ -1747,7 +1747,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -1759,7 +1759,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "PATCH",
|
||||
"summary": "partially update scale of the specified Scale",
|
||||
"nickname": "patchNamespacedScaleScale",
|
||||
|
@ -1801,7 +1801,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -5121,7 +5121,7 @@
|
|||
"description": "API at /apis/extensions/v1beta1",
|
||||
"operations": [
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "GET",
|
||||
"summary": "read scale of the specified Scale",
|
||||
"nickname": "readNamespacedScaleScale",
|
||||
|
@ -5155,7 +5155,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -5167,7 +5167,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "PUT",
|
||||
"summary": "replace scale of the specified Scale",
|
||||
"nickname": "replaceNamespacedScaleScale",
|
||||
|
@ -5181,7 +5181,7 @@
|
|||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"paramType": "body",
|
||||
"name": "body",
|
||||
"description": "",
|
||||
|
@ -5209,7 +5209,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -5221,7 +5221,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Scale",
|
||||
"type": "v1beta1.Scale",
|
||||
"method": "PATCH",
|
||||
"summary": "partially update scale of the specified Scale",
|
||||
"nickname": "patchNamespacedScaleScale",
|
||||
|
@ -5263,7 +5263,7 @@
|
|||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Scale"
|
||||
"responseModel": "v1beta1.Scale"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
|
@ -7234,9 +7234,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.Scale": {
|
||||
"id": "v1.Scale",
|
||||
"description": "Scale represents a scaling request for a resource.",
|
||||
"v1beta1.Scale": {
|
||||
"id": "v1beta1.Scale",
|
||||
"description": "represents a scaling request for a resource.",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
|
@ -7251,18 +7251,18 @@
|
|||
"description": "Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata."
|
||||
},
|
||||
"spec": {
|
||||
"$ref": "v1.ScaleSpec",
|
||||
"$ref": "v1beta1.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",
|
||||
"$ref": "v1beta1.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.",
|
||||
"v1beta1.ScaleSpec": {
|
||||
"id": "v1beta1.ScaleSpec",
|
||||
"description": "describes the attributes of a scale subresource",
|
||||
"properties": {
|
||||
"replicas": {
|
||||
"type": "integer",
|
||||
|
@ -7271,9 +7271,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.ScaleStatus": {
|
||||
"id": "v1.ScaleStatus",
|
||||
"description": "ScaleStatus represents the current status of a scale subresource.",
|
||||
"v1beta1.ScaleStatus": {
|
||||
"id": "v1beta1.ScaleStatus",
|
||||
"description": "represents the current status of a scale subresource.",
|
||||
"required": [
|
||||
"replicas"
|
||||
],
|
||||
|
@ -7284,8 +7284,12 @@
|
|||
"description": "actual number of observed instances of the scaled object."
|
||||
},
|
||||
"selector": {
|
||||
"type": "any",
|
||||
"description": "label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors"
|
||||
},
|
||||
"targetSelector": {
|
||||
"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"
|
||||
"description": "label selector for pods that should match the replicas count. This is a serializated version of both map-based and more expressive set-based selectors. This is done to avoid introspection in the clients. The string will be in the same format as the query-param syntax. If the target type only supports map-based selectors, both this field and map-based selector field are populated. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7887,61 +7891,6 @@
|
|||
"description": "ObservedGeneration reflects the generation of the most recently observed ReplicaSet."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.Scale": {
|
||||
"id": "v1beta1.Scale",
|
||||
"description": "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": "v1beta1.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": "v1beta1.ScaleStatus",
|
||||
"description": "current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.ScaleSpec": {
|
||||
"id": "v1beta1.ScaleSpec",
|
||||
"description": "describes the attributes of a scale subresource",
|
||||
"properties": {
|
||||
"replicas": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "desired number of instances for the scaled object."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta1.ScaleStatus": {
|
||||
"id": "v1beta1.ScaleStatus",
|
||||
"description": "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": "any",
|
||||
"description": "label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1332,47 +1332,6 @@ 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="_v1beta1_jobstatus">v1beta1.JobStatus</h3>
|
||||
|
@ -2457,68 +2416,6 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</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>
|
||||
|
@ -3737,6 +3634,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_any">any</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">targetSelector</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">label selector for pods that should match the replicas count. This is a serializated version of both map-based and more expressive set-based selectors. This is done to avoid introspection in the clients. The string will be in the same format as the query-param syntax. If the target type only supports map-based selectors, both this field and map-based selector field are populated. More info: <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>
|
||||
|
||||
|
@ -4686,40 +4590,6 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</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="_v1beta1_labelselector">v1beta1.LabelSelector</h3>
|
||||
|
@ -5728,7 +5598,7 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-03-03 20:23:06 UTC
|
||||
Last updated 2016-03-09 19:21:59 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -3304,7 +3304,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -3386,7 +3386,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<td class="tableblock halign-left valign-top"><p class="tableblock">body</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -3428,7 +3428,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -3552,7 +3552,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -7858,7 +7858,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -7940,7 +7940,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<td class="tableblock halign-left valign-top"><p class="tableblock">body</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -7982,7 +7982,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -8106,7 +8106,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">200</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">success</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1_scale">v1.Scale</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="definitions.html#_v1beta1_scale">v1beta1.Scale</a></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -11401,7 +11401,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-02-28 04:44:42 UTC
|
||||
Last updated 2016-03-09 19:21:59 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -413,6 +413,25 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
|
|||
seLinuxRules := []extensions.SELinuxStrategy{extensions.SELinuxStrategyRunAsAny, extensions.SELinuxStrategyMustRunAs}
|
||||
psp.SELinux.Rule = seLinuxRules[c.Rand.Intn(len(seLinuxRules))]
|
||||
},
|
||||
func(s *extensions.Scale, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
// TODO: Implement a fuzzer to generate valid keys, values and operators for
|
||||
// selector requirements.
|
||||
if s.Status.Selector != nil {
|
||||
s.Status.Selector = &unversioned.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"testlabelkey": "testlabelval",
|
||||
},
|
||||
MatchExpressions: []unversioned.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "testkey",
|
||||
Operator: unversioned.LabelSelectorOpIn,
|
||||
Values: []string{"val1", "val2", "val3"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
|
||||
// labels.Selector
|
||||
// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
|
||||
func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
|
||||
if ps == nil {
|
||||
return labels.Nothing(), nil
|
||||
|
@ -34,7 +35,7 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
|
|||
}
|
||||
selector := labels.NewSelector()
|
||||
for k, v := range ps.MatchLabels {
|
||||
r, err := labels.NewRequirement(k, labels.InOperator, sets.NewString(v))
|
||||
r, err := labels.NewRequirement(k, labels.EqualsOperator, sets.NewString(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -63,6 +64,55 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
|
|||
return selector, nil
|
||||
}
|
||||
|
||||
// ParseToLabelSelector parses a string representing a selector into a LabelSelector object.
|
||||
// Note: This function should be kept in sync with the parser in pkg/labels/selector.go
|
||||
func ParseToLabelSelector(selector string) (*LabelSelector, error) {
|
||||
reqs, err := labels.ParseToRequirements(selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse the selector string \"%s\": %v", selector, err)
|
||||
}
|
||||
|
||||
labelSelector := &LabelSelector{
|
||||
MatchLabels: map[string]string{},
|
||||
MatchExpressions: []LabelSelectorRequirement{},
|
||||
}
|
||||
for _, req := range reqs {
|
||||
var op LabelSelectorOperator
|
||||
switch req.Operator() {
|
||||
case labels.EqualsOperator, labels.DoubleEqualsOperator:
|
||||
vals := req.Values()
|
||||
if vals.Len() != 1 {
|
||||
return nil, fmt.Errorf("equals operator must have exactly one value")
|
||||
}
|
||||
val, ok := vals.PopAny()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("equals operator has exactly one value but it cannot be retrieved")
|
||||
}
|
||||
labelSelector.MatchLabels[req.Key()] = val
|
||||
continue
|
||||
case labels.InOperator:
|
||||
op = LabelSelectorOpIn
|
||||
case labels.NotInOperator:
|
||||
op = LabelSelectorOpNotIn
|
||||
case labels.ExistsOperator:
|
||||
op = LabelSelectorOpExists
|
||||
case labels.DoesNotExistOperator:
|
||||
op = LabelSelectorOpDoesNotExist
|
||||
case labels.GreaterThanOperator, labels.LessThanOperator:
|
||||
// Adding a separate case for these operators to indicate that this is deliberate
|
||||
return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator())
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid label selector operator", req.Operator())
|
||||
}
|
||||
labelSelector.MatchExpressions = append(labelSelector.MatchExpressions, LabelSelectorRequirement{
|
||||
Key: req.Key(),
|
||||
Operator: op,
|
||||
Values: req.Values().List(),
|
||||
})
|
||||
}
|
||||
return labelSelector, nil
|
||||
}
|
||||
|
||||
// SetAsLabelSelector converts the labels.Set object into a LabelSelector api object.
|
||||
func SetAsLabelSelector(ls labels.Set) *LabelSelector {
|
||||
if ls == nil {
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestLabelSelectorAsSelector(t *testing.T) {
|
|||
{in: &LabelSelector{}, out: labels.Everything()},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels},
|
||||
out: mustParse("foo in (bar)"),
|
||||
out: mustParse("foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions},
|
||||
|
@ -54,7 +54,7 @@ func TestLabelSelectorAsSelector(t *testing.T) {
|
|||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions},
|
||||
out: mustParse("foo in (bar),baz in (norf,qux)"),
|
||||
out: mustParse("baz in (norf,qux),foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{
|
||||
|
|
|
@ -68,7 +68,7 @@ func init() {
|
|||
if false { // reference the types, but skip this branch at build/run time
|
||||
var v0 pkg2_api.ObjectMeta
|
||||
var v1 pkg4_resource.Quantity
|
||||
var v2 pkg1_unversioned.TypeMeta
|
||||
var v2 pkg1_unversioned.LabelSelector
|
||||
var v3 pkg3_types.UID
|
||||
var v4 pkg6_intstr.IntOrString
|
||||
var v5 pkg5_inf.Dec
|
||||
|
@ -263,7 +263,7 @@ func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
var yyq2 [2]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = len(x.Selector) != 0
|
||||
yyq2[1] = x.Selector != nil
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(2)
|
||||
|
@ -305,8 +305,9 @@ func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
yym7 := z.EncBinary()
|
||||
_ = yym7
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x.Selector) {
|
||||
} else {
|
||||
z.F.EncMapStringStringV(x.Selector, false, e)
|
||||
z.EncFallback(x.Selector)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -323,8 +324,9 @@ func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
yym8 := z.EncBinary()
|
||||
_ = yym8
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.EncExt(x.Selector) {
|
||||
} else {
|
||||
z.F.EncMapStringStringV(x.Selector, false, e)
|
||||
z.EncFallback(x.Selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -398,14 +400,19 @@ func (x *ScaleStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
case "selector":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Selector = nil
|
||||
if x.Selector != nil {
|
||||
x.Selector = nil
|
||||
}
|
||||
} else {
|
||||
yyv5 := &x.Selector
|
||||
if x.Selector == nil {
|
||||
x.Selector = new(pkg1_unversioned.LabelSelector)
|
||||
}
|
||||
yym6 := z.DecBinary()
|
||||
_ = yym6
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x.Selector) {
|
||||
} else {
|
||||
z.F.DecMapStringStringX(yyv5, false, d)
|
||||
z.DecFallback(x.Selector, false)
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
@ -450,14 +457,19 @@ func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.Selector = nil
|
||||
if x.Selector != nil {
|
||||
x.Selector = nil
|
||||
}
|
||||
} else {
|
||||
yyv9 := &x.Selector
|
||||
if x.Selector == nil {
|
||||
x.Selector = new(pkg1_unversioned.LabelSelector)
|
||||
}
|
||||
yym10 := z.DecBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else if z.HasExtensions() && z.DecExt(x.Selector) {
|
||||
} else {
|
||||
z.F.DecMapStringStringX(yyv9, false, d)
|
||||
z.DecFallback(x.Selector, false)
|
||||
}
|
||||
}
|
||||
for {
|
||||
|
|
|
@ -46,8 +46,9 @@ type ScaleStatus struct {
|
|||
// actual number of observed instances of the scaled object.
|
||||
Replicas int `json:"replicas"`
|
||||
|
||||
// label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
Selector map[string]string `json:"selector,omitempty"`
|
||||
// label query over pods that should match the replicas count.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
Selector *unversioned.LabelSelector `json:"selector,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient=true,noMethods=true
|
||||
|
|
|
@ -34,6 +34,8 @@ func addConversionFuncs(scheme *runtime.Scheme) {
|
|||
err := scheme.AddConversionFuncs(
|
||||
Convert_api_PodSpec_To_v1_PodSpec,
|
||||
Convert_v1_PodSpec_To_api_PodSpec,
|
||||
Convert_extensions_ScaleStatus_To_v1beta1_ScaleStatus,
|
||||
Convert_v1beta1_ScaleStatus_To_extensions_ScaleStatus,
|
||||
Convert_extensions_DeploymentSpec_To_v1beta1_DeploymentSpec,
|
||||
Convert_v1beta1_DeploymentSpec_To_extensions_DeploymentSpec,
|
||||
Convert_extensions_DeploymentStrategy_To_v1beta1_DeploymentStrategy,
|
||||
|
@ -93,6 +95,58 @@ func Convert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s conve
|
|||
return v1.Convert_v1_PodSpec_To_api_PodSpec(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in *extensions.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*extensions.ScaleStatus))(in)
|
||||
}
|
||||
out.Replicas = int32(in.Replicas)
|
||||
|
||||
out.Selector = nil
|
||||
out.TargetSelector = ""
|
||||
if in.Selector != nil {
|
||||
if in.Selector.MatchExpressions == nil || len(in.Selector.MatchExpressions) == 0 {
|
||||
out.Selector = in.Selector.MatchLabels
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(in.Selector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
out.TargetSelector = selector.String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in *ScaleStatus, out *extensions.ScaleStatus, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ScaleStatus))(in)
|
||||
}
|
||||
out.Replicas = int(in.Replicas)
|
||||
|
||||
// Normally when 2 fields map to the same internal value we favor the old field, since
|
||||
// old clients can't be expected to know about new fields but clients that know about the
|
||||
// new field can be expected to know about the old field (though that's not quite true, due
|
||||
// to kubectl apply). However, these fields are readonly, so any non-nil value should work.
|
||||
if in.TargetSelector != "" {
|
||||
labelSelector, err := unversioned.ParseToLabelSelector(in.TargetSelector)
|
||||
if err != nil {
|
||||
out.Selector = nil
|
||||
return fmt.Errorf("failed to parse target selector: %v", err)
|
||||
}
|
||||
out.Selector = labelSelector
|
||||
} else if in.Selector != nil {
|
||||
out.Selector = new(unversioned.LabelSelector)
|
||||
selector := make(map[string]string)
|
||||
for key, val := range in.Selector {
|
||||
selector[key] = val
|
||||
}
|
||||
out.Selector.MatchLabels = selector
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_extensions_DeploymentSpec_To_v1beta1_DeploymentSpec(in *extensions.DeploymentSpec, out *DeploymentSpec, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*extensions.DeploymentSpec))(in)
|
||||
|
|
|
@ -3746,21 +3746,10 @@ func autoConvert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in *extensions.Sc
|
|||
defaulting.(func(*extensions.ScaleStatus))(in)
|
||||
}
|
||||
out.Replicas = int32(in.Replicas)
|
||||
if in.Selector != nil {
|
||||
out.Selector = make(map[string]string)
|
||||
for key, val := range in.Selector {
|
||||
out.Selector[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
// in.Selector has no peer in out
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in *extensions.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
|
||||
return autoConvert_extensions_ScaleStatus_To_v1beta1_ScaleStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_extensions_SubresourceReference_To_v1beta1_SubresourceReference(in *extensions.SubresourceReference, out *SubresourceReference, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*extensions.SubresourceReference))(in)
|
||||
|
@ -5002,21 +4991,11 @@ func autoConvert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in *ScaleStatus,
|
|||
defaulting.(func(*ScaleStatus))(in)
|
||||
}
|
||||
out.Replicas = int(in.Replicas)
|
||||
if in.Selector != nil {
|
||||
out.Selector = make(map[string]string)
|
||||
for key, val := range in.Selector {
|
||||
out.Selector[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
// in.Selector has no peer in out
|
||||
// in.TargetSelector has no peer in out
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in *ScaleStatus, out *extensions.ScaleStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_ScaleStatus_To_extensions_ScaleStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_SubresourceReference_To_extensions_SubresourceReference(in *SubresourceReference, out *extensions.SubresourceReference, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*SubresourceReference))(in)
|
||||
|
|
|
@ -1846,6 +1846,7 @@ func deepCopy_v1beta1_ScaleStatus(in ScaleStatus, out *ScaleStatus, c *conversio
|
|||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
out.TargetSelector = in.TargetSelector
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -260,13 +260,14 @@ func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
} else {
|
||||
yysep2 := !z.EncBinary()
|
||||
yy2arr2 := z.EncBasicHandle().StructToArray
|
||||
var yyq2 [2]bool
|
||||
var yyq2 [3]bool
|
||||
_, _, _ = yysep2, yyq2, yy2arr2
|
||||
const yyr2 bool = false
|
||||
yyq2[1] = len(x.Selector) != 0
|
||||
yyq2[2] = x.TargetSelector != ""
|
||||
var yynn2 int
|
||||
if yyr2 || yy2arr2 {
|
||||
r.EncodeArrayStart(2)
|
||||
r.EncodeArrayStart(3)
|
||||
} else {
|
||||
yynn2 = 1
|
||||
for _, b := range yyq2 {
|
||||
|
@ -329,6 +330,31 @@ func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if yyq2[2] {
|
||||
yym10 := z.EncBinary()
|
||||
_ = yym10
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.TargetSelector))
|
||||
}
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, "")
|
||||
}
|
||||
} else {
|
||||
if yyq2[2] {
|
||||
z.EncSendContainerState(codecSelfer_containerMapKey1234)
|
||||
r.EncodeString(codecSelferC_UTF81234, string("targetSelector"))
|
||||
z.EncSendContainerState(codecSelfer_containerMapValue1234)
|
||||
yym11 := z.EncBinary()
|
||||
_ = yym11
|
||||
if false {
|
||||
} else {
|
||||
r.EncodeString(codecSelferC_UTF81234, string(x.TargetSelector))
|
||||
}
|
||||
}
|
||||
}
|
||||
if yyr2 || yy2arr2 {
|
||||
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
} else {
|
||||
|
@ -408,6 +434,12 @@ func (x *ScaleStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
|
|||
z.F.DecMapStringStringX(yyv5, false, d)
|
||||
}
|
||||
}
|
||||
case "targetSelector":
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TargetSelector = ""
|
||||
} else {
|
||||
x.TargetSelector = string(r.DecodeString())
|
||||
}
|
||||
default:
|
||||
z.DecStructFieldNotFound(-1, yys3)
|
||||
} // end switch yys3
|
||||
|
@ -419,16 +451,16 @@ func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
var h codecSelfer1234
|
||||
z, r := codec1978.GenHelperDecoder(d)
|
||||
_, _, _ = h, z, r
|
||||
var yyj7 int
|
||||
var yyb7 bool
|
||||
var yyhl7 bool = l >= 0
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
var yyj8 int
|
||||
var yyb8 bool
|
||||
var yyhl8 bool = l >= 0
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -438,13 +470,13 @@ func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
} else {
|
||||
x.Replicas = int32(r.DecodeInt(32))
|
||||
}
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
|
@ -452,26 +484,42 @@ func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
|
|||
if r.TryDecodeAsNil() {
|
||||
x.Selector = nil
|
||||
} else {
|
||||
yyv9 := &x.Selector
|
||||
yym10 := z.DecBinary()
|
||||
_ = yym10
|
||||
yyv10 := &x.Selector
|
||||
yym11 := z.DecBinary()
|
||||
_ = yym11
|
||||
if false {
|
||||
} else {
|
||||
z.F.DecMapStringStringX(yyv9, false, d)
|
||||
z.F.DecMapStringStringX(yyv10, false, d)
|
||||
}
|
||||
}
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb8 {
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
return
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
if r.TryDecodeAsNil() {
|
||||
x.TargetSelector = ""
|
||||
} else {
|
||||
x.TargetSelector = string(r.DecodeString())
|
||||
}
|
||||
for {
|
||||
yyj7++
|
||||
if yyhl7 {
|
||||
yyb7 = yyj7 > l
|
||||
yyj8++
|
||||
if yyhl8 {
|
||||
yyb8 = yyj8 > l
|
||||
} else {
|
||||
yyb7 = r.CheckBreak()
|
||||
yyb8 = r.CheckBreak()
|
||||
}
|
||||
if yyb7 {
|
||||
if yyb8 {
|
||||
break
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
|
||||
z.DecStructFieldNotFound(yyj7-1, "")
|
||||
z.DecStructFieldNotFound(yyj8-1, "")
|
||||
}
|
||||
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
|
||||
}
|
||||
|
|
|
@ -36,6 +36,14 @@ type ScaleStatus struct {
|
|||
|
||||
// label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
Selector map[string]string `json:"selector,omitempty"`
|
||||
|
||||
// label selector for pods that should match the replicas count. This is a serializated
|
||||
// version of both map-based and more expressive set-based selectors. This is done to
|
||||
// avoid introspection in the clients. The string will be in the same format as the
|
||||
// query-param syntax. If the target type only supports map-based selectors, both this
|
||||
// field and map-based selector field are populated.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
TargetSelector string `json:"targetSelector,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient=true,noMethods=true
|
||||
|
|
|
@ -593,9 +593,10 @@ func (ScaleSpec) SwaggerDoc() map[string]string {
|
|||
}
|
||||
|
||||
var map_ScaleStatus = map[string]string{
|
||||
"": "represents the current status of a scale subresource.",
|
||||
"replicas": "actual number of observed instances of the scaled object.",
|
||||
"selector": "label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
|
||||
"": "represents the current status of a scale subresource.",
|
||||
"replicas": "actual number of observed instances of the scaled object.",
|
||||
"selector": "label query over pods that should match the replicas count. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
|
||||
"targetSelector": "label selector for pods that should match the replicas count. This is a serializated version of both map-based and more expressive set-based selectors. This is done to avoid introspection in the clients. The string will be in the same format as the query-param syntax. If the target type only supports map-based selectors, both this field and map-based selector field are populated. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
|
||||
}
|
||||
|
||||
func (ScaleStatus) SwaggerDoc() map[string]string {
|
||||
|
|
|
@ -129,7 +129,20 @@ func (a *HorizontalController) computeReplicasForCPUUtilization(hpa *extensions.
|
|||
targetUtilization = hpa.Spec.CPUUtilization.TargetPercentage
|
||||
}
|
||||
currentReplicas := scale.Status.Replicas
|
||||
currentUtilization, timestamp, err := a.metricsClient.GetCPUUtilization(hpa.Namespace, scale.Status.Selector)
|
||||
|
||||
if scale.Status.Selector == nil {
|
||||
errMsg := "selector is required"
|
||||
a.eventRecorder.Event(hpa, api.EventTypeWarning, "SelectorRequired", errMsg)
|
||||
return 0, nil, time.Time{}, fmt.Errorf(errMsg)
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(scale.Status.Selector)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("couldn't convert selector string to a corresponding selector object: %v", err)
|
||||
a.eventRecorder.Event(hpa, api.EventTypeWarning, "InvalidSelector", errMsg)
|
||||
return 0, nil, time.Time{}, fmt.Errorf(errMsg)
|
||||
}
|
||||
currentUtilization, timestamp, err := a.metricsClient.GetCPUUtilization(hpa.Namespace, selector)
|
||||
|
||||
// TODO: what to do on partial errors (like metrics obtained for 75% of pods).
|
||||
if err != nil {
|
||||
|
@ -177,7 +190,19 @@ func (a *HorizontalController) computeReplicasForCustomMetrics(hpa *extensions.H
|
|||
}
|
||||
|
||||
for _, customMetricTarget := range targetList.Items {
|
||||
value, currentTimestamp, err := a.metricsClient.GetCustomMetric(customMetricTarget.Name, hpa.Namespace, scale.Status.Selector)
|
||||
if scale.Status.Selector == nil {
|
||||
errMsg := "selector is required"
|
||||
a.eventRecorder.Event(hpa, api.EventTypeWarning, "SelectorRequired", errMsg)
|
||||
return 0, "", "", time.Time{}, fmt.Errorf("selector is required")
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(scale.Status.Selector)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("couldn't convert selector string to a corresponding selector object: %v", err)
|
||||
a.eventRecorder.Event(hpa, api.EventTypeWarning, "InvalidSelector", errMsg)
|
||||
return 0, "", "", time.Time{}, fmt.Errorf("couldn't convert selector string to a corresponding selector object: %v", err)
|
||||
}
|
||||
value, currentTimestamp, err := a.metricsClient.GetCustomMetric(customMetricTarget.Name, hpa.Namespace, selector)
|
||||
// TODO: what to do on partial errors (like metrics obtained for 75% of pods).
|
||||
if err != nil {
|
||||
a.eventRecorder.Event(hpa, api.EventTypeWarning, "FailedGetCustomMetrics", err.Error())
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
_ "k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
|
@ -56,6 +57,12 @@ type fakeResponseWrapper struct {
|
|||
raw []byte
|
||||
}
|
||||
|
||||
type fakeResource struct {
|
||||
name string
|
||||
apiVersion string
|
||||
kind string
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
minReplicas int
|
||||
maxReplicas int
|
||||
|
@ -74,6 +81,9 @@ type testCase struct {
|
|||
verifyEvents bool
|
||||
// Channel with names of HPA objects which we have reconciled.
|
||||
processed chan string
|
||||
|
||||
// Target resource information.
|
||||
resource *fakeResource
|
||||
}
|
||||
|
||||
func (tc *testCase) computeCPUCurrent() {
|
||||
|
@ -94,8 +104,10 @@ func (tc *testCase) computeCPUCurrent() {
|
|||
func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
||||
namespace := "test-namespace"
|
||||
hpaName := "test-hpa"
|
||||
rcName := "test-rc"
|
||||
podNamePrefix := "test-pod"
|
||||
selector := &unversioned.LabelSelector{
|
||||
MatchLabels: map[string]string{"name": podNamePrefix},
|
||||
}
|
||||
|
||||
tc.scaleUpdated = false
|
||||
tc.statusUpdated = false
|
||||
|
@ -103,6 +115,16 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
tc.processed = make(chan string, 100)
|
||||
tc.computeCPUCurrent()
|
||||
|
||||
// TODO(madhusudancs): HPA only supports resources in extensions/v1beta1 right now. Add
|
||||
// tests for "v1" replicationcontrollers when HPA adds support for cross-group scale.
|
||||
if tc.resource == nil {
|
||||
tc.resource = &fakeResource{
|
||||
name: "test-rc",
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "replicationcontrollers",
|
||||
}
|
||||
}
|
||||
|
||||
fakeClient := &fake.Clientset{}
|
||||
fakeClient.AddReactor("list", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := &extensions.HorizontalPodAutoscalerList{
|
||||
|
@ -115,8 +137,9 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
},
|
||||
Spec: extensions.HorizontalPodAutoscalerSpec{
|
||||
ScaleRef: extensions.SubresourceReference{
|
||||
Kind: "replicationController",
|
||||
Name: rcName,
|
||||
Kind: tc.resource.kind,
|
||||
Name: tc.resource.name,
|
||||
APIVersion: tc.resource.apiVersion,
|
||||
Subresource: "scale",
|
||||
},
|
||||
MinReplicas: &tc.minReplicas,
|
||||
|
@ -143,10 +166,10 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
return true, obj, nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("get", "replicationController", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
fakeClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: rcName,
|
||||
Name: tc.resource.name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: extensions.ScaleSpec{
|
||||
|
@ -154,7 +177,41 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: tc.initialReplicas,
|
||||
Selector: map[string]string{"name": podNamePrefix},
|
||||
Selector: selector,
|
||||
},
|
||||
}
|
||||
return true, obj, nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: tc.resource.name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: tc.initialReplicas,
|
||||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: tc.initialReplicas,
|
||||
Selector: selector,
|
||||
},
|
||||
}
|
||||
return true, obj, nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: tc.resource.name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: tc.initialReplicas,
|
||||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: tc.initialReplicas,
|
||||
Selector: selector,
|
||||
},
|
||||
}
|
||||
return true, obj, nil
|
||||
|
@ -206,7 +263,23 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
return true, newFakeResponseWrapper(heapsterRawMemResponse), nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("update", "replicationController", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
fakeClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := action.(testclient.UpdateAction).GetObject().(*extensions.Scale)
|
||||
replicas := action.(testclient.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
|
||||
assert.Equal(t, tc.desiredReplicas, replicas)
|
||||
tc.scaleUpdated = true
|
||||
return true, obj, nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := action.(testclient.UpdateAction).GetObject().(*extensions.Scale)
|
||||
replicas := action.(testclient.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
|
||||
assert.Equal(t, tc.desiredReplicas, replicas)
|
||||
tc.scaleUpdated = true
|
||||
return true, obj, nil
|
||||
})
|
||||
|
||||
fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||
obj := action.(testclient.UpdateAction).GetObject().(*extensions.Scale)
|
||||
replicas := action.(testclient.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas
|
||||
assert.Equal(t, tc.desiredReplicas, replicas)
|
||||
|
@ -269,7 +342,7 @@ func (tc *testCase) runTest(t *testing.T) {
|
|||
tc.verifyResults(t)
|
||||
}
|
||||
|
||||
func TestDefaultScaleUp(t *testing.T) {
|
||||
func TestDefaultScaleUpRC(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
maxReplicas: 6,
|
||||
|
@ -282,6 +355,42 @@ func TestDefaultScaleUp(t *testing.T) {
|
|||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestDefaultScaleUpDeployment(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
maxReplicas: 6,
|
||||
initialReplicas: 4,
|
||||
desiredReplicas: 5,
|
||||
verifyCPUCurrent: true,
|
||||
reportedLevels: []uint64{900, 950, 950, 1000},
|
||||
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
||||
resource: &fakeResource{
|
||||
name: "test-dep",
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "deployments",
|
||||
},
|
||||
}
|
||||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestDefaultScaleUpReplicaSet(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
maxReplicas: 6,
|
||||
initialReplicas: 4,
|
||||
desiredReplicas: 5,
|
||||
verifyCPUCurrent: true,
|
||||
reportedLevels: []uint64{900, 950, 950, 1000},
|
||||
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
||||
resource: &fakeResource{
|
||||
name: "test-replicaset",
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "replicasets",
|
||||
},
|
||||
}
|
||||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestScaleUp(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
|
@ -296,6 +405,44 @@ func TestScaleUp(t *testing.T) {
|
|||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestScaleUpDeployment(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
maxReplicas: 6,
|
||||
initialReplicas: 3,
|
||||
desiredReplicas: 5,
|
||||
CPUTarget: 30,
|
||||
verifyCPUCurrent: true,
|
||||
reportedLevels: []uint64{300, 500, 700},
|
||||
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
||||
resource: &fakeResource{
|
||||
name: "test-dep",
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "deployments",
|
||||
},
|
||||
}
|
||||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestScaleUpReplicaSet(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
maxReplicas: 6,
|
||||
initialReplicas: 3,
|
||||
desiredReplicas: 5,
|
||||
CPUTarget: 30,
|
||||
verifyCPUCurrent: true,
|
||||
reportedLevels: []uint64{300, 500, 700},
|
||||
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
||||
resource: &fakeResource{
|
||||
name: "test-replicaset",
|
||||
apiVersion: "extensions/v1beta1",
|
||||
kind: "replicasets",
|
||||
},
|
||||
}
|
||||
tc.runTest(t)
|
||||
}
|
||||
|
||||
func TestScaleUpCM(t *testing.T) {
|
||||
tc := testCase{
|
||||
minReplicas: 2,
|
||||
|
|
|
@ -44,11 +44,11 @@ type MetricsClient interface {
|
|||
// GetCPUUtilization returns the average utilization over all pods represented as a percent of requested CPU
|
||||
// (e.g. 70 means that an average pod uses 70% of the requested CPU)
|
||||
// and the time of generation of the oldest of utilization reports for pods.
|
||||
GetCPUUtilization(namespace string, selector map[string]string) (*int, time.Time, error)
|
||||
GetCPUUtilization(namespace string, selector labels.Selector) (*int, time.Time, error)
|
||||
|
||||
// GetCustomMetric returns the average value of the given custom metrics from the
|
||||
// pods picked using the namespace and selector passed as arguments.
|
||||
GetCustomMetric(customMetricName string, namespace string, selector map[string]string) (*float64, time.Time, error)
|
||||
GetCustomMetric(customMetricName string, namespace string, selector labels.Selector) (*float64, time.Time, error)
|
||||
}
|
||||
|
||||
type intAndFloat struct {
|
||||
|
@ -100,7 +100,7 @@ func NewHeapsterMetricsClient(client clientset.Interface, namespace, scheme, ser
|
|||
}
|
||||
}
|
||||
|
||||
func (h *HeapsterMetricsClient) GetCPUUtilization(namespace string, selector map[string]string) (*int, time.Time, error) {
|
||||
func (h *HeapsterMetricsClient) GetCPUUtilization(namespace string, selector labels.Selector) (*int, time.Time, error) {
|
||||
avgConsumption, avgRequest, timestamp, err := h.GetCpuConsumptionAndRequestInMillis(namespace, selector)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, fmt.Errorf("failed to get CPU consumption and request: %v", err)
|
||||
|
@ -109,12 +109,11 @@ func (h *HeapsterMetricsClient) GetCPUUtilization(namespace string, selector map
|
|||
return &utilization, timestamp, nil
|
||||
}
|
||||
|
||||
func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace string, selector map[string]string) (avgConsumption int64,
|
||||
func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace string, selector labels.Selector) (avgConsumption int64,
|
||||
avgRequest int64, timestamp time.Time, err error) {
|
||||
|
||||
labelSelector := labels.SelectorFromSet(labels.Set(selector))
|
||||
podList, err := h.client.Core().Pods(namespace).
|
||||
List(api.ListOptions{LabelSelector: labelSelector})
|
||||
List(api.ListOptions{LabelSelector: selector})
|
||||
|
||||
if err != nil {
|
||||
return 0, 0, time.Time{}, fmt.Errorf("failed to get pod list: %v", err)
|
||||
|
@ -144,7 +143,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
|
|||
if missing || requestSum == 0 {
|
||||
return 0, 0, time.Time{}, fmt.Errorf("some pods do not have request for cpu")
|
||||
}
|
||||
glog.V(4).Infof("%s %v - sum of CPU requested: %d", namespace, selector, requestSum)
|
||||
glog.V(4).Infof("%s %s - sum of CPU requested: %d", namespace, selector, requestSum)
|
||||
requestAvg := requestSum / int64(len(podList.Items))
|
||||
// Consumption is already averaged and in millis.
|
||||
consumption, timestamp, err := h.getForPods(heapsterCpuUsageMetricDefinition, namespace, podNames)
|
||||
|
@ -156,11 +155,10 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
|
|||
|
||||
// GetCustomMetric returns the average value of the given custom metric from the
|
||||
// pods picked using the namespace and selector passed as arguments.
|
||||
func (h *HeapsterMetricsClient) GetCustomMetric(customMetricName string, namespace string, selector map[string]string) (*float64, time.Time, error) {
|
||||
func (h *HeapsterMetricsClient) GetCustomMetric(customMetricName string, namespace string, selector labels.Selector) (*float64, time.Time, error) {
|
||||
metricSpec := getHeapsterCustomMetricDefinition(customMetricName)
|
||||
|
||||
labelSelector := labels.SelectorFromSet(labels.Set(selector))
|
||||
podList, err := h.client.Core().Pods(namespace).List(api.ListOptions{LabelSelector: labelSelector})
|
||||
podList, err := h.client.Core().Pods(namespace).List(api.ListOptions{LabelSelector: selector})
|
||||
|
||||
if err != nil {
|
||||
return nil, time.Time{}, fmt.Errorf("failed to get pod list: %v", err)
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
heapster "k8s.io/heapster/api/v1/types"
|
||||
|
@ -69,15 +70,15 @@ type testCase struct {
|
|||
reportedMetricsPoints [][]metricPoint
|
||||
namespace string
|
||||
podListOverride *api.PodList
|
||||
selector map[string]string
|
||||
selector labels.Selector
|
||||
}
|
||||
|
||||
func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
||||
namespace := "test-namespace"
|
||||
tc.namespace = namespace
|
||||
podNamePrefix := "test-pod"
|
||||
selector := map[string]string{"name": podNamePrefix}
|
||||
tc.selector = selector
|
||||
podLabels := map[string]string{"name": podNamePrefix}
|
||||
tc.selector = labels.SelectorFromSet(podLabels)
|
||||
|
||||
fakeClient := &fake.Clientset{}
|
||||
|
||||
|
@ -88,7 +89,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
obj := &api.PodList{}
|
||||
for i := 0; i < tc.replicas; i++ {
|
||||
podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
|
||||
pod := buildPod(namespace, podName, selector, api.PodRunning)
|
||||
pod := buildPod(namespace, podName, podLabels, api.PodRunning)
|
||||
obj.Items = append(obj.Items, pod)
|
||||
}
|
||||
return true, obj, nil
|
||||
|
@ -120,12 +121,12 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
|
|||
return fakeClient
|
||||
}
|
||||
|
||||
func buildPod(namespace, podName string, selector map[string]string, phase api.PodPhase) api.Pod {
|
||||
func buildPod(namespace, podName string, podLabels map[string]string, phase api.PodPhase) api.Pod {
|
||||
return api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: podName,
|
||||
Namespace: namespace,
|
||||
Labels: selector,
|
||||
Labels: podLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
|
@ -193,10 +194,10 @@ func TestCPUPending(t *testing.T) {
|
|||
|
||||
namespace := "test-namespace"
|
||||
podNamePrefix := "test-pod"
|
||||
selector := map[string]string{"name": podNamePrefix}
|
||||
podLabels := map[string]string{"name": podNamePrefix}
|
||||
for i := 0; i < tc.replicas; i++ {
|
||||
podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
|
||||
pod := buildPod(namespace, podName, selector, api.PodRunning)
|
||||
pod := buildPod(namespace, podName, podLabels, api.PodRunning)
|
||||
tc.podListOverride.Items = append(tc.podListOverride.Items, pod)
|
||||
}
|
||||
tc.podListOverride.Items[0].Status.Phase = api.PodPending
|
||||
|
@ -216,10 +217,10 @@ func TestCPUAllPending(t *testing.T) {
|
|||
|
||||
namespace := "test-namespace"
|
||||
podNamePrefix := "test-pod"
|
||||
selector := map[string]string{"name": podNamePrefix}
|
||||
podLabels := map[string]string{"name": podNamePrefix}
|
||||
for i := 0; i < tc.replicas; i++ {
|
||||
podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
|
||||
pod := buildPod(namespace, podName, selector, api.PodPending)
|
||||
pod := buildPod(namespace, podName, podLabels, api.PodPending)
|
||||
tc.podListOverride.Items = append(tc.podListOverride.Items, pod)
|
||||
}
|
||||
tc.runTest(t)
|
||||
|
@ -248,10 +249,10 @@ func TestQPSPending(t *testing.T) {
|
|||
|
||||
namespace := "test-namespace"
|
||||
podNamePrefix := "test-pod"
|
||||
selector := map[string]string{"name": podNamePrefix}
|
||||
podLabels := map[string]string{"name": podNamePrefix}
|
||||
for i := 0; i < tc.replicas; i++ {
|
||||
podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
|
||||
pod := buildPod(namespace, podName, selector, api.PodRunning)
|
||||
pod := buildPod(namespace, podName, podLabels, api.PodRunning)
|
||||
tc.podListOverride.Items = append(tc.podListOverride.Items, pod)
|
||||
}
|
||||
tc.podListOverride.Items[0].Status.Phase = api.PodPending
|
||||
|
@ -270,10 +271,10 @@ func TestQPSAllPending(t *testing.T) {
|
|||
|
||||
namespace := "test-namespace"
|
||||
podNamePrefix := "test-pod"
|
||||
selector := map[string]string{"name": podNamePrefix}
|
||||
podLabels := map[string]string{"name": podNamePrefix}
|
||||
for i := 0; i < tc.replicas; i++ {
|
||||
podName := fmt.Sprintf("%s-%d", podNamePrefix, i)
|
||||
pod := buildPod(namespace, podName, selector, api.PodPending)
|
||||
pod := buildPod(namespace, podName, podLabels, api.PodPending)
|
||||
tc.podListOverride.Items = append(tc.podListOverride.Items, pod)
|
||||
}
|
||||
tc.podListOverride.Items[0].Status.Phase = api.PodPending
|
||||
|
|
|
@ -743,13 +743,25 @@ func (p *Parser) parseExactValue() (sets.String, error) {
|
|||
// (5) A requirement with just !KEY requires that the KEY not exist.
|
||||
//
|
||||
func Parse(selector string) (Selector, error) {
|
||||
p := &Parser{l: &Lexer{s: selector, pos: 0}}
|
||||
items, error := p.parse()
|
||||
if error == nil {
|
||||
sort.Sort(ByKey(items)) // sort to grant determistic parsing
|
||||
return internalSelector(items), error
|
||||
parsedSelector, err := parse(selector)
|
||||
if err == nil {
|
||||
return parsedSelector, nil
|
||||
}
|
||||
return nil, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse parses the string representation of the selector and returns the internalSelector struct.
|
||||
// The callers of this method can then decide how to return the internalSelector struct to their
|
||||
// callers. This function has two callers now, one returns a Selector interface and the other
|
||||
// returns a list of requirements.
|
||||
func parse(selector string) (internalSelector, error) {
|
||||
p := &Parser{l: &Lexer{s: selector, pos: 0}}
|
||||
items, err := p.parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Sort(ByKey(items)) // sort to grant determistic parsing
|
||||
return internalSelector(items), err
|
||||
}
|
||||
|
||||
var qualifiedNameErrorMsg string = fmt.Sprintf(`must be a qualified name (at most %d characters, matching regex %s), with an optional DNS subdomain prefix (at most %d characters, matching regex %s) and slash (/): e.g. "MyName" or "example.com/MyName"`, validation.QualifiedNameMaxLength, validation.QualifiedNameFmt, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt)
|
||||
|
@ -788,3 +800,12 @@ func SelectorFromSet(ls Set) Selector {
|
|||
sort.Sort(ByKey(requirements))
|
||||
return internalSelector(requirements)
|
||||
}
|
||||
|
||||
// ParseToRequirements takes a string representing a selector and returns a list of
|
||||
// requirements. This function is suitable for those callers that perform additional
|
||||
// processing on selector requirements.
|
||||
// See the documentation for Parse() function for more details.
|
||||
// TODO: Consider exporting the internalSelector type instead.
|
||||
func ParseToRequirements(selector string) ([]Requirement, error) {
|
||||
return parse(selector)
|
||||
}
|
||||
|
|
|
@ -248,12 +248,6 @@ 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{
|
||||
|
@ -723,10 +717,7 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
|
|||
storage["deployments"] = deploymentStorage.Deployment
|
||||
storage["deployments/status"] = deploymentStorage.Status
|
||||
storage["deployments/rollback"] = deploymentStorage.Rollback
|
||||
|
||||
if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) {
|
||||
storage["deployments/scale"] = deploymentStorage.Scale
|
||||
}
|
||||
storage["deployments/scale"] = deploymentStorage.Scale
|
||||
}
|
||||
if isEnabled("jobs") {
|
||||
m.constructJobResources(c, storage)
|
||||
|
@ -744,9 +735,7 @@ 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
|
||||
}
|
||||
storage["replicasets/scale"] = replicaSetStorage.Scale
|
||||
}
|
||||
|
||||
return storage
|
||||
|
|
|
@ -23,9 +23,6 @@ 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"
|
||||
|
@ -192,13 +189,13 @@ var _ = rest.Patcher(&ScaleREST{})
|
|||
|
||||
// New creates a new Scale object
|
||||
func (r *ScaleREST) New() runtime.Object {
|
||||
return &autoscaling.Scale{}
|
||||
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)
|
||||
return nil, errors.NewNotFound(extensions.Resource("deployments/scale"), name)
|
||||
}
|
||||
scale, err := scaleFromDeployment(deployment)
|
||||
if err != nil {
|
||||
|
@ -211,18 +208,18 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
if obj == nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||
}
|
||||
scale, ok := obj.(*autoscaling.Scale)
|
||||
scale, ok := obj.(*extensions.Scale)
|
||||
if !ok {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("expected input object type to be Scale, but %T", 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)
|
||||
return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name)
|
||||
}
|
||||
deployment.Spec.Replicas = scale.Spec.Replicas
|
||||
deployment.ResourceVersion = scale.ResourceVersion
|
||||
|
@ -238,12 +235,8 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
}
|
||||
|
||||
// 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{
|
||||
func scaleFromDeployment(deployment *extensions.Deployment) (*extensions.Scale, error) {
|
||||
return &extensions.Scale{
|
||||
// TODO: Create a variant of ObjectMeta type that only contains the fields below.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: deployment.Name,
|
||||
|
@ -252,12 +245,12 @@ func scaleFromDeployment(deployment *extensions.Deployment) (*autoscaling.Scale,
|
|||
ResourceVersion: deployment.ResourceVersion,
|
||||
CreationTimestamp: deployment.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: deployment.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: deployment.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
Selector: deployment.Spec.Selector,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ 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"
|
||||
|
@ -195,11 +194,7 @@ func TestScaleGet(t *testing.T) {
|
|||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(validDeployment.Spec.Selector)
|
||||
if err != nil {
|
||||
t.Errorf("invalid deployment selector %+v: %v", validDeployment.Spec.Selector, err)
|
||||
}
|
||||
want := &autoscaling.Scale{
|
||||
want := &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
|
@ -207,19 +202,19 @@ func TestScaleGet(t *testing.T) {
|
|||
ResourceVersion: deployment.ResourceVersion,
|
||||
CreationTimestamp: deployment.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: validDeployment.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: validDeployment.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
Selector: validDeployment.Spec.Selector,
|
||||
},
|
||||
}
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
got := obj.(*autoscaling.Scale)
|
||||
got := obj.(*extensions.Scale)
|
||||
if !api.Semantic.DeepEqual(want, got) {
|
||||
t.Errorf("unexpected scale: %s", util.ObjectDiff(want, got))
|
||||
}
|
||||
|
@ -236,9 +231,9 @@ func TestScaleUpdate(t *testing.T) {
|
|||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||
}
|
||||
replicas := 12
|
||||
update := autoscaling.Scale{
|
||||
update := extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
}
|
||||
|
@ -250,7 +245,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
scale := obj.(*autoscaling.Scale)
|
||||
scale := obj.(*extensions.Scale)
|
||||
if scale.Spec.Replicas != replicas {
|
||||
t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas)
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/registry/controller"
|
||||
"k8s.io/kubernetes/pkg/registry/controller/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
|
@ -67,20 +67,7 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
|||
if err != nil {
|
||||
return nil, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), name)
|
||||
}
|
||||
return &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: rc.Namespace,
|
||||
CreationTimestamp: rc.CreationTimestamp,
|
||||
},
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: rc.Spec.Replicas,
|
||||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: rc.Status.Replicas,
|
||||
Selector: rc.Spec.Selector,
|
||||
},
|
||||
}, nil
|
||||
return scaleFromRC(rc), nil
|
||||
}
|
||||
|
||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
|
@ -105,10 +92,17 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
if err != nil {
|
||||
return nil, false, errors.NewConflict(extensions.Resource("replicationcontrollers/scale"), scale.Name, err)
|
||||
}
|
||||
return scaleFromRC(rc), false, nil
|
||||
}
|
||||
|
||||
// scaleFromRC returns a scale subresource for a replication controller.
|
||||
func scaleFromRC(rc *api.ReplicationController) *extensions.Scale {
|
||||
return &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: rc.Name,
|
||||
Namespace: rc.Namespace,
|
||||
UID: rc.UID,
|
||||
ResourceVersion: rc.ResourceVersion,
|
||||
CreationTimestamp: rc.CreationTimestamp,
|
||||
},
|
||||
Spec: extensions.ScaleSpec{
|
||||
|
@ -116,9 +110,11 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: rc.Status.Replicas,
|
||||
Selector: rc.Spec.Selector,
|
||||
Selector: &unversioned.LabelSelector{
|
||||
MatchLabels: rc.Spec.Selector,
|
||||
},
|
||||
},
|
||||
}, false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Dummy implementation
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
|
@ -73,7 +74,9 @@ var validScale = extensions.Scale{
|
|||
},
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: 0,
|
||||
Selector: validPodTemplate.Template.Labels,
|
||||
Selector: &unversioned.LabelSelector{
|
||||
MatchLabels: validPodTemplate.Template.Labels,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,8 @@ import (
|
|||
"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"
|
||||
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||
|
@ -130,13 +128,13 @@ var _ = rest.Patcher(&ScaleREST{})
|
|||
|
||||
// New creates a new Scale object
|
||||
func (r *ScaleREST) New() runtime.Object {
|
||||
return &autoscaling.Scale{}
|
||||
return &extensions.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)
|
||||
return nil, errors.NewNotFound(extensions.Resource("replicasets/scale"), name)
|
||||
}
|
||||
scale, err := scaleFromReplicaSet(rs)
|
||||
if err != nil {
|
||||
|
@ -149,18 +147,18 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
if obj == nil {
|
||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||
}
|
||||
scale, ok := obj.(*autoscaling.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)
|
||||
}
|
||||
|
||||
rs, err := r.registry.GetReplicaSet(ctx, scale.Name)
|
||||
if err != nil {
|
||||
return nil, false, errors.NewNotFound(autoscaling.Resource("replicasets/scale"), scale.Name)
|
||||
return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), scale.Name)
|
||||
}
|
||||
rs.Spec.Replicas = scale.Spec.Replicas
|
||||
rs.ResourceVersion = scale.ResourceVersion
|
||||
|
@ -176,12 +174,8 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||
}
|
||||
|
||||
// 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{
|
||||
func scaleFromReplicaSet(rs *extensions.ReplicaSet) (*extensions.Scale, error) {
|
||||
return &extensions.Scale{
|
||||
// TODO: Create a variant of ObjectMeta type that only contains the fields below.
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: rs.Name,
|
||||
|
@ -190,12 +184,12 @@ func scaleFromReplicaSet(rs *extensions.ReplicaSet) (*autoscaling.Scale, error)
|
|||
ResourceVersion: rs.ResourceVersion,
|
||||
CreationTimestamp: rs.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: rs.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: rs.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
Selector: rs.Spec.Selector,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"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"
|
||||
|
@ -256,11 +255,7 @@ func TestScaleGet(t *testing.T) {
|
|||
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{
|
||||
want := &extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
|
@ -268,16 +263,16 @@ func TestScaleGet(t *testing.T) {
|
|||
ResourceVersion: rs.ResourceVersion,
|
||||
CreationTimestamp: rs.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: validReplicaSet.Spec.Replicas,
|
||||
},
|
||||
Status: autoscaling.ScaleStatus{
|
||||
Status: extensions.ScaleStatus{
|
||||
Replicas: validReplicaSet.Status.Replicas,
|
||||
Selector: selector.String(),
|
||||
Selector: validReplicaSet.Spec.Selector,
|
||||
},
|
||||
}
|
||||
obj, err := storage.Scale.Get(ctx, name)
|
||||
got := obj.(*autoscaling.Scale)
|
||||
got := obj.(*extensions.Scale)
|
||||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
|
@ -299,12 +294,12 @@ func TestScaleUpdate(t *testing.T) {
|
|||
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
||||
}
|
||||
replicas := 12
|
||||
update := autoscaling.Scale{
|
||||
update := extensions.Scale{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: autoscaling.ScaleSpec{
|
||||
Spec: extensions.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
}
|
||||
|
@ -317,7 +312,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("error fetching scale for %s: %v", name, err)
|
||||
}
|
||||
scale := obj.(*autoscaling.Scale)
|
||||
scale := obj.(*extensions.Scale)
|
||||
if scale.Spec.Replicas != replicas {
|
||||
t.Errorf("wrong replicas count expected: %d got: %d", replicas, scale.Spec.Replicas)
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ const (
|
|||
resourceConsumerImage = "gcr.io/google_containers/resource_consumer:beta2"
|
||||
rcIsNil = "ERROR: replicationController = nil"
|
||||
deploymentIsNil = "ERROR: deployment = nil"
|
||||
rsIsNil = "ERROR: replicaset = nil"
|
||||
invalidKind = "ERROR: invalid workload kind for resource consumer"
|
||||
customMetricName = "QPS"
|
||||
)
|
||||
|
@ -298,6 +299,13 @@ func (rc *ResourceConsumer) GetReplicas() int {
|
|||
Failf(deploymentIsNil)
|
||||
}
|
||||
return deployment.Status.Replicas
|
||||
case kindReplicaSet:
|
||||
rs, err := rc.framework.Client.ReplicaSets(rc.framework.Namespace.Name).Get(rc.name)
|
||||
expectNoError(err)
|
||||
if rs == nil {
|
||||
Failf(rsIsNil)
|
||||
}
|
||||
return rs.Status.Replicas
|
||||
default:
|
||||
Failf(invalidKind)
|
||||
}
|
||||
|
@ -381,6 +389,12 @@ func runServiceAndWorkloadForResourceConsumer(c *client.Client, ns, name, kind s
|
|||
}
|
||||
expectNoError(RunDeployment(dpConfig))
|
||||
break
|
||||
case kindReplicaSet:
|
||||
rsConfig := ReplicaSetConfig{
|
||||
rcConfig,
|
||||
}
|
||||
expectNoError(RunReplicaSet(rsConfig))
|
||||
break
|
||||
default:
|
||||
Failf(invalidKind)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
const (
|
||||
kindRC = "replicationController"
|
||||
kindDeployment = "deployment"
|
||||
kindReplicaSet = "replicaset"
|
||||
subresource = "scale"
|
||||
)
|
||||
|
||||
|
@ -41,17 +42,27 @@ var _ = Describe("Horizontal pod autoscaling (scale resource: CPU)", func() {
|
|||
titleUp := "Should scale from 1 pod to 3 pods and from 3 to 5 and verify decision stability"
|
||||
titleDown := "Should scale from 5 pods to 3 pods and from 3 to 1 and verify decision stability"
|
||||
|
||||
// TODO(madhusudancs): Fix this when Scale group issues are resolved (see issue #18528).
|
||||
// These tests take ~20 minutes each.
|
||||
// Describe("[Serial] [Slow] Deployment", func() {
|
||||
// // CPU tests via deployments
|
||||
// It(titleUp, func() {
|
||||
// scaleUp("deployment", kindDeployment, rc, f)
|
||||
// })
|
||||
// It(titleDown, func() {
|
||||
// scaleDown("deployment", kindDeployment, rc, f)
|
||||
// })
|
||||
// })
|
||||
Describe("[Serial] [Slow] Deployment", func() {
|
||||
// CPU tests via deployments
|
||||
It(titleUp, func() {
|
||||
scaleUp("test-deployment", kindDeployment, rc, f)
|
||||
})
|
||||
It(titleDown, func() {
|
||||
scaleDown("test-deployment", kindDeployment, rc, f)
|
||||
})
|
||||
})
|
||||
|
||||
// These tests take ~20 minutes each.
|
||||
Describe("[Serial] [Slow] ReplicaSet", func() {
|
||||
// CPU tests via deployments
|
||||
It(titleUp, func() {
|
||||
scaleUp("rs", kindReplicaSet, rc, f)
|
||||
})
|
||||
It(titleDown, func() {
|
||||
scaleDown("rs", kindReplicaSet, rc, f)
|
||||
})
|
||||
})
|
||||
|
||||
// These tests take ~20 minutes each.
|
||||
Describe("[Serial] [Slow] ReplicationController", func() {
|
||||
|
|
|
@ -294,6 +294,10 @@ type DeploymentConfig struct {
|
|||
RCConfig
|
||||
}
|
||||
|
||||
type ReplicaSetConfig struct {
|
||||
RCConfig
|
||||
}
|
||||
|
||||
func nowStamp() string {
|
||||
return time.Now().Format(time.StampMilli)
|
||||
}
|
||||
|
@ -1788,6 +1792,59 @@ func (config *DeploymentConfig) create() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RunReplicaSet launches (and verifies correctness) of a ReplicaSet
|
||||
// and waits until all the pods it launches to reach the "Running" state.
|
||||
// It's the caller's responsibility to clean up externally (i.e. use the
|
||||
// namespace lifecycle for handling cleanup).
|
||||
func RunReplicaSet(config ReplicaSetConfig) error {
|
||||
err := config.create()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return config.start()
|
||||
}
|
||||
|
||||
func (config *ReplicaSetConfig) create() error {
|
||||
By(fmt.Sprintf("creating replicaset %s in namespace %s", config.Name, config.Namespace))
|
||||
rs := &extensions.ReplicaSet{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: config.Name,
|
||||
},
|
||||
Spec: extensions.ReplicaSetSpec{
|
||||
Replicas: config.Replicas,
|
||||
Selector: &unversioned.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"name": config.Name,
|
||||
},
|
||||
},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: map[string]string{"name": config.Name},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: config.Name,
|
||||
Image: config.Image,
|
||||
Command: config.Command,
|
||||
Ports: []api.ContainerPort{{ContainerPort: 80}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
config.applyTo(rs.Spec.Template)
|
||||
|
||||
_, err := config.Client.ReplicaSets(config.Namespace).Create(rs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating replica set: %v", err)
|
||||
}
|
||||
Logf("Created replica set with name: %v, namespace: %v, replica count: %v", rs.Name, config.Namespace, rs.Spec.Replicas)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunRC Launches (and verifies correctness) of a Replication Controller
|
||||
// and will wait for all pods it spawns to become "Running".
|
||||
// It's the caller's responsibility to clean up externally (i.e. use the
|
||||
|
|
Loading…
Reference in New Issue