Copy over more services for polling

Use a class for rollout status response

Add some better errors

Add override styles for success case
This commit is contained in:
Sam Chow 2018-08-24 14:02:13 -04:00
parent d936d778da
commit 128cf0a28d
8 changed files with 318 additions and 72 deletions

View file

@ -43,12 +43,16 @@
<code>{{deployment.name}}</code>: {{deployment.message || 'Waiting for deployment information...'}}
</li>
</div>
<div ng-if="$ctrl.state === 'deployed'">
Configuration successfully deployed!
</div>
</div>
<div ng-if="$ctrl.state === 'error'">
</div>
<div ng-if="$ctrl.state === 'deployed'" class="modal-footer co-alert co-alert-success">
Configuration successfully rolled out and deployed!
<br>Note: The web interface of the Quay app may take a few minutes to come up.
</div>
<div ng-if="$ctrl.state === 'error'" class="modal-footer alert alert-danger">
{{ $ctrl.errorMessage }}
<div ng-if="$ctrl.offerRollback">
// todo
</div>
</div>
</div><!-- /.modal-content -->

View file

@ -1,4 +1,5 @@
import {Component, EventEmitter, Inject} from 'ng-metadata/core';
import {Component, EventEmitter, Inject, OnDestroy } from 'ng-metadata/core';
import {AngularPollChannel, PollHandle} from "../../services/services.types";
const templateUrl = require('./kube-deploy-modal.component.html');
const styleUrl = require('./kube-deploy-modal.css');
@ -8,12 +9,19 @@ type DeploymentRollout = {
message: string
};
type DeploymentStatus = {
name: string,
numPods: number,
message?: string,
pollHandler?: PollHandle,
}
@Component({
selector: 'kube-deploy-modal',
templateUrl,
styleUrls: [ styleUrl ],
})
export class KubeDeployModalComponent {
export class KubeDeployModalComponent implements OnDestroy {
private state
: 'loadingDeployments'
| 'readyToDeploy'
@ -21,13 +29,13 @@ export class KubeDeployModalComponent {
| 'cyclingDeployments'
| 'deployed'
| 'error';
private errorMessage: string;
private deploymentsStatus: { name: string, numPods: number, message?: string }[] = [];
private offerRollback: boolean;
private deploymentsStatus: DeploymentStatus[] = [];
private deploymentsCycled: number = 0;
private onDestroyListeners: Function[] = [];
constructor(@Inject('ApiService') private ApiService) {
constructor(@Inject('ApiService') private ApiService, @Inject('AngularPollChannel') private AngularPollChannel: AngularPollChannel) {
this.state = 'loadingDeployments';
ApiService.scGetNumDeployments().then(resp => {
@ -42,6 +50,14 @@ export class KubeDeployModalComponent {
})
}
// Call all listeners of the onDestroy
ngOnDestroy(): any {
this.onDestroyListeners.forEach(fn => {
fn()
});
}
deployConfiguration(): void {
this.ApiService.scDeployConfiguration().then(() => {
this.state = 'deployingConfiguration';
@ -62,34 +78,45 @@ export class KubeDeployModalComponent {
watchDeployments(): void {
this.deploymentsStatus.forEach(deployment => {
// Query each deployment every 500ms, and stop polling once it's either available or failed
const id: number = window.setInterval(() => {
const params = {
'deployment': deployment.name
};
this.ApiService.scGetDeploymentRolloutStatus(null, params).then((deploymentRollout: DeploymentRollout) => {
if (deploymentRollout.status === 'available') {
window.clearInterval(id);
this.deploymentsCycled++;
if (this.deploymentsCycled === this.deploymentsStatus.length) {
this.state = 'deployed';
}
} else if (deploymentRollout.status === 'progressing') {
deployment.message = deploymentRollout.message;
} else { // deployment rollout failed
window.clearInterval(id);
deployment.message = deploymentRollout.message;
}
}).catch(err => {
window.clearInterval(id);
this.state = 'error';
this.errorMessage = `Could not cycle the deployments with the new configuration. Error: ${err.toString()}`;
});
}, 500);
this.AngularPollChannel.create( {
// Have to mock the scope object for the poll channel since we're calling into angular1 code
// We register the onDestroy function to be called later when this object is destroyed
'$on': (_, onDestruction) => { this.onDestroyListeners.push(onDestruction) }
}, this.getDeploymentStatus(deployment), 5000 /* 5 seconds */)
.start();
});
}
// Query each deployment every 5s, and stop polling once it's either available or failed
getDeploymentStatus(deployment: DeploymentStatus): (boolean) => void {
return (continue_callback: (shouldContinue: boolean) => void) => {
const params = {
'deployment': deployment.name
};
this.ApiService.scGetDeploymentRolloutStatus(null, params).then((deploymentRollout: DeploymentRollout) => {
if (deploymentRollout.status === 'available') {
continue_callback(false);
this.deploymentsCycled++;
if (this.deploymentsCycled === this.deploymentsStatus.length) {
this.state = 'deployed';
}
} else if (deploymentRollout.status === 'progressing') {
continue_callback(true);
deployment.message = deploymentRollout.message;
} else { // deployment rollout failed
this.state = 'error';
continue_callback(false);
deployment.message = deploymentRollout.message;
this.errorMessage = `Could not cycle deployments: ${deploymentRollout.message}`;
this.offerRollback = true;
}
}).catch(err => {
continue_callback(false);
this.state = 'error';
this.errorMessage = `Could not cycle the deployments with the new configuration. Error: ${err.toString()}`;
});
}
}
}