Просмотр исходного кода

Merge pull request #778 from porter-dev/0.4.0-fix-websocket-protocol

0.4.0 fix websocket protocol
abelanger5 4 лет назад
Родитель
Сommit
606cb2daf7

+ 8 - 7
dashboard/react-table.d.ts

@@ -45,14 +45,15 @@ import {
   UseSortByHooks,
   UseSortByInstanceProps,
   UseSortByOptions,
-  UseSortByState
-} from 'react-table'
+  UseSortByState,
+} from "react-table";
 
-declare module 'react-table' {
+declare module "react-table" {
   // take this file as-is, or comment out the sections that don't apply to your plugin configuration
-  
-  export interface TableOptions<D extends object = {}>
-    extends UseExpandedOptions<D>,
+
+  export interface TableOptions<
+    D extends object = {}
+  > extends UseExpandedOptions<D>,
       UseFiltersOptions<D>,
       UseGlobalFiltersOptions<D>,
       UseGroupByOptions<D>,
@@ -117,4 +118,4 @@ declare module 'react-table' {
       UseGroupByRowProps<D>,
       UseRowSelectRowProps<D>,
       UseRowStateRowProps<D> {}
-}
+}

+ 10 - 12
dashboard/src/components/Table.tsx

@@ -7,7 +7,7 @@ import Loading from "components/Loading";
 const GlobalFilter: React.FunctionComponent<any> = ({ setGlobalFilter }) => {
   const [value, setValue] = React.useState("");
   const onChange = (value: string) => {
-    setValue(value)
+    setValue(value);
     setGlobalFilter(value || undefined);
   };
 
@@ -99,7 +99,9 @@ const Table: React.FC<TableProps> = ({
 
   return (
     <TableWrapper>
-      {!disableGlobalFilter && <GlobalFilter setGlobalFilter={setGlobalFilter} />}
+      {!disableGlobalFilter && (
+        <GlobalFilter setGlobalFilter={setGlobalFilter} />
+      )}
       <StyledTable {...getTableProps()}>
         <StyledTHead>
           {headerGroups.map((headerGroup) => (
@@ -140,10 +142,10 @@ export const StyledTr = styled.tr`
 export const StyledTd = styled.td`
   font-size: 13px;
   color: #ffffff;
-  :first-child{
+  :first-child {
     padding-left: 10px;
   }
-  :last-child{
+  :last-child {
     padding-right: 10px;
   }
 `;
@@ -157,10 +159,10 @@ export const StyledTh = styled.th`
   font-size: 13px;
   font-weight: 500;
   color: #aaaabb;
-  :first-child{
+  :first-child {
     padding-left: 10px;
   }
-  :last-child{
+  :last-child {
     padding-right: 10px;
   }
 `;
@@ -171,7 +173,6 @@ export const StyledTable = styled.table`
   border-collapse: collapse;
 `;
 
-
 const SearchInput = styled.input`
   outline: none;
   border: none;
@@ -188,12 +189,12 @@ const SearchRow = styled.div`
   width: 100%;
   font-size: 13px;
   color: #ffffff55;
-  border-radius: 4px; 
+  border-radius: 4px;
   user-select: none;
   align-items: center;
   padding: 10px 0px;
   min-width: 300px;
-  max-width: min-content;  
+  max-width: min-content;
   background: #ffffff11;
   margin-bottom: 7px;
   margin-top: 7px;
@@ -204,7 +205,4 @@ const SearchRow = styled.div`
     margin-right: 12px;
     font-size: 20px;
   }
-
 `;
-
-

+ 108 - 104
dashboard/src/main/home/cluster-dashboard/dashboard/ClusterSettings.tsx

@@ -1,9 +1,9 @@
-import React, { useContext, useState } from 'react'
-import styled from 'styled-components';
-import Heading from 'components/values-form/Heading';
+import React, { useContext, useState } from "react";
+import styled from "styled-components";
+import Heading from "components/values-form/Heading";
 import Helper from "components/values-form/Helper";
 import InputRow from "components/values-form/InputRow";
-import { Context } from 'shared/Context';
+import { Context } from "shared/Context";
 import api from "shared/api";
 
 const ClusterSettings: React.FC = () => {
@@ -14,124 +14,128 @@ const ClusterSettings: React.FC = () => {
   const [successfulRotate, setSuccessfulRotate] = useState<boolean>(false);
 
   let rotateCredentials = () => {
-    api.overwriteAWSIntegration(
-      "<token>",
-      {
-        aws_access_key_id: accessKeyId,
-        aws_secret_access_key: secretKey
-      },
-      {
-        projectID: context.currentProject.id,
-        awsIntegrationID: context.currentCluster.aws_integration_id,
-        cluster_id: context.currentCluster.id,
-      }
-    ).then(({ data }) => {
-      setSuccessfulRotate(true)
-    })
-    .catch(() => {
-      setSuccessfulRotate(false)
-    })
-  }
+    api
+      .overwriteAWSIntegration(
+        "<token>",
+        {
+          aws_access_key_id: accessKeyId,
+          aws_secret_access_key: secretKey,
+        },
+        {
+          projectID: context.currentProject.id,
+          awsIntegrationID: context.currentCluster.aws_integration_id,
+          cluster_id: context.currentCluster.id,
+        }
+      )
+      .then(({ data }) => {
+        setSuccessfulRotate(true);
+      })
+      .catch(() => {
+        setSuccessfulRotate(false);
+      });
+  };
 
-  let helperText = <Helper>
-    Delete this cluster and underlying infrastructure. To
-    ensure that everything has been properly destroyed, please visit
-    your cloud provider's console. Instructions to properly delete all
-    resources can be found
-    <a
-      target="none"
-      href="https://docs.getporter.dev/docs/deleting-dangling-resources"
-    >
-      {" "}
-      here
-    </a>.
-  </Helper>
+  let helperText = (
+    <Helper>
+      Delete this cluster and underlying infrastructure. To ensure that
+      everything has been properly destroyed, please visit your cloud provider's
+      console. Instructions to properly delete all resources can be found
+      <a
+        target="none"
+        href="https://docs.getporter.dev/docs/deleting-dangling-resources"
+      >
+        {" "}
+        here
+      </a>
+      .
+    </Helper>
+  );
 
   if (!context.currentCluster?.infra_id || !context.currentCluster?.service) {
-    helperText = <Helper>
-      Remove this cluster from Porter. 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. This operation cannot be undone. 
-    </Helper>
+    helperText = (
+      <Helper>
+        Remove this cluster from Porter. 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. This
+        operation cannot be undone.
+      </Helper>
+    );
   }
 
-  let keyRotationSection = null
+  let keyRotationSection = null;
 
-  if (context.currentCluster?.aws_integration_id && context.currentCluster?.aws_integration_id != 0) {
+  if (
+    context.currentCluster?.aws_integration_id &&
+    context.currentCluster?.aws_integration_id != 0
+  ) {
     if (successfulRotate) {
-      keyRotationSection = <div>
-        <Heading>Credential Rotation</Heading>
-        <Helper>
-          Successfully rotated credentials!
-        </Helper>
+      keyRotationSection = (
+        <div>
+          <Heading>Credential Rotation</Heading>
+          <Helper>Successfully rotated credentials!</Helper>
         </div>
+      );
     } else if (startRotateCreds) {
-      keyRotationSection = <div>
-        <Heading>Credential Rotation</Heading>
-        <Helper>
-          Input the new credentials for the EKS cluster. 
-        </Helper>
-        <InputRow
-          type="text"
-          value={accessKeyId}
-          setValue={(x: string) => setAccessKeyId(x)}
-          label="👤 AWS Access ID"
-          placeholder="ex: AKIAIOSFODNN7EXAMPLE"
-          width="100%"
-          isRequired={true}
-        />
-        <InputRow
-          type="password"
-          value={secretKey}
-          setValue={(x: string) => setSecretKey(x)}
-          label="🔒 AWS Secret Key"
-          placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
-          width="100%"
-          isRequired={true}
-        />
-        <Button
-          color="#616FEEcc"
-          onClick={rotateCredentials}
-        >
-          Submit
-        </Button>
-      </div>
+      keyRotationSection = (
+        <div>
+          <Heading>Credential Rotation</Heading>
+          <Helper>Input the new credentials for the EKS cluster.</Helper>
+          <InputRow
+            type="text"
+            value={accessKeyId}
+            setValue={(x: string) => setAccessKeyId(x)}
+            label="👤 AWS Access ID"
+            placeholder="ex: AKIAIOSFODNN7EXAMPLE"
+            width="100%"
+            isRequired={true}
+          />
+          <InputRow
+            type="password"
+            value={secretKey}
+            setValue={(x: string) => setSecretKey(x)}
+            label="🔒 AWS Secret Key"
+            placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
+            width="100%"
+            isRequired={true}
+          />
+          <Button color="#616FEEcc" onClick={rotateCredentials}>
+            Submit
+          </Button>
+        </div>
+      );
     } else {
-      keyRotationSection = <div>
-        <Heading>Credential Rotation</Heading>
-        <Helper>
-          Rotate the credentials that Porter uses to connect to the cluster.
-        </Helper>
-        <Button
-          color="#616FEEcc"
-          onClick={() => setStartRotateCreds(true)}
-        >
-          Rotate Credentials
-        </Button>
-        
-      </div>
+      keyRotationSection = (
+        <div>
+          <Heading>Credential Rotation</Heading>
+          <Helper>
+            Rotate the credentials that Porter uses to connect to the cluster.
+          </Helper>
+          <Button color="#616FEEcc" onClick={() => setStartRotateCreds(true)}>
+            Rotate Credentials
+          </Button>
+        </div>
+      );
     }
-    
   }
 
   return (
     <div>
       <StyledSettingsSection showSource={false}>
-          {keyRotationSection}
-          <Heading>Delete Cluster</Heading>
-          {helperText}
-          <Button
-            color="#b91133"
-            onClick={() => context.setCurrentModal("UpdateClusterModal")}
-          >
-            Delete Cluster
-          </Button>
-        </StyledSettingsSection>
+        {keyRotationSection}
+        <Heading>Delete Cluster</Heading>
+        {helperText}
+        <Button
+          color="#b91133"
+          onClick={() => context.setCurrentModal("UpdateClusterModal")}
+        >
+          Delete Cluster
+        </Button>
+      </StyledSettingsSection>
     </div>
-  )
-}
+  );
+};
 
-export default ClusterSettings
+export default ClusterSettings;
 
 const StyledSettingsSection = styled.div<{ showSource: boolean }>`
   margin-top: 35px;

+ 7 - 3
dashboard/src/main/home/cluster-dashboard/dashboard/NodeStatusModal.tsx

@@ -17,7 +17,6 @@ export const NodeStatusModal: React.FunctionComponent<NodeStatusModalProps> = ({
   width = "800px",
   height = "min-content",
 }) => {
-
   const columns = useMemo<Column<any>[]>(
     () => [
       {
@@ -49,7 +48,12 @@ export const NodeStatusModal: React.FunctionComponent<NodeStatusModalProps> = ({
       <Modal onRequestClose={onClose} width={width} height={height}>
         Node {node?.name} conditions:
         <TableWrapper>
-          <Table columns={columns} data={data} isLoading={false} disableGlobalFilter={true}/>
+          <Table
+            columns={columns}
+            data={data}
+            isLoading={false}
+            disableGlobalFilter={true}
+          />
         </TableWrapper>
       </Modal>
     </div>
@@ -58,4 +62,4 @@ export const NodeStatusModal: React.FunctionComponent<NodeStatusModalProps> = ({
 
 const TableWrapper = styled.div`
   margin-top: 14px;
-`
+`;

+ 7 - 7
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -142,12 +142,12 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
   };
 
   removeJob = (deletedJob: any) => {
-    let jobs = this.state.jobs.filter(job => {
-      return deletedJob.metadata?.name !== job.metadata?.name
+    let jobs = this.state.jobs.filter((job) => {
+      return deletedJob.metadata?.name !== job.metadata?.name;
     });
 
     this.sortJobsAndSave(jobs);
-  }
+  };
 
   setupJobWebsocket = (chart: ChartType) => {
     let chartVersion = `${chart.chart.metadata.name}-${chart.chart.metadata.version}`;
@@ -193,7 +193,7 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
           chartLabel == chartVersion &&
           releaseLabel == chart.name
         ) {
-          this.removeJob(event.Object)
+          this.removeJob(event.Object);
         }
       }
     };
@@ -431,10 +431,10 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
         }
         return (
           <TabWrapper>
-            <JobList 
-              jobs={this.state.jobs} 
+            <JobList
+              jobs={this.state.jobs}
               setJobs={(jobs: any) => {
-                this.setState({ jobs })
+                this.setState({ jobs });
               }}
             />
             <SaveButton

+ 9 - 9
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobList.tsx

@@ -21,7 +21,7 @@ export default class JobList extends Component<PropsType, StateType> {
   state = {
     deletionCandidate: null as any,
     deletionJob: null as any,
-  }
+  };
 
   renderJobList = () => {
     if (this.props.jobs.length === 0) {
@@ -38,9 +38,11 @@ export default class JobList extends Component<PropsType, StateType> {
             return (
               <JobResource
                 key={job?.metadata?.name}
-                job={job} 
+                job={job}
                 handleDelete={() => this.setState({ deletionCandidate: job })}
-                deleting={this.state.deletionJob?.metadata?.name == job.metadata?.name}
+                deleting={
+                  this.state.deletionJob?.metadata?.name == job.metadata?.name
+                }
               />
             );
           })}
@@ -51,7 +53,7 @@ export default class JobList extends Component<PropsType, StateType> {
 
   deleteJob = () => {
     let { currentCluster, currentProject, setCurrentError } = this.context;
-    let job = this.state.deletionCandidate
+    let job = this.state.deletionCandidate;
 
     api
       .deleteJob(
@@ -69,7 +71,7 @@ export default class JobList extends Component<PropsType, StateType> {
         this.setState({
           deletionJob: this.state.deletionCandidate,
           deletionCandidate: null,
-        })
+        });
       })
       .catch((err) => {
         let parsedErr =
@@ -79,7 +81,7 @@ export default class JobList extends Component<PropsType, StateType> {
         }
         setCurrentError(err);
       });
-  }
+  };
 
   render() {
     return (
@@ -90,9 +92,7 @@ export default class JobList extends Component<PropsType, StateType> {
           onYes={this.deleteJob}
           onNo={() => this.setState({ deletionCandidate: null })}
         />
-        <JobListWrapper>
-          {this.renderJobList()}
-        </JobListWrapper>
+        <JobListWrapper>{this.renderJobList()}</JobListWrapper>
       </>
     );
   }

+ 9 - 5
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobResource.tsx

@@ -270,7 +270,8 @@ export default class JobResource extends Component<PropsType, StateType> {
               <Icon src={icon && icon} />
               <Description>
                 <Label>
-                  Started at {this.readableDate(this.props.job.status?.startTime)}
+                  Started at{" "}
+                  {this.readableDate(this.props.job.status?.startTime)}
                 </Label>
                 <Subtitle>{this.getSubtitle()}</Subtitle>
               </Description>
@@ -280,10 +281,13 @@ export default class JobResource extends Component<PropsType, StateType> {
               {this.renderStatus()}
               <MaterialIconTray disabled={false}>
                 {this.renderStopButton()}
-                <i className="material-icons" onClick={(e) => {
-                  e.stopPropagation();
-                  this.props.handleDelete();
-                }}>
+                <i
+                  className="material-icons"
+                  onClick={(e) => {
+                    e.stopPropagation();
+                    this.props.handleDelete();
+                  }}
+                >
                   delete
                 </i>
                 <i className="material-icons" onClick={this.expandJob}>

+ 22 - 8
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/ControllerTab.tsx

@@ -23,6 +23,8 @@ type StateType = {
   podPendingDelete: any;
   websockets: Record<string, any>;
   selectors: string[];
+  available: number;
+  total: number;
 };
 
 // Controller tab in log section that displays list of pods on click.
@@ -34,6 +36,8 @@ export default class ControllerTab extends Component<PropsType, StateType> {
     podPendingDelete: null as any,
     websockets: {} as Record<string, any>,
     selectors: [] as string[],
+    available: null as number,
+    total: null as number,
   };
 
   updatePods = () => {
@@ -46,7 +50,7 @@ export default class ControllerTab extends Component<PropsType, StateType> {
         {
           cluster_id: currentCluster.id,
           namespace: controller?.metadata?.namespace,
-          selectors : this.state.selectors,
+          selectors: this.state.selectors,
         },
         {
           id: currentProject.id,
@@ -132,8 +136,8 @@ export default class ControllerTab extends Component<PropsType, StateType> {
 
   setupWebsocket = (kind: string) => {
     let { currentCluster, currentProject } = this.context;
-    let protocol = process.env.NODE_ENV == "production" ? "wss" : "ws";
-    let connString = `${protocol}://${process.env.API_SERVER}/api/projects/${currentProject.id}/k8s/${kind}/status?cluster_id=${currentCluster.id}`;
+    let protocol = window.location.protocol == "https:" ? "wss" : "ws";
+    let connString = `${protocol}://${window.location.host}/api/projects/${currentProject.id}/k8s/${kind}/status?cluster_id=${currentCluster.id}`;
 
     if (kind == "pod" && this.state.selectors) {
       connString += `&selectors=${this.state.selectors[0]}`;
@@ -149,12 +153,22 @@ export default class ControllerTab extends Component<PropsType, StateType> {
       let object = event.Object;
       object.metadata.kind = event.Kind;
 
-      // update pods no matter what
-      if (event.Kind == "pod") {
-        this.updatePods();
+      // update pods no matter what if ws message is a pod event.
+      // If controller event, check if ws message corresponds to the designated controller in props.
+      if (
+        event.Kind != "pod" &&
+        object.metadata.uid != this.props.controller.metadata.uid
+      )
+        return;
+
+      if (event.Kind != "pod") {
+        let [available, total] = this.getAvailability(
+          object.metadata.kind,
+          object
+        );
+        this.setState({ available, total });
       }
 
-      if (object.metadata.uid != this.props.controller.metadata.uid) return;
       this.updatePods();
     };
 
@@ -265,7 +279,7 @@ export default class ControllerTab extends Component<PropsType, StateType> {
 
   render() {
     let { controller, selectedPod, isLast, selectPod, isFirst } = this.props;
-    let [available, total] = this.getAvailability(controller.kind, controller);
+    let { available, total } = this.state;
     let status = available == total ? "running" : "waiting";
 
     controller?.status?.conditions?.forEach((condition: any) => {

+ 2 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx

@@ -130,8 +130,9 @@ export default class Logs extends Component<PropsType, StateType> {
       this.ws = null;
       this.setState({ logs: [] });
       this.setupWebsocket();
+    } else if (this.state.currentTab == "System") {
+      this.retrieveEvents(selectedPod);
     }
-    this.retrieveEvents(selectedPod);
   };
 
   componentDidUpdate = (prevProps: any, prevState: any) => {

+ 8 - 8
dashboard/src/shared/api.tsx

@@ -47,13 +47,13 @@ const createAWSIntegration = baseApi<
 
 const overwriteAWSIntegration = baseApi<
   {
-    aws_access_key_id: string,
-    aws_secret_access_key: string,
+    aws_access_key_id: string;
+    aws_secret_access_key: string;
   },
-  { 
-    projectID: number,
-    awsIntegrationID: number,
-    cluster_id: number,
+  {
+    projectID: number;
+    awsIntegrationID: number;
+    cluster_id: number;
   }
 >("POST", (pathParams) => {
   return `/api/projects/${pathParams.projectID}/integrations/aws/${pathParams.awsIntegrationID}/overwrite?cluster_id=${pathParams.cluster_id}`;
@@ -420,8 +420,8 @@ const getClusterNodes = baseApi<
     cluster_id: number;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/clusters/${pathParams.cluster_id}/nodes`
-})
+  return `/api/projects/${pathParams.project_id}/clusters/${pathParams.cluster_id}/nodes`;
+});
 
 const getGitRepoList = baseApi<
   {},