Ver Fonte

cluster and project deletion across cloud providers. Fixes #249

sunguroku há 5 anos atrás
pai
commit
baad23f31d

+ 48 - 14
dashboard/src/main/home/Home.tsx

@@ -70,13 +70,14 @@ export default class Home extends Component<PropsType, StateType> {
       }
       }
 
 
       if (res.data.length > 0 && (!currentCluster && !includesCompletedInfraSet(res.data))) {
       if (res.data.length > 0 && (!currentCluster && !includesCompletedInfraSet(res.data))) {
-        // force refresh if currentView is already set to provisioner.
+        // force refresh if currentView is identical set to provisioner. Tentative solution before refactoring.
         this.setState({ currentView: 'dashboard'}, () => {
         this.setState({ currentView: 'dashboard'}, () => {
           this.setState({ currentView: 'provisioner', sidebarReady: true, });
           this.setState({ currentView: 'provisioner', sidebarReady: true, });
         });
         });
       } else {
       } else {
-        // console.log('getting here', currentCluster)
-        this.setState({ currentView: 'dashboard', sidebarReady: true });
+        this.setState({ currentView: 'provisioner'}, () => {
+          this.setState({ currentView: 'dashboard', sidebarReady: true });
+        })
       }
       }
     });
     });
   }
   }
