提交 76350d28 编写于 作者: K Kenan Karamehmedovic 提交者: Marcin Maciaszczyk

Scaling for Statefulset resource (#1957)

上级 9c3a5fae
......@@ -30,7 +30,7 @@ type ReplicaCounts struct {
// GetScaleSpec returns a populated ReplicaCounts object with desired and actual number of replicas.
func GetScaleSpec(client client.Interface, kind, namespace, name string) (rc *ReplicaCounts, err error) {
rc = new(ReplicaCounts)
s, err := client.Extensions().Scales(namespace).Get(kind, name)
s, err := client.ExtensionsV1beta1().Scales(namespace).Get(kind, name)
if err != nil {
return nil, err
}
......@@ -47,6 +47,8 @@ func ScaleResource(client client.Interface, kind, namespace, name, count string)
rc = new(ReplicaCounts)
if strings.ToLower(kind) == "job" {
err = scaleJobResource(client, namespace, name, count, rc)
} else if strings.ToLower(kind) == "statefulset" {
err = scaleStatefulSetResource(client, namespace, name, count, rc)
} else {
err = scaleGenericResource(client, kind, namespace, name, count, rc)
}
......@@ -59,7 +61,7 @@ func ScaleResource(client client.Interface, kind, namespace, name, count string)
//ScaleGenericResource is used for Deployment, ReplicaSet, Replication Controller scaling.
func scaleGenericResource(client client.Interface, kind, namespace, name, count string, rc *ReplicaCounts) error {
s, err := client.Extensions().Scales(namespace).Get(kind, name)
s, err := client.ExtensionsV1beta1().Scales(namespace).Get(kind, name)
if err != nil {
return err
}
......@@ -68,7 +70,7 @@ func scaleGenericResource(client client.Interface, kind, namespace, name, count
return err
}
s.Spec.Replicas = int32(c)
s, err = client.Extensions().Scales(namespace).Update(kind, s)
s, err = client.ExtensionsV1beta1().Scales(namespace).Update(kind, s)
if err != nil {
return err
}
......@@ -93,3 +95,20 @@ func scaleJobResource(client client.Interface, namespace, name, count string, rc
return nil
}
// scaleStatefulSet is exclusively used for statefulsets
func scaleStatefulSetResource(client client.Interface, namespace, name, count string, rc *ReplicaCounts) error {
ss, err := client.AppsV1beta1().StatefulSets(namespace).Get(name, metaV1.GetOptions{})
c, err := strconv.Atoi(count)
if err != nil {
return err
}
*ss.Spec.Replicas = int32(c)
ss, err = client.AppsV1beta1().StatefulSets(namespace).Update(ss)
rc.DesiredReplicas = *ss.Spec.Replicas
rc.ActualReplicas = ss.Status.Replicas
return nil
}
......@@ -13,7 +13,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<md-button ng-click="$ctrl.handleScaleResourceDialog()">
<md-icon class="kd-actionbar-icon-button">linear_scale</md-icon>
<md-tooltip md-direction="bottom">
[[Edit number of pods|Tooltip for the 'scale' button on the action bar of a statefulset details view.]]
</md-tooltip>
[[Scale|Tooltip for the 'scale' button on the action bar of a statefulset details view.]]
</md-button>
<kd-actionbar-detail-buttons resource-kind-name="[[Stateful Set|Label 'Stateful Set' which appears at the top of the delete dialog, opened from a stateful set details page.]]"
type-meta="$ctrl.details.typeMeta"
object-meta="$ctrl.details.objectMeta">
......
......@@ -18,10 +18,24 @@
export class ActionBarController {
/**
* @param {!backendApi.StatefulSetDetail} statefulSetDetail
* @param {!./../../common/scaling/service.ScaleService} kdScaleService
* @ngInject
*/
constructor(statefulSetDetail) {
constructor(statefulSetDetail, kdScaleService) {
/** @private {!./../../common/scaling/service.ScaleService} */
this.kdScaleService_ = kdScaleService;
/** @export {!backendApi.StatefulSetDetail} */
this.details = statefulSetDetail;
}
/**
* Handles update of replicas count in statefulset controller dialog.
* @export
*/
handleScaleResourceDialog() {
this.kdScaleService_.showScaleDialog(
this.details.objectMeta.namespace, this.details.objectMeta.name,
this.details.podInfo.current, this.details.podInfo.desired, this.details.typeMeta.kind);
}
}
......@@ -27,7 +27,6 @@ limitations under the License.
</div>
<kd-stateful-set-info stateful-set="::ctrl.statefulSetDetail"></kd-stateful-set-info>
<kd-content-card>
<kd-content>
<kd-pod-card-list pod-list="::ctrl.statefulSetDetail.podList"
......@@ -39,6 +38,26 @@ limitations under the License.
</kd-pod-card-list>
</kd-content>
</kd-content-card>
<kd-content-card>
<kd-content>
<kd-service-card-list service-list="::ctrl.statefulSetDetail.serviceList"
service-list-resource="::ctrl.statefulSetServiceResource">
<kd-empty-list-text>
[[There are currently no Services with the same label selector as this Replica Set.|Text for services card zerostate in replica set details page.]]
</kd-empty-list-text>
</kd-service-card-list>
</kd-content>
</kd-content-card>
<kd-content-card>
<kd-content>
<kd-horizontal-pod-autoscaler-card-list horizontal-pod-autoscaler-list="::ctrl.statefulSetDetail.horizontalPodAutoscalerList">
<kd-empty-list-text>
[[There are currently no Horizontal Pod Autoscalers targeting this Replica Set.|Text for horizontal pod autoscalers card zerostate in replica set details page.]]
</kd-empty-list-text>
</kd-horizontal-pod-autoscaler-card-list>
</kd-content>
</kd-content-card>
<kd-event-card-list event-list="::ctrl.statefulSetDetail.eventList"
event-list-resource="::ctrl.eventListResource"></kd-event-card-list>
......@@ -75,6 +75,11 @@ limitations under the License.
</kd-resource-card-column>
<kd-resource-card-column class="kd-row-layout-column kd-icon-column">
<kd-resource-card-menu>
<md-menu-item>
<md-button ng-click="$ctrl.showScaleDialog()">
[[Scale|Action 'Edit Pod Count' on the drop down menu for a single statefulset (statefulset list page).]]
</md-button>
</md-menu-item>
<kd-resource-card-delete-menu-item resource-kind-name="[[Stateful Set|Label 'Stateful Set' which will appear in the stateful set delete dialog opened from a stateful set card on the list page.]]">
</kd-resource-card-delete-menu-item>
<kd-resource-card-edit-menu-item resource-kind-name="[[Stateful Set|Label 'Stateful Set' which will appear in the stateful set delete dialog opened from a stateful set card on the list page.]]">
......
......@@ -25,9 +25,10 @@ export default class StatefulSetCardController {
* @param {!ui.router.$state} $state
* @param {!angular.$interpolate} $interpolate
* @param {!./../../common/namespace/service.NamespaceService} kdNamespaceService
* @param {!./../../common/scaling/service.ScaleService} kdScaleService
* @ngInject
*/
constructor($state, $interpolate, kdNamespaceService) {
constructor($state, $interpolate, kdNamespaceService, kdScaleService) {
/**
* Initialized from the scope.
* @export {!backendApi.StatefulSet}
......@@ -42,6 +43,9 @@ export default class StatefulSetCardController {
/** @private {!./../../common/namespace/service.NamespaceService} */
this.kdNamespaceService_ = kdNamespaceService;
/** @private {!./../../common/scaling/service.ScaleService} */
this.kdScaleService_ = kdScaleService;
}
/**
......@@ -52,6 +56,16 @@ export default class StatefulSetCardController {
return this.kdNamespaceService_.areMultipleNamespacesSelected();
}
/**
* @export
*/
showScaleDialog() {
this.kdScaleService_.showScaleDialog(
this.statefulSet.objectMeta.namespace, this.statefulSet.objectMeta.name,
this.statefulSet.pods.current, this.statefulSet.pods.desired,
this.statefulSet.typeMeta.kind);
}
/**
* @return {string}
* @export
......
......@@ -20,15 +20,21 @@
export class StatefulSetCardListController {
/**
* @param {!./../../common/namespace/service.NamespaceService} kdNamespaceService
* @param {!./../../common/scaling/service.ScaleService} kdScaleService
* @ngInject
*/
constructor(kdNamespaceService) {
constructor(kdNamespaceService, kdScaleService) {
/** @private {!./../../common/namespace/service.NamespaceService} */
this.kdNamespaceService_ = kdNamespaceService;
/** @export {!backendApi.StatefulSetList} - Initialized from binding. */
this.statefulSetList;
/** @export {!angular.Resource} Initialized from binding. */
this.statefulSetListResource;
/** @private {!./../../common/scaling/service.ScaleService} */
this.kdScaleService_ = kdScaleService;
}
/**
......
......@@ -16,6 +16,7 @@ import chromeModule from 'chrome/module';
import componentsModule from 'common/components/module';
import filtersModule from 'common/filters/module';
import namespaceModule from 'common/namespace/module';
import {ScaleService} from 'common/scaling/service';
import eventsModule from 'events/module';
import {statefulSetInfoComponent} from './detail/info_component';
......@@ -45,6 +46,7 @@ export default angular
.component('kdStatefulSetCard', statefulSetCardComponent)
.component('kdStatefulSetCardList', statefulSetCardListComponent)
.component('kdStatefulSetInfo', statefulSetInfoComponent)
.service('kdScaleService', ScaleService)
.factory('kdStatefulSetEventsResource', statefulSetEventsResource)
.factory('kdStatefulSetListResource', statefulSetListResource)
.factory('kdStatefulSetPodsResource', statefulSetPodsResource);
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import ScaleResourceDialogController from 'common/scaling/controller';
import statefulsetModule from 'statefulset/module';
describe('Update Deployment', () => {
/**
* Replicaset Detail controller.
* @type {!ScaleResourceDialogController}
*/
let ctrl;
/** @type {!md.$dialog} */
let mdDialog;
/** @type {!ui.router.$state} */
let state;
/** @type {!angular.$resource} */
let resource;
/** @type {!angular.$httpBackend} */
let httpBackend;
/** @type {!angular.$log} */
let log;
/** @type {string} */
let namespaceMock = 'foo-namespace';
/** @type {string} */
let replicaSetMock = 'foo-name';
/** @type {string} */
let resourceKindNameMock = 'statefulset';
beforeEach(() => {
angular.mock.module(statefulsetModule.name);
angular.mock.inject(($log, $state, $mdDialog, $controller, $httpBackend, $resource) => {
mdDialog = $mdDialog;
state = $state;
resource = $resource;
httpBackend = $httpBackend;
log = $log;
ctrl = $controller(ScaleResourceDialogController, {
$resource: resource,
namespace: namespaceMock,
currentPods: 1,
desiredPods: 2,
resourceName: replicaSetMock,
resourceKindName: resourceKindNameMock,
});
});
});
it('should update statefulset replicas to given number and log success', () => {
// given
let replicaCounts = {
desiredReplicas: 2,
actualReplicas: 1,
};
spyOn(log, 'info');
spyOn(state, 'reload');
httpBackend.whenPUT('api/v1/scale/statefulset/foo-namespace/foo-name?scaleBy=2')
.respond(200, replicaCounts);
// when
ctrl.scaleResource();
httpBackend.flush();
// then
expect(log.info).toHaveBeenCalledWith(
`Successfully updated replicas number to ${replicaCounts.desiredReplicas}`);
expect(state.reload).toHaveBeenCalled();
});
it('should log error on failed update', () => {
// given
spyOn(log, 'error');
httpBackend.whenPUT('api/v1/scale/statefulset/foo-namespace/foo-name?scaleBy=2').respond(404);
// when
ctrl.scaleResource();
httpBackend.flush();
// then
expect(log.error).toHaveBeenCalled();
});
it('should close the dialog on cancel', () => {
spyOn(state, 'reload');
// given
spyOn(mdDialog, 'cancel');
// when
ctrl.cancel();
// then
expect(mdDialog.cancel).toHaveBeenCalled();
expect(state.reload).not.toHaveBeenCalled();
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册