Skip to content

Commit

Permalink
Merge pull request #293 from wilhelmguo/feature/add_kubernetes_hpa
Browse files Browse the repository at this point in the history
Add kubernetes hpa support
  • Loading branch information
wilhelmguo committed Feb 19, 2019
2 parents 3a35127 + 65453d8 commit c619329
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/frontend/src/app/admin/admin-routing.module.ts
Expand Up @@ -81,6 +81,7 @@ import { KubeJobComponent } from './kubernetes/job/kube-job.component';
import { KubePvcComponent } from './kubernetes/pvc/kube-pvc.component';
import { KubeReplicasetComponent } from './kubernetes/replicaset/kube-replicaset.component';
import { KubeStorageclassComponent } from './kubernetes/storageclass/kube-storageclass.component';
import { KubeHpaComponent } from './kubernetes/hpa/kube-hpa.component';


const routes: Routes = [
Expand Down Expand Up @@ -187,6 +188,8 @@ const routes: Routes = [
{path: 'kubernetes/replicaset/:cluster', component: KubeReplicasetComponent},
{path: 'kubernetes/storageclass', component: KubeStorageclassComponent},
{path: 'kubernetes/storageclass/:cluster', component: KubeStorageclassComponent},
{path: 'kubernetes/horizontalpodautoscaler', component: KubeHpaComponent},
{path: 'kubernetes/horizontalpodautoscaler/:cluster', component: KubeHpaComponent},
...ADMINROUTES
]
}
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/app/admin/admin.module.ts
Expand Up @@ -61,6 +61,7 @@ import { KubeJobModule } from './kubernetes/job/kube-job.module';
import { KubeReplicasetModule } from './kubernetes/replicaset/kube-replicaset.module';
import { KubePvcModule } from './kubernetes/pvc/kube-pvc.module';
import { KubeStorageclassModule } from './kubernetes/storageclass/kube-storageclass.module';
import { KubeHpaModule } from './kubernetes/hpa/kube-hpa.module';

