@ -5,7 +5,7 @@ import { KubernetesResourceReservation } from 'Kubernetes/models/resource-reserv
import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper' ;
import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper' ;
import KubernetesNodeConverter from 'Kubernetes/node/converter' ;
import KubernetesNodeConverter from 'Kubernetes/node/converter' ;
import { KubernetesNodeLabelFormValues , KubernetesNodeTaintFormValues } from 'Kubernetes/node/formValues' ;
import { KubernetesNodeLabelFormValues , KubernetesNodeTaintFormValues } from 'Kubernetes/node/formValues' ;
import { KubernetesNodeTaintEffects } from 'Kubernetes/node/models' ;
import { KubernetesNodeTaintEffects , KubernetesNodeAvailabilities } from 'Kubernetes/node/models' ;
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper' ;
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper' ;
import { KubernetesNodeHelper } from 'Kubernetes/node/helper' ;
import { KubernetesNodeHelper } from 'Kubernetes/node/helper' ;
@ -35,12 +35,13 @@ class KubernetesNodeController {
this . KubernetesEndpointService = KubernetesEndpointService ;
this . KubernetesEndpointService = KubernetesEndpointService ;
this . onInit = this . onInit . bind ( this ) ;
this . onInit = this . onInit . bind ( this ) ;
this . getNode Async = this . getNode Async. bind ( this ) ;
this . getNode s Async = this . getNode s Async. bind ( this ) ;
this . getEvents = this . getEvents . bind ( this ) ;
this . getEvents = this . getEvents . bind ( this ) ;
this . getEventsAsync = this . getEventsAsync . bind ( this ) ;
this . getEventsAsync = this . getEventsAsync . bind ( this ) ;
this . getApplicationsAsync = this . getApplicationsAsync . bind ( this ) ;
this . getApplicationsAsync = this . getApplicationsAsync . bind ( this ) ;
this . getEndpointsAsync = this . getEndpointsAsync . bind ( this ) ;
this . getEndpointsAsync = this . getEndpointsAsync . bind ( this ) ;
this . updateNodeAsync = this . updateNodeAsync . bind ( this ) ;
this . updateNodeAsync = this . updateNodeAsync . bind ( this ) ;
this . drainNodeAsync = this . drainNodeAsync . bind ( this ) ;
}
}
selectTab ( index ) {
selectTab ( index ) {
@ -152,6 +153,47 @@ class KubernetesNodeController {
/* #endregion */
/* #endregion */
/* #region cordon */
computeCordonWarning ( ) {
return this . formValues . Availability === this . availabilities . PAUSE ;
}
/* #endregion */
/* #region drain */
computeDrainWarning ( ) {
return this . formValues . Availability === this . availabilities . DRAIN ;
}
async drainNodeAsync ( ) {
const pods = _ . flatten ( _ . map ( this . applications , ( app ) => app . Pods ) ) ;
let actionCount = pods . length ;
for ( const pod of pods ) {
try {
await this . KubernetesPodService . eviction ( pod ) ;
this . Notifications . success ( 'Pod successfully evicted' , pod . Name ) ;
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to evict pod' ) ;
this . formValues . Availability = this . availabilities . PAUSE ;
await this . KubernetesNodeService . patch ( this . node , this . formValues ) ;
} finally {
-- actionCount ;
if ( actionCount === 0 ) {
this . formValues . Availability = this . availabilities . PAUSE ;
await this . KubernetesNodeService . patch ( this . node , this . formValues ) ;
}
}
}
}
drainNode ( ) {
return this . $async ( this . drainNodeAsync ) ;
}
/* #endregion */
/* #region actions */
/* #region actions */
isNoChangesMade ( ) {
isNoChangesMade ( ) {
@ -160,8 +202,12 @@ class KubernetesNodeController {
return ! payload . length ;
return ! payload . length ;
}
}
isDrainError ( ) {
return ( this . state . isDrainOperation || this . state . isContainPortainer ) && this . formValues . Availability === this . availabilities . DRAIN ;
}
isFormValid ( ) {
isFormValid ( ) {
return ! this . state . hasDuplicateTaintKeys && ! this . state . hasDuplicateLabelKeys && ! this . isNoChangesMade ( ) ;
return ! this . state . hasDuplicateTaintKeys && ! this . state . hasDuplicateLabelKeys && ! this . isNoChangesMade ( ) && ! this . isDrainError ( ) ;
}
}
resetFormValues ( ) {
resetFormValues ( ) {
@ -196,7 +242,10 @@ class KubernetesNodeController {
async updateNodeAsync ( ) {
async updateNodeAsync ( ) {
try {
try {
await this . KubernetesNodeService . patch ( this . node , this . formValues ) ;
this . node = await this . KubernetesNodeService . patch ( this . node , this . formValues ) ;
if ( this . formValues . Availability === 'Drain' ) {
await this . drainNode ( ) ;
}
this . Notifications . success ( 'Node updated successfully' ) ;
this . Notifications . success ( 'Node updated successfully' ) ;
this . $state . reload ( ) ;
this . $state . reload ( ) ;
} catch ( err ) {
} catch ( err ) {
@ -207,6 +256,8 @@ class KubernetesNodeController {
updateNode ( ) {
updateNode ( ) {
const taintsWarning = this . computeTaintsWarning ( ) ;
const taintsWarning = this . computeTaintsWarning ( ) ;
const labelsWarning = this . computeLabelsWarning ( ) ;
const labelsWarning = this . computeLabelsWarning ( ) ;
const cordonWarning = this . computeCordonWarning ( ) ;
const drainWarning = this . computeDrainWarning ( ) ;
if ( taintsWarning && ! labelsWarning ) {
if ( taintsWarning && ! labelsWarning ) {
this . ModalService . confirmUpdate (
this . ModalService . confirmUpdate (
@ -235,16 +286,36 @@ class KubernetesNodeController {
}
}
}
}
) ;
) ;
} else if ( cordonWarning ) {
this . ModalService . confirmUpdate (
'Marking this node as unschedulable will effectively cordon the node and prevent any new workload from being scheduled on that node. Are you sure?' ,
( confirmed ) => {
if ( confirmed ) {
return this . $async ( this . updateNodeAsync ) ;
}
}
) ;
} else if ( drainWarning ) {
this . ModalService . confirmUpdate (
'Draining this node will cause all workloads to be evicted from that node. This might lead to some service interruption. Are you sure?' ,
( confirmed ) => {
if ( confirmed ) {
return this . $async ( this . updateNodeAsync ) ;
}
}
) ;
} else {
} else {
return this . $async ( this . updateNodeAsync ) ;
return this . $async ( this . updateNodeAsync ) ;
}
}
}
}
async getNodeAsync ( ) {
async getNode s Async( ) {
try {
try {
this . state . dataLoading = true ;
this . state . dataLoading = true ;
const nodeName = this . $transition$ . params ( ) . name ;
const nodeName = this . $transition$ . params ( ) . name ;
this . node = await this . KubernetesNodeService . get ( nodeName ) ;
this . nodes = await this . KubernetesNodeService . get ( ) ;
this . node = _ . find ( this . nodes , { Name : nodeName } ) ;
this . state . isDrainOperation = _ . find ( this . nodes , { Availability : this . availabilities . DRAIN } ) ;
} catch ( err ) {
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve node' ) ;
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve node' ) ;
} finally {
} finally {
@ -252,8 +323,8 @@ class KubernetesNodeController {
}
}
}
}
getNode ( ) {
getNode s ( ) {
return this . $async ( this . getNode Async) ;
return this . $async ( this . getNode s Async) ;
}
}
hasEventWarnings ( ) {
hasEventWarnings ( ) {
@ -303,6 +374,7 @@ class KubernetesNodeController {
} ) ;
} ) ;
this . resourceReservation . Memory = KubernetesResourceReservationHelper . megaBytesValue ( this . resourceReservation . Memory ) ;
this . resourceReservation . Memory = KubernetesResourceReservationHelper . megaBytesValue ( this . resourceReservation . Memory ) ;
this . memoryLimit = KubernetesResourceReservationHelper . megaBytesValue ( this . node . Memory ) ;
this . memoryLimit = KubernetesResourceReservationHelper . megaBytesValue ( this . node . Memory ) ;
this . state . isContainPortainer = _ . find ( this . applications , { ApplicationName : 'portainer' } ) ;
} catch ( err ) {
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve applications' ) ;
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve applications' ) ;
} finally {
} finally {
@ -328,11 +400,15 @@ class KubernetesNodeController {
hasDuplicateTaintKeys : false ,
hasDuplicateTaintKeys : false ,
duplicateLabelKeys : [ ] ,
duplicateLabelKeys : [ ] ,
hasDuplicateLabelKeys : false ,
hasDuplicateLabelKeys : false ,
isDrainOperation : false ,
isContainPortainer : false ,
} ;
} ;
this . availabilities = KubernetesNodeAvailabilities ;
this . state . activeTab = this . LocalStorage . getActiveTab ( 'node' ) ;
this . state . activeTab = this . LocalStorage . getActiveTab ( 'node' ) ;
await this . getNode ( ) ;
await this . getNode s ( ) ;
await this . getEvents ( ) ;
await this . getEvents ( ) ;
await this . getApplications ( ) ;
await this . getApplications ( ) ;
await this . getEndpoints ( ) ;
await this . getEndpoints ( ) ;