2020-07-05 23:21:03 +00:00
import angular from 'angular' ;
2021-02-26 15:50:33 +00:00
import _ from 'lodash-es' ;
2020-07-05 23:21:03 +00:00
import filesizeParser from 'filesize-parser' ;
2021-07-14 09:15:21 +00:00
import { KubernetesResourceQuotaDefaults } from 'Kubernetes/models/resource-quota/models' ;
2020-07-05 23:21:03 +00:00
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper' ;
2021-07-28 02:26:03 +00:00
import { KubernetesResourceReservation } from 'Kubernetes/models/resource-reservation/models' ;
2020-07-05 23:21:03 +00:00
import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper' ;
2022-09-26 19:43:24 +00:00
import { KubernetesResourcePoolFormValues , KubernetesResourcePoolIngressClassHostFormValue } from 'Kubernetes/models/resource-pool/formValues' ;
2020-08-20 00:51:14 +00:00
import { KubernetesIngressConverter } from 'Kubernetes/ingress/converter' ;
2021-02-26 15:50:33 +00:00
import { KubernetesFormValidationReferences } from 'Kubernetes/models/application/formValues' ;
2020-08-20 09:24:12 +00:00
import { KubernetesIngressClassTypes } from 'Kubernetes/ingress/constants' ;
2021-02-26 15:50:33 +00:00
import KubernetesResourceQuotaConverter from 'Kubernetes/converters/resourceQuota' ;
2021-08-26 14:00:59 +00:00
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper' ;
2022-11-13 08:10:18 +00:00
import { FeatureId } from '@/react/portainer/feature-flags/enums' ;
2022-09-26 19:43:24 +00:00
import { updateIngressControllerClassMap , getIngressControllerClassMap } from '@/react/kubernetes/cluster/ingressClass/utils' ;
2023-02-14 08:19:41 +00:00
import { confirmUpdate } from '@@/modals/confirm' ;
2020-07-05 23:21:03 +00:00
class KubernetesResourcePoolController {
2020-08-20 00:51:14 +00:00
/* #region CONSTRUCTOR */
2020-07-05 23:21:03 +00:00
/* @ngInject */
constructor (
$async ,
$state ,
2021-12-14 19:14:53 +00:00
$scope ,
2020-07-05 23:21:03 +00:00
Authentication ,
Notifications ,
LocalStorage ,
2021-07-14 09:15:21 +00:00
EndpointService ,
2020-07-05 23:21:03 +00:00
KubernetesNodeService ,
2021-07-28 02:26:03 +00:00
KubernetesMetricsService ,
2020-07-05 23:21:03 +00:00
KubernetesResourceQuotaService ,
KubernetesResourcePoolService ,
KubernetesEventService ,
KubernetesPodService ,
2020-08-07 00:03:00 +00:00
KubernetesApplicationService ,
2021-02-26 15:50:33 +00:00
KubernetesIngressService ,
KubernetesVolumeService
2020-07-05 23:21:03 +00:00
) {
2021-07-14 09:15:21 +00:00
Object . assign ( this , {
$async ,
$state ,
2021-12-14 19:14:53 +00:00
$scope ,
2021-07-14 09:15:21 +00:00
Authentication ,
Notifications ,
LocalStorage ,
EndpointService ,
KubernetesNodeService ,
2021-07-28 02:26:03 +00:00
KubernetesMetricsService ,
2021-07-14 09:15:21 +00:00
KubernetesResourceQuotaService ,
KubernetesResourcePoolService ,
KubernetesEventService ,
KubernetesPodService ,
KubernetesApplicationService ,
KubernetesIngressService ,
KubernetesVolumeService ,
} ) ;
2020-07-05 23:21:03 +00:00
2020-08-20 09:24:12 +00:00
this . IngressClassTypes = KubernetesIngressClassTypes ;
2021-02-26 15:50:33 +00:00
this . ResourceQuotaDefaults = KubernetesResourceQuotaDefaults ;
2020-08-20 09:24:12 +00:00
2021-12-14 19:14:53 +00:00
this . LBQuotaFeatureId = FeatureId . K8S _RESOURCE _POOL _LB _QUOTA ;
this . StorageQuotaFeatureId = FeatureId . K8S _RESOURCE _POOL _STORAGE _QUOTA ;
2021-10-06 06:24:26 +00:00
2020-07-05 23:21:03 +00:00
this . updateResourcePoolAsync = this . updateResourcePoolAsync . bind ( this ) ;
this . getEvents = this . getEvents . bind ( this ) ;
2021-12-14 19:14:53 +00:00
this . onToggleLoadBalancersQuota = this . onToggleLoadBalancersQuota . bind ( this ) ;
this . onToggleStorageQuota = this . onToggleStorageQuota . bind ( this ) ;
2022-09-26 19:43:24 +00:00
this . onChangeIngressControllerAvailability = this . onChangeIngressControllerAvailability . bind ( this ) ;
2022-09-21 07:10:58 +00:00
this . onRegistriesChange = this . onRegistriesChange . bind ( this ) ;
2022-11-04 01:12:53 +00:00
this . handleMemoryLimitChange = this . handleMemoryLimitChange . bind ( this ) ;
this . handleCpuLimitChange = this . handleCpuLimitChange . bind ( this ) ;
2020-07-05 23:21:03 +00:00
}
2020-08-20 00:51:14 +00:00
/* #endregion */
2022-09-21 07:10:58 +00:00
onRegistriesChange ( registries ) {
return this . $scope . $evalAsync ( ( ) => {
this . formValues . Registries = registries ;
} ) ;
}
2021-12-14 19:14:53 +00:00
onToggleLoadBalancersQuota ( checked ) {
return this . $scope . $evalAsync ( ( ) => {
this . formValues . UseLoadBalancersQuota = checked ;
} ) ;
}
onToggleStorageQuota ( storageClassName , enabled ) {
this . $scope . $evalAsync ( ( ) => {
this . formValues . StorageClasses = this . formValues . StorageClasses . map ( ( sClass ) => ( sClass . Name !== storageClassName ? sClass : { ... sClass , Selected : enabled } ) ) ;
} ) ;
}
2022-09-26 19:43:24 +00:00
onChangeIngressControllerAvailability ( controllerClassMap ) {
this . ingressControllers = controllerClassMap ;
2020-08-20 00:51:14 +00:00
}
2021-04-27 17:51:13 +00:00
2020-07-05 23:21:03 +00:00
selectTab ( index ) {
this . LocalStorage . storeActiveTab ( 'resourcePool' , index ) ;
}
2020-08-20 00:51:14 +00:00
isUpdateButtonDisabled ( ) {
2021-02-26 15:50:33 +00:00
return this . state . actionInProgress || ( this . formValues . HasQuota && ! this . isQuotaValid ( ) ) || this . state . duplicates . ingressHosts . hasRefs ;
2020-08-20 00:51:14 +00:00
}
2020-07-05 23:21:03 +00:00
isQuotaValid ( ) {
if (
this . state . sliderMaxCpu < this . formValues . CpuLimit ||
this . state . sliderMaxMemory < this . formValues . MemoryLimit ||
( this . formValues . CpuLimit === 0 && this . formValues . MemoryLimit === 0 )
) {
return false ;
}
return true ;
}
checkDefaults ( ) {
2021-02-26 15:50:33 +00:00
if ( this . formValues . CpuLimit < KubernetesResourceQuotaDefaults . CpuLimit ) {
this . formValues . CpuLimit = KubernetesResourceQuotaDefaults . CpuLimit ;
2020-07-05 23:21:03 +00:00
}
2021-02-26 15:50:33 +00:00
if ( this . formValues . MemoryLimit < KubernetesResourceReservationHelper . megaBytesValue ( KubernetesResourceQuotaDefaults . MemoryLimit ) ) {
this . formValues . MemoryLimit = KubernetesResourceReservationHelper . megaBytesValue ( KubernetesResourceQuotaDefaults . MemoryLimit ) ;
2020-07-05 23:21:03 +00:00
}
}
2022-11-04 01:12:53 +00:00
handleMemoryLimitChange ( memoryLimit ) {
return this . $async ( async ( ) => {
this . formValues . MemoryLimit = memoryLimit ;
} ) ;
}
handleCpuLimitChange ( cpuLimit ) {
return this . $async ( async ( ) => {
this . formValues . CpuLimit = cpuLimit ;
} ) ;
}
2020-07-05 23:21:03 +00:00
showEditor ( ) {
this . state . showEditorTab = true ;
this . selectTab ( 2 ) ;
}
2020-08-12 23:30:23 +00:00
hasResourceQuotaBeenReduced ( ) {
if ( this . formValues . HasQuota && this . oldQuota ) {
2020-08-07 22:46:11 +00:00
const cpuLimit = this . formValues . CpuLimit ;
const memoryLimit = KubernetesResourceReservationHelper . bytesValue ( this . formValues . MemoryLimit ) ;
if ( cpuLimit < this . oldQuota . CpuLimit || memoryLimit < this . oldQuota . MemoryLimit ) {
return true ;
}
}
return false ;
}
2021-04-27 08:12:34 +00:00
/* #region UPDATE NAMESPACE */
2021-08-26 14:00:59 +00:00
async updateResourcePoolAsync ( oldFormValues , newFormValues ) {
2020-07-05 23:21:03 +00:00
this . state . actionInProgress = true ;
try {
this . checkDefaults ( ) ;
2021-08-26 14:00:59 +00:00
await this . KubernetesResourcePoolService . patch ( oldFormValues , newFormValues ) ;
2022-10-03 23:13:56 +00:00
await updateIngressControllerClassMap ( this . endpoint . Id , this . ingressControllers || [ ] , this . formValues . Name ) ;
2021-04-27 08:12:34 +00:00
this . Notifications . success ( 'Namespace successfully updated' , this . pool . Namespace . Name ) ;
2021-09-24 08:21:50 +00:00
this . $state . reload ( this . $state . current ) ;
2020-07-05 23:21:03 +00:00
} catch ( err ) {
2021-04-27 08:12:34 +00:00
this . Notifications . error ( 'Failure' , err , 'Unable to create namespace' ) ;
2020-07-05 23:21:03 +00:00
} finally {
this . state . actionInProgress = false ;
}
}
updateResourcePool ( ) {
2021-09-06 05:25:02 +00:00
const ingressesToDelete = _ . filter ( this . formValues . IngressClasses , { WasSelected : true , Selected : false } ) ;
const registriesToDelete = _ . filter ( this . registries , { WasChecked : true , Checked : false } ) ;
2020-08-12 23:30:23 +00:00
const warnings = {
quota : this . hasResourceQuotaBeenReduced ( ) ,
2021-09-06 05:25:02 +00:00
ingress : ingressesToDelete . length !== 0 ,
registries : registriesToDelete . length !== 0 ,
2020-08-12 23:30:23 +00:00
} ;
2021-09-06 05:25:02 +00:00
if ( warnings . quota || warnings . ingress || warnings . registries ) {
2020-08-12 23:30:23 +00:00
const messages = {
quota :
2021-04-27 08:12:34 +00:00
'Reducing the quota assigned to an "in-use" namespace may have unintended consequences, including preventing running applications from functioning correctly and potentially even blocking them from running at all.' ,
2020-08-12 23:30:23 +00:00
ingress : 'Deactivating ingresses may cause applications to be unaccessible. All ingress configurations from affected applications will be removed.' ,
2021-09-06 05:25:02 +00:00
registries :
'Some registries you removed might be used by one or more applications inside this environment. Removing the registries access could lead to a service interruption for these applications.' ,
2020-08-12 23:30:23 +00:00
} ;
2021-09-06 05:25:02 +00:00
const displayedMessage = ` ${ warnings . quota ? messages . quota + '<br/><br/>' : '' }
$ { warnings . ingress ? messages . ingress + '<br/><br/>' : '' }
$ { warnings . registries ? messages . registries + '<br/><br/>' : '' }
Do you wish to continue ? ` ;
2023-02-14 08:19:41 +00:00
confirmUpdate ( displayedMessage , ( confirmed ) => {
2020-08-12 23:30:23 +00:00
if ( confirmed ) {
2021-08-26 14:00:59 +00:00
return this . $async ( this . updateResourcePoolAsync , this . savedFormValues , this . formValues ) ;
2020-08-07 22:46:11 +00:00
}
2020-08-12 23:30:23 +00:00
} ) ;
2020-08-07 22:46:11 +00:00
} else {
2021-08-26 14:00:59 +00:00
return this . $async ( this . updateResourcePoolAsync , this . savedFormValues , this . formValues ) ;
2020-08-07 22:46:11 +00:00
}
2020-07-05 23:21:03 +00:00
}
2021-08-26 14:00:59 +00:00
async confirmMarkUnmarkAsSystem ( ) {
const message = this . isSystem
? 'Unmarking this namespace as system will allow non administrator users to manage it and the resources in contains depending on the access control settings. Are you sure?'
: 'Marking this namespace as a system namespace will prevent non administrator users from managing it and the resources it contains. Are you sure?' ;
return new Promise ( ( resolve ) => {
2023-02-14 08:19:41 +00:00
confirmUpdate ( message , resolve ) ;
2021-08-26 14:00:59 +00:00
} ) ;
}
markUnmarkAsSystem ( ) {
return this . $async ( async ( ) => {
try {
const namespaceName = this . $state . params . id ;
this . state . actionInProgress = true ;
const confirmed = await this . confirmMarkUnmarkAsSystem ( ) ;
if ( ! confirmed ) {
return ;
}
await this . KubernetesResourcePoolService . toggleSystem ( this . endpoint . Id , namespaceName , ! this . isSystem ) ;
this . Notifications . success ( 'Namespace successfully updated' , namespaceName ) ;
2021-09-24 08:21:50 +00:00
this . $state . reload ( this . $state . current ) ;
2021-08-26 14:00:59 +00:00
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to create namespace' ) ;
} finally {
this . state . actionInProgress = false ;
}
} ) ;
}
2021-02-26 15:50:33 +00:00
/* #endregion */
2020-07-05 23:21:03 +00:00
hasEventWarnings ( ) {
return this . state . eventWarningCount ;
}
2020-08-20 00:51:14 +00:00
/* #region GET EVENTS */
2020-07-05 23:21:03 +00:00
getEvents ( ) {
2021-02-26 15:50:33 +00:00
return this . $async ( async ( ) => {
try {
this . state . eventsLoading = true ;
this . events = await this . KubernetesEventService . get ( this . pool . Namespace . Name ) ;
this . state . eventWarningCount = KubernetesEventHelper . warningCount ( this . events ) ;
} catch ( err ) {
2021-04-27 08:12:34 +00:00
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve namespace related events' ) ;
2021-02-26 15:50:33 +00:00
} finally {
this . state . eventsLoading = false ;
}
} ) ;
2020-07-05 23:21:03 +00:00
}
2020-08-20 00:51:14 +00:00
/* #endregion */
2020-07-05 23:21:03 +00:00
2020-08-20 00:51:14 +00:00
/* #region GET APPLICATIONS */
2020-07-05 23:21:03 +00:00
getApplications ( ) {
2021-02-26 15:50:33 +00:00
return this . $async ( async ( ) => {
try {
this . state . applicationsLoading = true ;
this . applications = await this . KubernetesApplicationService . get ( this . pool . Namespace . Name ) ;
this . applications = _ . map ( this . applications , ( app ) => {
const resourceReservation = KubernetesResourceReservationHelper . computeResourceReservation ( app . Pods ) ;
app . CPU = resourceReservation . CPU ;
app . Memory = resourceReservation . Memory ;
return app ;
} ) ;
2021-07-28 02:26:03 +00:00
2021-08-13 04:46:18 +00:00
if ( this . state . useServerMetrics ) {
await this . getResourceUsage ( this . pool . Namespace . Name ) ;
}
2021-02-26 15:50:33 +00:00
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve applications.' ) ;
} finally {
this . state . applicationsLoading = false ;
}
} ) ;
2020-07-05 23:21:03 +00:00
}
2020-08-20 00:51:14 +00:00
/* #endregion */
2020-07-05 23:21:03 +00:00
2020-08-20 00:51:14 +00:00
/* #region GET INGRESSES */
2020-08-12 23:30:23 +00:00
getIngresses ( ) {
2021-02-26 15:50:33 +00:00
return this . $async ( async ( ) => {
this . state . ingressesLoading = true ;
try {
const namespace = this . pool . Namespace . Name ;
2021-08-31 21:43:11 +00:00
this . allIngresses = await this . KubernetesIngressService . get ( this . state . hasWriteAuthorization ? '' : namespace ) ;
2021-02-26 15:50:33 +00:00
this . ingresses = _ . filter ( this . allIngresses , { Namespace : namespace } ) ;
_ . forEach ( this . ingresses , ( ing ) => {
ing . Namespace = namespace ;
_ . forEach ( ing . Paths , ( path ) => {
const application = _ . find ( this . applications , { ServiceName : path . ServiceName } ) ;
path . ApplicationName = application && application . Name ? application . Name : '-' ;
} ) ;
} ) ;
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve ingresses.' ) ;
} finally {
this . state . ingressesLoading = false ;
}
} ) ;
2020-08-12 23:30:23 +00:00
}
2020-08-20 00:51:14 +00:00
/* #endregion */
2020-08-12 23:30:23 +00:00
2021-07-14 09:15:21 +00:00
/* #region GET REGISTRIES */
getRegistries ( ) {
return this . $async ( async ( ) => {
try {
const namespace = this . $state . params . id ;
if ( this . isAdmin ) {
this . registries = await this . EndpointService . registries ( this . endpoint . Id ) ;
this . registries . forEach ( ( reg ) => {
if ( reg . RegistryAccesses && reg . RegistryAccesses [ this . endpoint . Id ] && reg . RegistryAccesses [ this . endpoint . Id ] . Namespaces . includes ( namespace ) ) {
reg . Checked = true ;
2021-09-06 05:25:02 +00:00
reg . WasChecked = true ;
2021-07-14 09:15:21 +00:00
this . formValues . Registries . push ( reg ) ;
}
} ) ;
2021-09-03 13:47:37 +00:00
this . selectedRegistries = this . formValues . Registries . map ( ( r ) => r . Name ) . join ( ', ' ) ;
2021-07-14 09:15:21 +00:00
return ;
}
const registries = await this . EndpointService . registries ( this . endpoint . Id , namespace ) ;
this . selectedRegistries = registries . map ( ( r ) => r . Name ) . join ( ', ' ) ;
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve registries' ) ;
}
} ) ;
}
/* #endregion */
2021-07-28 02:26:03 +00:00
async getResourceUsage ( namespace ) {
try {
const namespaceMetrics = await this . KubernetesMetricsService . getPods ( namespace ) ;
// extract resource usage of all containers within each pod of the namespace
const containerResourceUsageList = namespaceMetrics . items . flatMap ( ( i ) => i . containers . map ( ( c ) => c . usage ) ) ;
const namespaceResourceUsage = containerResourceUsageList . reduce ( ( total , u ) => {
total . CPU += KubernetesResourceReservationHelper . parseCPU ( u . cpu ) ;
total . Memory += KubernetesResourceReservationHelper . megaBytesValue ( u . memory ) ;
return total ;
} , new KubernetesResourceReservation ( ) ) ;
this . state . resourceUsage = namespaceResourceUsage ;
} catch ( err ) {
2021-10-11 21:37:07 +00:00
this . Notifications . error ( 'Failure' , err , 'Unable to retrieve namespace resource usage' ) ;
2021-07-28 02:26:03 +00:00
}
}
2021-07-14 09:15:21 +00:00
/* #region ON INIT */
$onInit ( ) {
return this . $async ( async ( ) => {
try {
this . isAdmin = this . Authentication . isAdmin ( ) ;
this . state = {
actionInProgress : false ,
sliderMaxMemory : 0 ,
sliderMaxCpu : 0 ,
cpuUsage : 0 ,
memoryUsage : 0 ,
2021-07-28 02:26:03 +00:00
resourceReservation : { CPU : 0 , Memory : 0 } ,
2021-07-14 09:15:21 +00:00
activeTab : 0 ,
currentName : this . $state . $current . name ,
showEditorTab : false ,
eventsLoading : true ,
applicationsLoading : true ,
ingressesLoading : true ,
viewReady : false ,
eventWarningCount : 0 ,
2022-09-26 19:43:24 +00:00
canUseIngress : false ,
2021-07-28 02:26:03 +00:00
useServerMetrics : this . endpoint . Kubernetes . Configuration . UseServerMetrics ,
2021-07-14 09:15:21 +00:00
duplicates : {
ingressHosts : new KubernetesFormValidationReferences ( ) ,
} ,
2022-09-26 19:43:24 +00:00
ingressAvailabilityPerNamespace : this . endpoint . Kubernetes . Configuration . IngressAvailabilityPerNamespace ,
2021-07-14 09:15:21 +00:00
} ;
this . state . activeTab = this . LocalStorage . getActiveTab ( 'resourcePool' ) ;
const name = this . $state . params . id ;
2023-02-10 05:28:53 +00:00
const [ nodes , pools ] = await Promise . all ( [ this . KubernetesNodeService . get ( ) , this . KubernetesResourcePoolService . get ( '' , { getQuota : true } ) ] ) ;
2021-07-14 09:15:21 +00:00
2022-09-26 19:43:24 +00:00
this . ingressControllers = [ ] ;
if ( this . state . ingressAvailabilityPerNamespace ) {
this . ingressControllers = await getIngressControllerClassMap ( { environmentId : this . endpoint . Id , namespace : name } ) ;
}
2021-07-14 09:15:21 +00:00
this . pool = _ . find ( pools , { Namespace : { Name : name } } ) ;
this . formValues = new KubernetesResourcePoolFormValues ( KubernetesResourceQuotaDefaults ) ;
this . formValues . Name = this . pool . Namespace . Name ;
this . formValues . EndpointId = this . endpoint . Id ;
2021-08-26 14:00:59 +00:00
this . formValues . IsSystem = this . pool . Namespace . IsSystem ;
2021-07-14 09:15:21 +00:00
_ . forEach ( nodes , ( item ) => {
this . state . sliderMaxMemory += filesizeParser ( item . Memory ) ;
this . state . sliderMaxCpu += item . CPU ;
} ) ;
this . state . sliderMaxMemory = KubernetesResourceReservationHelper . megaBytesValue ( this . state . sliderMaxMemory ) ;
2020-07-05 23:21:03 +00:00
2021-07-14 09:15:21 +00:00
const quota = this . pool . Quota ;
if ( quota ) {
this . oldQuota = angular . copy ( quota ) ;
this . formValues = KubernetesResourceQuotaConverter . quotaToResourcePoolFormValues ( quota ) ;
this . formValues . EndpointId = this . endpoint . Id ;
2020-07-05 23:21:03 +00:00
2021-07-28 02:26:03 +00:00
this . state . resourceReservation . CPU = quota . CpuLimitUsed ;
this . state . resourceReservation . Memory = KubernetesResourceReservationHelper . megaBytesValue ( quota . MemoryLimitUsed ) ;
2021-07-14 09:15:21 +00:00
}
2021-08-26 14:00:59 +00:00
this . isSystem = KubernetesNamespaceHelper . isSystemNamespace ( this . pool . Namespace . Name ) ;
this . isDefaultNamespace = KubernetesNamespaceHelper . isDefaultNamespace ( this . pool . Namespace . Name ) ;
this . isEditable = ! this . isSystem && ! this . isDefaultNamespace ;
2020-07-05 23:21:03 +00:00
2021-07-14 09:15:21 +00:00
await this . getEvents ( ) ;
await this . getApplications ( ) ;
if ( this . state . canUseIngress ) {
await this . getIngresses ( ) ;
2021-07-28 02:26:03 +00:00
const ingressClasses = this . endpoint . Kubernetes . Configuration . IngressClasses ;
2021-07-14 09:15:21 +00:00
this . formValues . IngressClasses = KubernetesIngressConverter . ingressClassesToFormValues ( ingressClasses , this . ingresses ) ;
_ . forEach ( this . formValues . IngressClasses , ( ic ) => {
if ( ic . Hosts . length === 0 ) {
ic . Hosts . push ( new KubernetesResourcePoolIngressClassHostFormValue ( ) ) ;
}
} ) ;
}
2020-07-05 23:21:03 +00:00
2021-07-14 09:15:21 +00:00
await this . getRegistries ( ) ;
2020-08-07 00:03:00 +00:00
2021-07-14 09:15:21 +00:00
this . savedFormValues = angular . copy ( this . formValues ) ;
} catch ( err ) {
this . Notifications . error ( 'Failure' , err , 'Unable to load view data' ) ;
} finally {
this . state . viewReady = true ;
2020-08-12 23:30:23 +00:00
}
2021-07-14 09:15:21 +00:00
} ) ;
2020-07-05 23:21:03 +00:00
}
2020-08-20 00:51:14 +00:00
/* #endregion */
2020-07-05 23:21:03 +00:00
$onDestroy ( ) {
if ( this . state . currentName !== this . $state . $current . name ) {
this . LocalStorage . storeActiveTab ( 'resourcePool' , 0 ) ;
}
}
}
export default KubernetesResourcePoolController ;
angular . module ( 'portainer.kubernetes' ) . controller ( 'KubernetesResourcePoolController' , KubernetesResourcePoolController ) ;