@NgModule({
imports: [
Expand Down Expand Up @@ -115,7 +116,8 @@ import { KubeStorageclassModule } from './kubernetes/storageclass/kube-storagecl
KubeReplicasetModule,
KubeJobModule,
KubePvcModule,
KubeStorageclassModule
KubeStorageclassModule,
KubeHpaModule
],
providers: [
AdminAuthCheckGuard,
Expand Down
52 changes: 52 additions & 0 deletions src/frontend/src/app/admin/kubernetes/hpa/kube-hpa.component.html
@@ -0,0 +1,52 @@
<div class="clr-row">
<div class="clr-col-lg-12 clr-col-md-12 clr-col-sm-12 clr-col-xs-12">
<div class="table-search">
<div class="table-search-left">
<button class="wayne-button normal" (click)="createResource()">
{{'ADMIN.KUBERNETES.HPA.CREATE' | translate}}
</button>
<button class="wayne-button normal" (click)="retrieveResource()">
{{'ADMIN.KUBERNETES.ACTION.REFRESH' | translate}}
</button>
<wayne-filter-box (confirm)="onConfirmEvent()" (cancel)="onCancelEvent()">
<wayne-checkbox-group [(ngModel)]="showList">
<wayne-checkbox value="name">{{'ADMIN.KUBERNETES.HPA.LIST.NAME' | translate}}</wayne-checkbox>
<wayne-checkbox value="label">{{'ADMIN.KUBERNETES.HPA.LIST.LABEL' | translate}}</wayne-checkbox>
<wayne-checkbox value="reference">{{'ADMIN.KUBERNETES.HPA.LIST.REFERENCE' | translate}}</wayne-checkbox>
<wayne-checkbox value="targets">{{'ADMIN.KUBERNETES.HPA.LIST.TARGETS' | translate}}</wayne-checkbox>
<wayne-checkbox value="minpods">{{'ADMIN.KUBERNETES.HPA.LIST.MINPODS' | translate}}</wayne-checkbox>
<wayne-checkbox value="maxpods">{{'ADMIN.KUBERNETES.HPA.LIST.MAXPODS' | translate}}</wayne-checkbox>
<wayne-checkbox value="replicas">{{'ADMIN.KUBERNETES.HPA.LIST.REPLICAS' | translate}}</wayne-checkbox>
<wayne-checkbox value="age">{{'ADMIN.KUBERNETES.HPA.LIST.AGE' | translate}}</wayne-checkbox>
</wayne-checkbox-group>
</wayne-filter-box>
<label for="namespace_name" class="clr-col-md-3">{{'ADMIN.KUBERNETES.LABEL.NAMESPACE' | translate}}</label>
<wayne-select [(ngModel)]="namespace" (change)="retrieveResource()"
searchable
name="namespace_name"
[placeholder]="'PLACEHOLDER.CHOOSE' | translate"
style="margin-left: 12px;">
<wayne-option *ngFor="let ns of namespaces" [value]="ns">{{ns}}</wayne-option>
</wayne-select>
</div>
</div>

<wayne-list-hpa
[resources]="resources"
[showState]="showState"
(delete)="onDeleteResourceEvent($event)"
(edit)="onEditResourceEvent($event)"
[page]="pageState.page"
[cluster]="cluster"
(migration)="migration($event)"
(paginate)="retrieveResource($event)">
</wayne-list-hpa>
</div>
</div>
<kube-migration></kube-migration>
<deletion-dialog (outputObj)="confirmDeleteEvent($event)"></deletion-dialog>
<wayne-ace-editor (createOutputObj)="onCreateResourceEvent($event)" (outputObj)="onSaveResourceEvent($event)"></wayne-ace-editor>
<wayne-float-window value="{{ cluster }}">
<wayne-float-window-item *ngFor="let cluster of clusters" [value]="cluster"
(click)="jumpToHref(cluster)"></wayne-float-window-item>
</wayne-float-window>
68 changes: 68 additions & 0 deletions src/frontend/src/app/admin/kubernetes/hpa/kube-hpa.component.ts
@@ -0,0 +1,68 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service';
import { ClusterService } from '../../../shared/client/v1/cluster.service';
import { AuthService } from '../../../shared/auth/auth.service';
import { AceEditorComponent } from '../../../shared/ace-editor/ace-editor.component';
import { KubernetesClient } from '../../../shared/client/v1/kubernetes/kubernetes';
import { KubeResourceHorizontalPodAutoscaler } from '../../../shared/shared.const';
import { KubernetesNamespacedResource } from '../../../shared/base/kubernetes-namespaced/kubernetes-namespaced-resource';
import { DeletionDialogComponent } from '../../../shared/deletion-dialog/deletion-dialog.component';
import { MigrationComponent } from './migration/migration.component';
import { ListHpaComponent } from './list-hpa/list-hpa.component';

const showState = {
'name': {hidden: false},
'label': {hidden: false},
'reference': {hidden: false},
'targets': {hidden: false},
'minpods': {hidden: false},
'maxpods': {hidden: false},
'replicas': {hidden: false},
'age': {hidden: false},
};

@Component({
selector: 'wayne-kube-hpa',
templateUrl: './kube-hpa.component.html'
})

export class KubeHpaComponent extends KubernetesNamespacedResource implements OnInit, OnDestroy {
@ViewChild(ListHpaComponent)
listResourceComponent: ListHpaComponent;

@ViewChild(AceEditorComponent)
aceEditorModal: AceEditorComponent;

@ViewChild(DeletionDialogComponent)
deletionDialogComponent: DeletionDialogComponent;

@ViewChild(MigrationComponent)
migrationComponent: MigrationComponent;

constructor(public kubernetesClient: KubernetesClient,
public route: ActivatedRoute,
public router: Router,
public clusterService: ClusterService,
public authService: AuthService,
public messageHandlerService: MessageHandlerService) {
super(kubernetesClient, route, router, clusterService, authService, messageHandlerService);
super.registResourceType('horizontalpodautoscaler');
super.registKubeResource(KubeResourceHorizontalPodAutoscaler);
super.registShowSate(showState);
}

ngOnInit() {
super.ngOnInit();
}

ngOnDestroy(): void {
super.ngOnDestroy();
}


migration(obj: any) {
this.migrationComponent.openModal(this.cluster, obj);
}

}
31 changes: 31 additions & 0 deletions src/frontend/src/app/admin/kubernetes/hpa/kube-hpa.module.ts
@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../shared/shared.module';
import { ReactiveFormsModule } from '@angular/forms';
import { KubeHpaComponent } from './kube-hpa.component';
import { KubernetesClient } from '../../../shared/client/v1/kubernetes/kubernetes';
import { DeletionDialogModule } from '../../../shared/deletion-dialog/deletion-dialog.module';
import { MigrationComponent } from './migration/migration.component';
import { ListHpaComponent } from './list-hpa/list-hpa.component';

@NgModule({
imports: [
SharedModule,
ReactiveFormsModule,
DeletionDialogModule
],
providers: [
KubernetesClient
],
exports: [
KubeHpaComponent,
ListHpaComponent
],
declarations: [
KubeHpaComponent,
ListHpaComponent,
MigrationComponent
]
})

export class KubeHpaModule {
}
@@ -0,0 +1,71 @@
<clr-datagrid (clrDgRefresh)="refresh($event)">
<clr-dg-column class="col-app-name" [clrDgField]="'name'">
<ng-container *clrDgHideableColumn="showState['name']">
{{'ADMIN.KUBERNETES.HPA.LIST.NAME' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['label']">
{{'ADMIN.KUBERNETES.HPA.LIST.LABEL' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['reference']">
{{'ADMIN.KUBERNETES.HPA.LIST.REFERENCE' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['targets']">
{{'ADMIN.KUBERNETES.HPA.LIST.TARGETS' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['minpods']">
{{'ADMIN.KUBERNETES.HPA.LIST.MINPODS' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['maxpods']">
{{'ADMIN.KUBERNETES.HPA.LIST.MAXPODS' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column>
<ng-container *clrDgHideableColumn="showState['replicas']">
{{'ADMIN.KUBERNETES.HPA.LIST.REPLICAS' | translate}}
</ng-container>
</clr-dg-column>
<clr-dg-column [clrDgField]="'creationTimestamp'">
<ng-container *clrDgHideableColumn="showState['age']">
{{'ADMIN.KUBERNETES.HPA.LIST.AGE' | translate}}
</ng-container>
</clr-dg-column>


<clr-dg-row *ngFor="let obj of resources" [clrDgItem]="obj">
<clr-dg-action-overflow>
<button class="action-item" (click)="onEditEvent(obj)">{{'ADMIN.KUBERNETES.ACTION.EDIT' | translate}}</button>
<button class="action-item" (click)="onDeleteEvent(obj)">{{'ADMIN.KUBERNETES.ACTION.DELETE' | translate}}</button>
<button class="action-item" (click)="migrationResource(obj)">{{'ADMIN.KUBERNETES.ACTION.MIGRATION' | translate}}</button>
</clr-dg-action-overflow>
<clr-dg-cell class="col-app-name"> {{ obj.metadata.name }} </clr-dg-cell>
<clr-dg-cell>
<div *ngFor="let label of obj.metadata.labels | keyvalue" class="version-text">
<a href="javascript:" (click)="versionDetail(label.key + ': ' + label.value)">{{label.key}}: {{label.value}}</a>
</div>
</clr-dg-cell>
<clr-dg-cell> {{ obj.spec.scaleTargetRef?.kind}}/{{ obj.spec.scaleTargetRef?.name}} </clr-dg-cell>
<clr-dg-cell> {{ obj.status.currentCPUUtilizationPercentage !== undefined ? obj.status.currentCPUUtilizationPercentage + '%' : 'unknown'}}/{{ obj.spec.targetCPUUtilizationPercentage }}% </clr-dg-cell>
<clr-dg-cell> {{ obj.spec.minReplicas}}</clr-dg-cell>
<clr-dg-cell> {{ obj.spec.maxReplicas}}</clr-dg-cell>
<clr-dg-cell> {{ obj.status.currentReplicas}}</clr-dg-cell>
<clr-dg-cell> {{ obj.metadata.creationTimestamp | relativeTime}} </clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<wayne-paginate
[(currentPage)]="currentPage"
[total]="page.totalCount"
[pageSizes]="[10, 20, 50]"
(sizeChange)="pageSizeChange($event)">
</wayne-paginate>
</clr-dg-footer>
</clr-datagrid>
@@ -0,0 +1,23 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { KubernetesListResource } from '../../../../shared/base/kubernetes-namespaced/kubernetes-list-resource';
import { TplDetailService } from '../../../../shared/tpl-detail/tpl-detail.service';

@Component({
selector: 'wayne-list-hpa',
templateUrl: './list-hpa.component.html'
})

export class ListHpaComponent extends KubernetesListResource {
@Input() resources: any[];
@Input() showState: object;

@Output() migration = new EventEmitter<any>();

constructor(public tplDetailService: TplDetailService) {
super(tplDetailService);
}

migrationResource(obj: any) {
this.migration.emit(obj);
}
}
@@ -0,0 +1,32 @@
<clr-modal [(clrModalOpen)]="modalOpened" [clrModalSize]="'xl'" #modal>
<h3 class="modal-title">迁移资源
<wayne-modal-operate [modal]="modal" *ngIf="modalOpened"></wayne-modal-operate>
</h3>
<div class="modal-body">
<form #ngForm="ngForm">
<section class="form-block">
<div class="form-group" style="padding-left: 135px;">
<label for="app" class="clr-col-md-3 form-group-label-override required">应用</label>
<div class="select form-control">
<wayne-select name="app" [(ngModel)]="selectedApp"
searchable
[placeholder]="'PLACEHOLDER.CHOOSE' | translate">
<wayne-option *ngFor="let app of apps" [value]="app">{{app.name}}</wayne-option>
</wayne-select>
</div>
</div>
<div class="form-group" style="padding-left: 135px;">
<label class="clr-col-md-3 form-group-label-override">模版</label>
<wayne-ace-editor-box></wayne-ace-editor-box>

</div>
</section>
</form>
<div class="modal-footer">

<button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" [disabled]="!isValid"
(click)="onSubmit()">{{'BUTTON.SUBMIT' | translate}}</button>
</div>
</div>
</clr-modal>
@@ -0,0 +1,64 @@
import { Component, OnInit } from '@angular/core';
import { AppService } from '../../../../shared/client/v1/app.service';
import { AceEditorService } from '../../../../shared/ace-editor/ace-editor.service';
import { MessageHandlerService } from '../../../../shared/message-handler/message-handler.service';
import { MigrationResource } from '../../../../shared/base/kubernetes-namespaced/migration-resource';
import { KubernetesClient } from '../../../../shared/client/v1/kubernetes/kubernetes';
import { KubeResourceHorizontalPodAutoscaler } from '../../../../shared/shared.const';
import { AutoscaleService } from '../../../../shared/client/v1/autoscale.service';
import { AutoscaleTplService } from '../../../../shared/client/v1/autoscaletpl.service';
import { AutoscaleTpl } from '../../../../shared/model/v1/autoscaletpl';
import { Autoscale } from '../../../../shared/model/v1/autoscale';

@Component({
selector: 'kube-migration',
templateUrl: 'migration.component.html'
})
export class MigrationComponent extends MigrationResource implements OnInit {

constructor(private hpaService: AutoscaleService,
private hpaTplService: AutoscaleTplService,
public appService: AppService,
public kubernetesClient: KubernetesClient,
public aceEditorService: AceEditorService,
public messageHandlerService: MessageHandlerService) {
super(kubernetesClient, appService, aceEditorService, messageHandlerService);
super.registKubeResource(KubeResourceHorizontalPodAutoscaler);
}

ngOnInit(): void {
super.ngOnInit();
}

onSubmit() {
if (this.isSubmitOnGoing) {
return;
}
this.isSubmitOnGoing = true;
const resource = new Autoscale();
resource.name = this.obj.metadata.name;
resource.appId = this.selectedApp.id;
this.hpaService.create(resource).subscribe(
resp => {
const data = resp.data;
const tpl = new AutoscaleTpl();
tpl.name = this.obj.metadata.name;
tpl.hpaId = data.id;
tpl.template = JSON.stringify(this.obj);
tpl.description = 'migration from kubernetes. ';
this.hpaTplService.create(tpl, this.selectedApp.id).subscribe(
() => {
this.messageHandlerService.showSuccess('资源创建成功!请前往前台手动发布到相应机房!');
},
error => {
this.messageHandlerService.handleError(error);
});
},
error => {
this.messageHandlerService.handleError(error);
}
);
this.modalOpened = false;
}

}
7 changes: 7 additions & 0 deletions src/frontend/src/app/admin/sidenav/sidenav.component.html
Expand Up @@ -84,6 +84,13 @@
<clr-icon clrVerticalNavIcon shape="tree"></clr-icon>
Pod
</a>
<a clrVerticalNavLink
routerLink="kubernetes/horizontalpodautoscaler"
[routerLinkActiveOptions]="{exact:true}"
routerLinkActive="active">
<clr-icon clrVerticalNavIcon shape="cloud-scale"></clr-icon>
HPA
</a>
<div class="nav-divider"></div>
<a clrVerticalNavLink
routerLink="kubernetes/service"
Expand Down

0 comments on commit c619329

Please sign in to comment.