@@ -357,7 +358,7 @@ export default class Home extends Component<PropsType, StateType> {
     let { setCurrentModal, currentProject } = this.context;
     let { setCurrentModal, currentProject } = this.context;
     api.deleteProject('<token>', {}, { id: currentProject.id }, (err: any, res: any) => {
     api.deleteProject('<token>', {}, { id: currentProject.id }, (err: any, res: any) => {
       if (err) {
       if (err) {
-        // console.log(err)
+        console.log(err)
       } else {
       } else {
         this.projectOverlayCall();
         this.projectOverlayCall();
       }
       }
@@ -365,15 +366,21 @@ export default class Home extends Component<PropsType, StateType> {
 
 
     // Loop through and delete infra of all clusters we've provisioned
     // Loop through and delete infra of all clusters we've provisioned
     api.getClusters('<token>', {}, { id: currentProject.id }, (err: any, res: any) => {
     api.getClusters('<token>', {}, { id: currentProject.id }, (err: any, res: any) => {
-      if (err) {
-        console.log(err);
-      } else {
-        res.data.forEach((cluster: ClusterType) => {
 
 
-          // Handle destroying infra we've provisioned
-          if (cluster.infra_id) {
-            console.log('destroying provisioned infra...', cluster.infra_id);
-            api.destroyCluster('<token>', { eks_name: cluster.name }, { 
+      if (err) { 
+        console.log(err); 
+        return; 
+      }
+      
+      for (var i = 0; i < res.data.length; i++) {
+        let cluster = res.data[i];
+        if (!cluster.infra_id) continue;
+
+        // Handle destroying infra we've provisioned
+        switch (cluster.service) {
+
+          case "eks":
+            api.destroyEKS('<token>', { eks_name: cluster.name }, { 
               project_id: currentProject.id,
               project_id: currentProject.id,
               infra_id: cluster.infra_id,
               infra_id: cluster.infra_id,
             }, (err: any, res: any) => {
             }, (err: any, res: any) => {
@@ -383,8 +390,34 @@ export default class Home extends Component<PropsType, StateType> {
                 console.log('destroyed provisioned infra:', cluster.infra_id);
                 console.log('destroyed provisioned infra:', cluster.infra_id);
               }
               }
             });
             });
-          }
-        });
+            break;
+
+          case 'gke':
+            api.destroyGKE('<token>', { gke_name: cluster.name }, { 
+              project_id: currentProject.id,
+              infra_id: cluster.infra_id,
+            }, (err: any, res: any) => {
+              if (err) {
+                console.log(err)
+              } else {
+                console.log('destroyed provisioned infra.');
+              }
+            });
+            break;
+
+          case 'doks':
+            api.destroyDOKS('<token>', { doks_name: cluster.name }, { 
+              project_id: currentProject.id,
+              infra_id: cluster.infra_id,
+            }, (err: any, res: any) => {
+              if (err) {
+                console.log(err)
+              } else {
+                console.log('destroyed provisioned infra.');
+              }
+            });
+            break;
+        }
       }
       }
     });
     });
     setCurrentModal(null, null)
     setCurrentModal(null, null)
@@ -393,6 +426,7 @@ export default class Home extends Component<PropsType, StateType> {
 
 
   render() {
   render() {
     let { currentModal, setCurrentModal, currentProject } = this.context;
     let { currentModal, setCurrentModal, currentProject } = this.context;
+
     return (
     return (
       <StyledHome>
       <StyledHome>
         {currentModal === 'ClusterInstructionsModal' &&
         {currentModal === 'ClusterInstructionsModal' &&

+ 60 - 12
dashboard/src/main/home/modals/UpdateClusterModal.tsx

@@ -35,15 +35,33 @@ export default class UpdateClusterModal extends Component<PropsType, StateType>
       project_id: currentProject.id,
       project_id: currentProject.id,
       cluster_id: currentCluster.id,
       cluster_id: currentCluster.id,
     }, (err: any, res: any) => {
     }, (err: any, res: any) => {
+
       if (err) {
       if (err) {
         this.setState({ status: 'error' });
         this.setState({ status: 'error' });
         console.log(err)
         console.log(err)
-      } else {
+        return;
+      }
+
+      if (!currentCluster?.infra_id) return;
+
+      // Handle destroying infra we've provisioned
+      switch (currentCluster.service) {
+        case 'eks':
+          api.destroyEKS('<token>', { eks_name: currentCluster.name }, { 
+            project_id: currentProject.id,
+            infra_id: currentCluster.infra_id,
+          }, (err: any, res: any) => {
+            if (err) {
+              this.setState({ status: 'error' });
+              console.log(err)
+            } else {
+              console.log('destroyed provisioned infra.');
+            }
+          });
+          break;
 
 
-        // Handle destroying infra we've provisioned
-        if (currentCluster.infra_id) {
-          console.log('destroying provisioned infra...');
-          api.destroyCluster('<token>', { eks_name: currentCluster.name }, { 
+        case 'gke':
+          api.destroyGKE('<token>', { gke_name: currentCluster.name }, { 
             project_id: currentProject.id,
             project_id: currentProject.id,
             infra_id: currentCluster.infra_id,
             infra_id: currentCluster.infra_id,
           }, (err: any, res: any) => {
           }, (err: any, res: any) => {
@@ -54,15 +72,46 @@ export default class UpdateClusterModal extends Component<PropsType, StateType>
               console.log('destroyed provisioned infra.');
               console.log('destroyed provisioned infra.');
             }
             }
           });
           });
-        }
+          break;
 
 
-        this.props.setRefreshClusters(true);
-        this.setState({ status: 'successful', showDeleteOverlay: false });
-        this.context.setCurrentModal(null, null);
+        case 'doks':
+          api.destroyDOKS('<token>', { doks_name : currentCluster.name }, { 
+            project_id: currentProject.id,
+            infra_id: currentCluster.infra_id,
+          }, (err: any, res: any) => {
+            if (err) {
+              this.setState({ status: 'error' });
+              console.log(err)
+            } else {
+              console.log('destroyed provisioned infra.');
+            }
+          });
+          break;
       }
       }
+        
+      this.props.setRefreshClusters(true);
+      this.setState({ status: 'successful', showDeleteOverlay: false });
+      this.context.setCurrentModal(null, null);
     });
     });
   }
   }
 
 
+  renderWarning = () => {
+    let { currentCluster } = this.context;
+    if (!currentCluster?.infra_id || !currentCluster.service) {
+      return(
+        <Warning highlight={true}>
+          ⚠️ Since this cluster was not provisioned by Porter, deleting the cluster will only detach this cluster from your project. To delete the cluster itself, you must do so manually.
+        </Warning>
+      )    
+    }
+
+    return(
+      <Warning highlight={true}>
+        ⚠️ Deletion may result in dangling resources. Please visit your cloud provider's console to ensure that all resources have been removed. Note that deleting the cluster does not delete your registries.
+      </Warning>
+    )    
+  }
+
   render() {
   render() {
     return (
     return (
       <StyledUpdateProjectModal>
       <StyledUpdateProjectModal>
@@ -91,9 +140,8 @@ export default class UpdateClusterModal extends Component<PropsType, StateType>
           />
           />
         </InputWrapper>
         </InputWrapper>
 
 
-        <Warning highlight={true}>
-          ⚠️ Deletion may result in dangling resources. Please visit the AWS console to ensure that all resources have been removed.
-        </Warning>
+        {this.renderWarning()}
+
         <Help 
         <Help 
           href='https://docs.getporter.dev/docs/getting-started-with-porter-on-aws#deleting-provisioned-resources'
           href='https://docs.getporter.dev/docs/getting-started-with-porter-on-aws#deleting-provisioned-resources'
           target='_blank'
           target='_blank'

+ 11 - 4
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -29,7 +29,7 @@ export default class ProjectSettings extends Component<PropsType, StateType> {
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
-    let { currentProject, user } = this.context;
+    let { currentProject } = this.context;
     this.setState({ projectName: currentProject.name });
     this.setState({ projectName: currentProject.name });
   }
   }
 
 
@@ -40,7 +40,13 @@ export default class ProjectSettings extends Component<PropsType, StateType> {
       return (
       return (
         <>
         <>
           <Heading isAtTop={true}>Delete Project</Heading>
           <Heading isAtTop={true}>Delete Project</Heading>
-          <Helper>Permanently delete this project. <Warning highlight={true}>This action cannot be undone.</Warning></Helper>
+          <Helper>
+            Permanently delete this project. This will destroy all clusters tied to this project that have been provisioned by Porter. Note that this will not delete the image registries provisioned by Porter. To delete the registries, please do so manually in your cloud console.
+          </Helper>
+
+          <Warning highlight={true}>This action cannot be undone.</Warning>
+
+
           <DeleteButton
           <DeleteButton
             onClick={() => {
             onClick={() => {
               this.context.setCurrentModal('UpdateProjectModal', {
               this.context.setCurrentModal('UpdateProjectModal', {
@@ -76,9 +82,10 @@ export default class ProjectSettings extends Component<PropsType, StateType> {
 
 
 ProjectSettings.contextType = Context;
 ProjectSettings.contextType = Context;
 
 
-const Warning = styled.span`
+const Warning = styled.div`
+  font-size: 13px;
   color: ${(props: { highlight: boolean, makeFlush?: boolean }) => props.highlight ? '#f5cb42' : ''};
   color: ${(props: { highlight: boolean, makeFlush?: boolean }) => props.highlight ? '#f5cb42' : ''};
-  margin-left: 5px;
+  margin-bottom: 20px;
 `;
 `;
 
 
 const Title = styled.div`
 const Title = styled.div`

+ 0 - 1
dashboard/src/main/home/provisioner/ProvisionerStatus.tsx

@@ -70,7 +70,6 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
       } 
       } 
       
       
       let infras = filterOldInfras(res.data);
       let infras = filterOldInfras(res.data);
-      console.log('infras: ', res.data);
       let error = false;
       let error = false;
 
 
       let maxStep = {} as Record<string, number>
       let maxStep = {} as Record<string, number>

+ 11 - 0
dashboard/src/main/home/templates/expanded-template/LaunchTemplate.tsx

@@ -77,9 +77,20 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
     }, (err: any, res: any) => {
     }, (err: any, res: any) => {
       if (err) {
       if (err) {
         this.setState({ saveValuesStatus: 'error' });
         this.setState({ saveValuesStatus: 'error' });
+        posthog.capture('Failed to deploy template', {
+          name: this.props.currentTemplate.name,
+          namespace: this.state.selectedNamespace,
+          values: values,
+          error: err
+        })
       } else {
       } else {
         // this.props.setCurrentView('cluster-dashboard');
         // this.props.setCurrentView('cluster-dashboard');
         this.setState({ saveValuesStatus: 'successful' });
         this.setState({ saveValuesStatus: 'successful' });
+        posthog.capture('Deployed template', {
+          name: this.props.currentTemplate.name,
+          namespace: this.state.selectedNamespace,
+          values: values,
+        })
       }
       }
     });
     });
   }
   }

+ 22 - 2
dashboard/src/shared/api.tsx

@@ -296,7 +296,7 @@ const getInfra = baseApi<{
   return `/api/projects/${pathParams.project_id}/infra`;
   return `/api/projects/${pathParams.project_id}/infra`;
 });
 });
 
 
-const destroyCluster = baseApi<{
+const destroyEKS = baseApi<{
   eks_name: string,
   eks_name: string,
 }, {
 }, {
   project_id: number,
   project_id: number,
@@ -305,6 +305,24 @@ const destroyCluster = baseApi<{
   return `/api/projects/${pathParams.project_id}/infra/${pathParams.infra_id}/eks/destroy`;
   return `/api/projects/${pathParams.project_id}/infra/${pathParams.infra_id}/eks/destroy`;
 });
 });
 
 
+const destroyGKE = baseApi<{
+  gke_name: string,
+}, {
+  project_id: number,
+  infra_id: number,
+}>('POST', pathParams => {
+  return `/api/projects/${pathParams.project_id}/infra/${pathParams.infra_id}/gke/destroy`;
+});
+
+const destroyDOKS = baseApi<{
+  doks_name: string,
+}, {
+  project_id: number,
+  infra_id: number,
+}>('POST', pathParams => {
+  return `/api/projects/${pathParams.project_id}/infra/${pathParams.infra_id}/doks/destroy`;
+});
+
 const deleteCluster = baseApi<{
 const deleteCluster = baseApi<{
 }, {
 }, {
   project_id: number,
   project_id: number,
@@ -392,7 +410,9 @@ export default {
   deleteInvite,
   deleteInvite,
   deleteProject,
   deleteProject,
   deployTemplate,
   deployTemplate,
-  destroyCluster,
+  destroyEKS,
+  destroyGKE,
+  destroyDOKS,
   getBranchContents,
   getBranchContents,
   getBranches,
   getBranches,
   getChart,
   getChart,

+ 2 - 1
dashboard/src/shared/types.tsx

@@ -3,7 +3,8 @@ export interface ClusterType {
   name: string,
   name: string,
   server: string,
   server: string,
   service_account_id: number
   service_account_id: number
-  infra_id?: number
+  infra_id?: number,
+  service?: string,
 }
 }
 
 
 export interface ChartType {
 export interface ChartType {