Browse Source

fix merge conflicts

Alexander Belanger 5 năm trước cách đây
mục cha
commit
221b6d1e5a

+ 17 - 3
.github/workflows/gcr.yaml

@@ -1,10 +1,10 @@
 name: Build, Push to GCR.
 on:
   push:
-    branches:
+    branches: 
     - staging
 jobs:
-  build-push-test:
+  login-build-push:
     runs-on: ubuntu-latest
     steps:
     - name: Set up Cloud SDK
@@ -17,7 +17,21 @@ jobs:
       run: gcloud auth configure-docker
     - name: Checkout
       uses: actions/checkout@v2.3.4
+    - name: Write Dashboard Environment Variables
+      run: |
+        cat >./dashboard/.env <<EOL
+        NODE_ENV=development
+        API_SERVER=localhost:8080
+        FULLSTORY_ORG_ID=${{secrets.FULLSTORY_ORG_ID}}
+        DISCORD_KEY=${{secrets.DISCORD_KEY}}
+        DISCORD_CID=${{secrets.DISCORD_CID}}
+        FEEDBACK_ENDPOINT=${{secrets.FEEDBACK_ENDPOINT}}
+        EOL
+
+        cat ./dashboard/.env
     - name: Build
       run: |
-        docker build . -t gcr.io/porter-dev-273614/porter-prov:latest -f ./docker/Dockerfile
+        DOCKER_BUILDKIT=1 docker build . -t gcr.io/porter-dev-273614/porter-prov:latest -f ./docker/Dockerfile
+    - name: Push
+      run: |
         docker push gcr.io/porter-dev-273614/porter-prov:latest

+ 5 - 0
dashboard/package-lock.json

@@ -981,6 +981,11 @@
       "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
       "dev": true
     },
+    "ansi-parser": {
+      "version": "3.2.10",
+      "resolved": "https://registry.npmjs.org/ansi-parser/-/ansi-parser-3.2.10.tgz",
+      "integrity": "sha512-CGKGIbd678lm15IXJXI1cTyOVAnMQw0jES+klW/yIc+GzYccsYanLMhczPIIj2hE64B79g75QfiuWrEWd6nJdg=="
+    },
     "ansi-regex": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",

+ 2 - 2
dashboard/package.json

@@ -12,6 +12,7 @@
     "ace-builds": "^1.4.12",
     "axios": "^0.20.0",
     "dotenv": "^8.2.0",
+    "ini": ">=1.3.6",
     "js-base64": "^3.6.0",
     "js-yaml": "^3.14.0",
     "lodash": "^4.17.20",
@@ -24,8 +25,7 @@
     "react-dom": "^16.13.1",
     "react-modal": "^3.11.2",
     "react-router-dom": "^5.2.0",
-    "styled-components": "^5.2.0",
-    "ini": ">=1.3.6"
+    "styled-components": "^5.2.0"
   },
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",

+ 17 - 11
dashboard/src/main/home/Home.tsx

@@ -28,7 +28,7 @@ type StateType = {
   forceSidebar: boolean,
   showWelcome: boolean,
   currentView: string,
-  viewData: any,
+  viewData: any[],
 
   // Track last project id for refreshing clusters on project change
   prevProjectId: number | null,
@@ -59,16 +59,22 @@ export default class Home extends Component<PropsType, StateType> {
             if (err) {
               console.log(err);
             } else if (res.data) {
-              
+
+              let viewData = [] as any[]
               // TODO: separately handle non meta-provisioning case
               res.data.forEach((el: InfraType) => {
                 if (el.status === 'creating') {
-                  this.setState({ currentView: 'provisioner', viewData: {
+                  viewData.push({
                     infra_id: el.id,
                     kind: el.kind,
-                  }});
+                  })
                 }
               });
+
+              if (viewData.length > 0) {
+                this.setState({ currentView: 'provisioner', viewData});
+              }
+
             }
           });
         } else if (res.data.length === 0) {
@@ -108,7 +114,7 @@ export default class Home extends Component<PropsType, StateType> {
               setCurrentModal('ClusterConfigModal', { currentTab: 'select' });
             }}>Select Clusters</A> tab.<br /><br />
             3. For additional information, please refer to our <A>docs</A>.<br /><br /><br />
-            
+
             * Make sure all fields are explicitly declared (e.g., certs and keys).
           </Placeholder>
         </DashboardWrapper>
@@ -154,8 +160,8 @@ export default class Home extends Component<PropsType, StateType> {
     }
 
     return (
-      <Templates 
-        setCurrentView={(x: string) => this.setState({ currentView: x })} 
+      <Templates
+        setCurrentView={(x: string) => this.setState({ currentView: x })}
       />
     );
   }
@@ -171,11 +177,11 @@ export default class Home extends Component<PropsType, StateType> {
   renderSidebar = () => {
     if (this.context.projects.length > 0) {
 
-      // Force sidebar closed on first provision 
+      // Force sidebar closed on first provision
       if (this.state.currentView === 'provisioner' && this.state.forceSidebar) {
         this.setState({ forceSidebar: false });
       }
-      
+
       return (
         <Sidebar
           forceSidebar={this.state.forceSidebar}
@@ -227,8 +233,8 @@ export default class Home extends Component<PropsType, StateType> {
         {this.renderSidebar()}
 
         <ViewWrapper>
-          <Navbar 
-            logOut={this.props.logOut} 
+          <Navbar
+            logOut={this.props.logOut}
             currentView={this.state.currentView} // For form feedback
           />
           {this.renderContents()}

+ 63 - 15
dashboard/src/main/home/new-project/Provisioner.tsx

@@ -3,11 +3,13 @@ import styled from 'styled-components';
 
 import api from '../../../shared/api';
 import { Context } from '../../../shared/Context';
+import ansiparse from '../../../shared/ansiparser'
 import { integrationList } from '../../../shared/common';
 import loading from '../../../assets/loading.gif';
 
 import Helper from '../../../components/values-form/Helper';
 import { eventNames } from 'process';
+import { inflateRaw, inflateRawSync } from 'zlib';
 
 type PropsType = {
   viewData: any,
@@ -33,11 +35,23 @@ export default class Provisioner extends Component<PropsType, StateType> {
     this.scrollRef.current.scrollTop = this.scrollRef.current.scrollHeight
   }
 
+  isJSON = (str: string) => {
+    try {
+        JSON.parse(str);
+    } catch (e) {
+        return false;
+    }
+    return true;
+  }
+
   componentDidMount() {
     let { currentProject } = this.context;
     let protocol = process.env.NODE_ENV == 'production' ? 'wss' : 'ws'
+    let viewData = this.props.viewData || []
 
-    let websockets = this.props.viewData.forEach((infra: any) => {
+    console.log("viewData", viewData)
+
+    let websockets = viewData.map((infra: any) => {
       let ws = new WebSocket(`${protocol}://${process.env.API_SERVER}/api/projects/${currentProject.id}/provision/${infra.kind}/${infra.infra_id}/logs`)
       
       ws.onopen = () => {
@@ -46,32 +60,63 @@ export default class Provisioner extends Component<PropsType, StateType> {
 
       ws.onmessage = (evt: MessageEvent) => {
         let event = JSON.parse(evt.data)
-        let data = event.map((msg: any) => { return `${infra.kind}: ${msg["Values"]["data"]}` })
+        console.log(event)
+        let validEvents = [] as any[]
         let err = null
-
-        // check for error
-        event.forEach((e: any) => {
-          err = e["Values"]["kind"] == "error" ? e["Values"]["data"] : null
-        })
-
+        
+        for (var i = 0; i < event.length; i++) {
+          let msg = event[i]
+          if (msg["Values"] && msg["Values"]["data"] && this.isJSON(msg["Values"]["data"])) { 
+            let d = JSON.parse(msg["Values"]["data"])
+  
+            if (d["kind"] == "error") {
+              err = d["log"]
+              break;
+            }
+  
+            // add only valid events
+            if (d["log"] != null && d["created_resources"] != null && d["total_resources"] != null) {
+              validEvents.push(d)
+            }
+          }
+        }
+  
         if (err) {
-          this.setState({ logs: [err] })
+          let e = ansiparse(err).map((el: any) => {
+            return el.text
+          })
+          console.log("error", e)
+          this.setState({ logs: e })
+          return;
+        }
+  
+        if (validEvents.length == 0) {
+          return;
         }
         
-        if (!this.state.maxStep[infra.kind]) {
+        if (!this.state.maxStep[infra.kind] || !this.state.maxStep[infra.kind]["total_resources"]) {
           this.setState({
             maxStep: {
               ...this.state.maxStep,
-              [infra.kind] : event[event.length]["Values"]["created_resources"]
+              [infra.kind] : validEvents[validEvents.length - 1]["total_resources"]
             }
           })
         }
+        
+        let logs = [] as any[]
+        validEvents.forEach((e: any) => {
+          logs.push(...ansiparse(e["log"]))
+        })
 
+        logs = logs.map((log: any) => {
+          return log.text
+        })
+  
         this.setState({ 
-          logs: [...this.state.logs, ...data], 
+          logs: [...this.state.logs, ...logs], 
           currentStep: {
             ...this.state.currentStep,
-            [infra.kind] : event[event.length]["Values"]["created_resources"]
+            [infra.kind] : validEvents[validEvents.length - 1]["created_resources"]
           },
         }, () => {
           this.scrollToBottom()
@@ -93,7 +138,9 @@ export default class Provisioner extends Component<PropsType, StateType> {
   }
 
   componentWillUnmount() {
-    this.state.websockets?.forEach((ws) => {
+    if (!this.state.websockets) { return; }
+
+    this.state.websockets.forEach((ws) => {
       ws.close()
     })
   }
@@ -111,6 +158,7 @@ export default class Provisioner extends Component<PropsType, StateType> {
     let currentStep = 0;
 
     for (let key in this.state.maxStep) {
+      console.log(key)
       maxStep += this.state.maxStep[key]
     }
 
@@ -133,7 +181,7 @@ export default class Provisioner extends Component<PropsType, StateType> {
         </Helper>
 
         <LoadingBar>
-          <Loaded progress={((currentStep / maxStep) * 100).toString() + '%'} />
+          <Loaded progress={((currentStep / (maxStep == 0 ? 1 : maxStep)) * 100).toString() + '%'} />
         </LoadingBar>
 
         <LogStream ref={this.scrollRef}>

+ 134 - 0
dashboard/src/shared/ansiparser.tsx

@@ -0,0 +1,134 @@
+/* eslint-disable no-plusplus, no-continue */
+const foregroundColors = {
+    '30': 'black',
+    '31': 'red',
+    '32': 'green',
+    '33': 'yellow',
+    '34': 'blue',
+    '35': 'magenta',
+    '36': 'cyan',
+    '37': 'white',
+    '90': 'grey',
+  } as Record<string, string>;
+
+  const backgroundColors = {
+    '40': 'black',
+    '41': 'red',
+    '42': 'green',
+    '43': 'yellow',
+    '44': 'blue',
+    '45': 'magenta',
+    '46': 'cyan',
+    '47': 'white',
+  } as Record<string, string>;
+
+  const styles = {
+    '1': 'bold',
+    '3': 'italic',
+    '4': 'underline',
+  } as Record<string, string>;
+
+  const eraseChar = (matchingText: any, result: any) => {
+    if (matchingText.length) {
+      return [matchingText.substr(0, matchingText.length - 1), result];
+    } else if (result.length) {
+      const index = result.length - 1;
+      const { text } = result[index];
+      const newResult =
+        text.length === 1
+          ? result.slice(0, result.length - 1)
+          : result.map((item: any, i: number) =>
+              index === i
+                ? { ...item, text: text.substr(0, text.length - 1) }
+                : item
+            );
+  
+      return [matchingText, newResult];
+    }
+  
+    return [matchingText, result];
+  };
+  
+  const ansiparse = (str: string) => {
+    let matchingControl = null;
+    let matchingData = null;
+    let matchingText = '';
+    let ansiState = [] as any[];
+    let result = [] as any[];
+    let state = {} as any;
+  
+    for (let i = 0; i < str.length; i++) {
+      if (matchingControl !== null) {
+        if (matchingControl === '\x1b' && str[i] === '[') {
+          if (matchingText) {
+            state.text = matchingText;
+            result.push(state);
+            state = {};
+            matchingText = '';
+          }
+  
+          matchingControl = null;
+          matchingData = '';
+        } else {
+          matchingText += matchingControl + str[i];
+          matchingControl = null;
+        }
+  
+        continue;
+      } else if (matchingData !== null) {
+        if (str[i] === ';') {
+          ansiState.push(matchingData);
+          matchingData = '';
+        } else if (str[i] === 'm') {
+          ansiState.push(matchingData);
+          matchingData = null;
+          matchingText = '';
+  
+          for (let a = 0; a < ansiState.length; a++) {
+            const ansiCode = ansiState[a];
+  
+            if (foregroundColors[ansiCode]) {
+              state.foreground = foregroundColors[ansiCode];
+            } else if (backgroundColors[ansiCode]) {
+              state.background = backgroundColors[ansiCode];
+            } else if (ansiCode === 39) {
+              delete state.foreground;
+            } else if (ansiCode === 49) {
+              delete state.background;
+            } else if (styles[ansiCode]) {
+              state[styles[ansiCode]] = true;
+            } else if (ansiCode === 22) {
+              state.bold = false;
+            } else if (ansiCode === 23) {
+              state.italic = false;
+            } else if (ansiCode === 24) {
+              state.underline = false;
+            }
+          }
+  
+          ansiState = [];
+        } else {
+          matchingData += str[i];
+        }
+  
+        continue;
+      }
+  
+      if (str[i] === '\x1b') {
+        matchingControl = str[i];
+      } else if (str[i] === '\u0008') {
+        [matchingText, result] = eraseChar(matchingText, result);
+      } else {
+        matchingText += str[i];
+      }
+    }
+  
+    if (matchingText) {
+      state.text = matchingText + (matchingControl || '');
+      result.push(state);
+    }
+  
+    return result;
+  };
+  
+  export default ansiparse;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6 - 0
prov.yaml


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác