├── .DS_Store ├── .babelrc ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── LICENSE ├── README.MD ├── __tests__ └── gcp.test.ts ├── jest.config.js ├── package-lock.json ├── package.json ├── setupEnzyme.js ├── src ├── .DS_Store ├── client │ ├── .DS_Store │ ├── assets │ │ ├── credsPage │ │ │ ├── aws.png │ │ │ ├── azure.png │ │ │ ├── azure2.png │ │ │ ├── deploymentGCP.gif │ │ │ ├── google.png │ │ │ ├── kub.icns │ │ │ ├── kub.png │ │ │ ├── kubernati image.png │ │ │ ├── kubernatiGif.gif │ │ │ ├── puttingAws.gif │ │ │ └── puttingCreds.gif │ │ └── visualizerPage │ │ │ ├── Basic_hexagon.svg │ │ │ ├── hexagon.ong.gif │ │ │ ├── hexagon.png │ │ │ └── hexagon.svg │ ├── components │ │ ├── DisplayContainer.tsx │ │ ├── LandingPage.tsx │ │ ├── UploadPage.tsx │ │ ├── UploadPage2.tsx │ │ ├── app.tsx │ │ ├── gcpDeploy.tsx │ │ ├── sidebar.tsx │ │ └── visualizer.tsx │ ├── index.html │ ├── renderer.tsx │ └── styles.css └── main │ ├── aws │ ├── awsDataCLI.ts │ └── getAWSData.ts │ ├── gcp │ └── getGCPdata.ts │ ├── local │ └── local.ts │ └── main.ts ├── store.tsx ├── styles.css ├── tsconfig.json ├── tslint.json └── webpack.config.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/.DS_Store -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/env", 4 | "@babel/react", 5 | "@babel/typescript" 6 | ], 7 | "plugins": [ 8 | ["@babel/plugin-transform-async-to-generator"] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | extends: [ 4 | 'airbnb', 5 | 'prettier', 6 | 'prettier/react' 7 | ], 8 | plugins: ['prettier','import','react','jest','jsx-a11y','babel'], 9 | env: { 10 | browser: true, 11 | node: true, 12 | jest: true, 13 | es6: true 14 | }, 15 | parserOptions: { 16 | ecmaFeatures: { 17 | jsx: true 18 | }, 19 | ecmaVersion: 2018, 20 | sourceType: 'module', 21 | }, 22 | rules: { 23 | semi: ['error','always'], 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /creds.json 4 | .DS_store 5 | /release-builds 6 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | printWidth: 100, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | tabWidth: 4, 7 | bracketSpacing: true, 8 | jsxBracketSameLine: true 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 OSLabs Beta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # KuberOptic 2 | ### 3 | kuberoptic.com 4 | *** 5 | ![](src/client/assets/credsPage/kubernatiGif.gif) 6 | ### A visualization and deployment tool for your Kubernetes cluster 7 | ### 8 | 9 | KuberOptic provides a tool that allows developers to visualize the structure of their clusters, including the nodes, pods, and containers. At each level of a cluster, KuberOptic gives you monitoring analytics that describe the health of your application. KuberOptic also allows you to deploy new clusters onto the cloud. 10 | 11 | *** 12 | ## How to Use: 13 | 14 | ### Local Deployment of Kubernetes 15 | First we need a cluster to visualize. We could use minikube to set up a simple cluster. This api will automatically scan for whether a cluster is deployed locally and visualize it. 16 | 17 | [Kubernetes Documentation](https://kubernetes.io/docs/tasks/tools/install-minikube/) 18 | *** 19 | ### Reading clusters from cloud services 20 | *** 21 | ### GCP 22 | First create a google developer account and start a project through GCP. Find your credentials on Google and then enter them with the corresponding time zone on the upload page. The credientials you get from Google should be in a JSON in the forn of GOOGLE_APPLICATION_CREDIENTIALS. Your deployed cluster through GCP will now be visualized in real time. 23 | **Prequisites** 24 | - Google Developer account 25 | - Create a project on GCP 26 | 27 | **Configuring GCP through command line** 28 | ``` 29 | gcloud auth application-default login 30 | ``` 31 | #### Input Project credentials 32 | ![](src/client/assets/credsPage/puttingCreds.gif) 33 | *** 34 | #### Deployment (GCP) 35 | ![](src/client/assets/credsPage/deploymentGCP.gif) 36 | *** 37 | ### AWS 38 | Our API utilizes AWS-SDK's EKS(Amazon Elastic Kubernetes Service). Simply go and create an AWS account to generate a secret ID and SecretKey for your IAM account. Enter the Secret ID and Key along with the cluster you want to inspect. As of now, you must specify the cluster name 39 | ![](src/client/assets/credsPage/puttingAws.gif) 40 | *** 41 | ### Azure 42 | **COMING SOON** 43 | *** 44 | **Build project with Webpack** 45 | ``` 46 | npm run prod 47 | ``` 48 | **Run in production environment** 49 | ``` 50 | npm start 51 | ``` 52 | **Run tests with Jest** 53 | ``` 54 | npm run test 55 | ``` 56 | **Build package for mac OS*** 57 | ``` 58 | npm run package-mac 59 | ``` 60 | **Lint project** 61 | ``` 62 | npm run lint 63 | ``` 64 | ## Coming Soon 65 | **Stretch Features** 66 | - Deployment to Azure 67 | - Remodeled UI 68 | *** 69 | ## Authors 70 | [Juan Espinoza](https://github.com/jespinoza17) 71 | [Jacob Banks](https://github.com/jacobbanks) 72 | [Jay Dawson](https://github.com/ImJustJay) 73 | [Jimmy Deng](https://github.com/rev619) 74 | ## License 75 | MIT -------------------------------------------------------------------------------- /__tests__/gcp.test.ts: -------------------------------------------------------------------------------- 1 | // import test credentials 2 | const fetchLocal = require('../src/main/local/local').default 3 | const [quickstart, create] = require('../src/main/gcp/getGCPdata').default 4 | const testCreds = {}; 5 | // set up tests to output of GCP functions, local cluster functions 6 | // GCP tests are asynchronous 7 | 8 | // test creation with different inputs 9 | describe('Cluster testing', () => { 10 | 11 | describe('Testing fectchLocal function', () => { 12 | it('fetchLocal data should return a node named Minikube', () => { 13 | fetchLocal().then(data => expect(data.dataforNodes.nodeName).not.toBe(undefined)); 14 | }); 15 | it('fetchLocal data should come from default namespace', () => { 16 | fetchLocal().then(data => expect(data.dataforNodes.metaDataNameSpace).not.toBe(undefined)); 17 | }); 18 | it('fetchLocal data should have the correct container', () => { 19 | fetchLocal().then(data => expect(data.dataforNodes.dockerContainer_0.containerName).toBe('hello-node')); 20 | }); 21 | it('fetchLocal data should return the correct name of the cluster', () => { 22 | fetchLocal().then(data => expect(data.dataforNodes.clusterName).toBe('Minikube')); 23 | }); 24 | it('fetchLocal data should return the correct status of the cluster', () => { 25 | fetchLocal().then(data => expect(data.dataforNodes.metaDat.statusDat.phase).toBe('Running')); 26 | }); 27 | it('fetchLocal data should verify that service links have been enabled', () => { 28 | fetchLocal().then(data => expect(data.dataforNodes.metaDat.specDat.enableServiceLinks).toBeTruthy()); 29 | }); 30 | 31 | }); 32 | 33 | // 34 | describe('Testing GCP fetchData Function', () => { 35 | xit('quickstart should return GCP cluster data as an array with at least one cluster', () => { 36 | // make sure the length is of length 1 or more 37 | quickstart(testCreds).then(data => expect(data.length).not.toBe(0)) 38 | }); 39 | xit('First cluster has correct properties', () => { 40 | quickstart(testCreds).then(data => { 41 | expect(data[0].clusterData.name).not.toBe(undefined) 42 | expect(data[0].clusterData.clusterName).not.toBe(undefined) 43 | }); 44 | }) 45 | xit('CLuster should be up and running', () => { 46 | quickstart(testCreds).then(data => expect(data[0].clusterData.clusterStatus).toBe('RUNNING')) 47 | }); 48 | xit('check for correct cluster data', () => { 49 | quickstart(testCreds).then(data => expect(data[0].location).toBe('us-central1-a')) 50 | }); 51 | xit('check for correct number of nodes', () => { 52 | quickstart(testCreds).then(data => expect(data[0].nodeCount).toBe(4)) 53 | }); 54 | 55 | }) 56 | 57 | // tests will be rewritten to check for most relevant data 58 | describe('Testing GCP create Function', () => { 59 | 60 | xit('Should correctly create a cluster to GCP', () => { 61 | // nothing should be returned from the create function 62 | create(testCreds).then(data => expect(data).toBe(undefined)) 63 | }); 64 | xit('check for correct cluster data', () => { 65 | create(testCreds).then(data => expect(data).not.toBe(undefined)) 66 | }); 67 | 68 | }) 69 | 70 | // need to import some function or object from AWS to perform tests 71 | describe('Testing AWS Function', () => { 72 | xit('Commands are working correctly', () => { 73 | //test case to be added 74 | }); 75 | 76 | xit('Correct configuration to AWS', () => { 77 | //test case to be added 78 | }); 79 | 80 | }) 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | globals: { 4 | 'ts-jest': { 5 | diagnostics: false, 6 | } 7 | }, 8 | // setupFiles: ['./setupEnzyme.js'], // for enzyme 9 | moduleFileExtensions: ['ts','tsx','js','json','jsx','node'], //ts in front 10 | moduleDirectories: ['node_modules'], 11 | modulePaths: [''], 12 | transform: { 13 | '^.+\\.jsx?$': 'babel-jest', 14 | '^.+\\.tsx?$': 'ts-jest', 15 | }, 16 | testMatch: [ "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ], 17 | // snapshotSerializers: ['enzyme-to-json/serializer'], // for enzyme set up 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kubernati", 3 | "version": "1.0.0", 4 | "productName": "KuberOptic", 5 | "description": "An Electron app for developers to visualize their Kubernetes clusters in real-time", 6 | "main": "dist/main.bundle.js", 7 | "scripts": { 8 | "start": "electron ./dist/main.bundle.js", 9 | "dev": "electron ./dist/main.bundle.js", 10 | "prod": "rimraf dist && cross-env NODE_ENV=production webpack --progress --colors", 11 | "build": "tsc && cp ./src/client/index.html", 12 | "build:watch": "npm run build -- --watch", 13 | "build:mwl": "npm run compile && electron-builder", 14 | "lint": "eslint --ignore-path .gitignore '**/*.{ts,tsx}' ", 15 | "lint:fix": "npm run lint --fix", 16 | "test": "jest", 17 | "package-mac": "electron-packager . kuberoptic --overwrite --platform=darwin --arch=x64 --icon=src/client/assets/credsPage/kub.icns --prune=true --out=release-builds", 18 | "create-installer-mac": "electron-installer-dmg ./release-builds/kuberoptic-darwin-x64/kuberoptic.app kuberoptic --out=release-builds --overwrite" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/oslabs-beta/kubernati.git" 23 | }, 24 | "contributors": [ 25 | "Jacob", 26 | "Jay", 27 | "Jimmy", 28 | "Juan" 29 | ], 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/oslabs-beta/kubernati/issues" 33 | }, 34 | "homepage": "https://github.com/oslabs-beta/kubernati#readme", 35 | "devDependencies": { 36 | "@babel/plugin-transform-async-to-generator": "^7.5.0", 37 | "@babel/plugin-transform-modules-commonjs": "^7.5.0", 38 | "@types/enzyme": "^3.10.3", 39 | "@types/jest": "^24.0.18", 40 | "@types/node": "^12.7.4", 41 | "@types/react": "^16.9.2", 42 | "@types/react-dom": "^16.9.0", 43 | "@types/underscore": "^1.9.2", 44 | "@typescript-eslint/parser": "^2.2.0", 45 | "babel-core": "^6.26.3", 46 | "babel-jest": "^24.9.0", 47 | "babel-loader": "^8.0.6", 48 | "babel-plugin-transform-runtime": "^6.23.0", 49 | "babel-polyfill": "^6.26.0", 50 | "babel-preset-es2015": "^6.24.1", 51 | "babel-preset-stage-0": "^6.24.1", 52 | "copy-pkg-json-webpack-plugin": "0.0.38", 53 | "cross-env": "^5.2.0", 54 | "css-loader": "^3.2.0", 55 | "electron": "^6.0.8", 56 | "electron-builder": "^21.2.0", 57 | "electron-connect": "^0.6.3", 58 | "electron-connect-webpack-plugin": "^0.1.1", 59 | "electron-devtools-installer": "^2.2.4", 60 | "electron-installer-dmg": "^3.0.0", 61 | "electron-packager": "^14.0.6", 62 | "electron-prebuilt": "^1.4.13", 63 | "electron-react-devtools": "^0.5.3", 64 | "electron-reload": "^1.5.0", 65 | "electron-reload-webpack-plugin": "^2.0.4", 66 | "electron-webpack": "^2.7.4", 67 | "enzyme": "^3.10.0", 68 | "enzyme-adapter-react-16": "^1.14.0", 69 | "enzyme-to-json": "^3.4.0", 70 | "eslint": "^6.3.0", 71 | "eslint-config-airbnb-base": "^14.0.0", 72 | "eslint-plugin-babel": "^5.3.0", 73 | "eslint-plugin-import": "^2.18.2", 74 | "eslint-plugin-jest": "^22.17.0", 75 | "eslint-plugin-jsx-a11y": "^6.2.3", 76 | "eslint-plugin-react": "^7.14.3", 77 | "file-loader": "^4.2.0", 78 | "jest": "^24.9.0", 79 | "lodash": "^4.17.15", 80 | "rimraf": "^3.0.0", 81 | "source-map-loader": "^0.2.4", 82 | "style-loader": "^1.0.0", 83 | "ts-jest": "^24.0.2", 84 | "ts-loader": "^6.0.4", 85 | "tsconfig-paths": "^3.8.0", 86 | "typescript": "^3.5.3", 87 | "url-loader": "^2.1.0", 88 | "webpack": "^4.39.2", 89 | "webpack-cli": "^3.3.7", 90 | "webpack-livereload-plugin": "^2.2.0" 91 | }, 92 | "dependencies": { 93 | "@babel/core": "^7.5.5", 94 | "@babel/preset-env": "^7.5.5", 95 | "@babel/preset-react": "^7.0.0", 96 | "@babel/preset-typescript": "^7.3.3", 97 | "@google-cloud/container": "^1.1.3", 98 | "@google-cloud/containeranalysis": "^1.3.3", 99 | "@kubernetes/client-node": "^0.10.2", 100 | "@material-ui/icons": "^4.2.1", 101 | "@types/aws-sdk": "^2.7.0", 102 | "@types/d3": "^5.7.2", 103 | "@types/electron-devtools-installer": "^2.2.0", 104 | "@types/react-router-dom": "^4.3.5", 105 | "aws-sdk": "^2.524.0", 106 | "babel-loader": "^8.0.6", 107 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", 108 | "bootstrap": "^4.3.1", 109 | "d3": "^5.11.0", 110 | "electron-connect": "^0.6.3", 111 | "google-proto-files": "^1.1.0", 112 | "html-webpack-plugin": "^3.2.0", 113 | "prettier": "^1.18.2", 114 | "react": "^16.9.0", 115 | "react-bootstrap": "^1.0.0-beta.12", 116 | "react-dom": "^16.9.0", 117 | "react-router-dom": "^5.0.1", 118 | "scale": "0.0.7", 119 | "tachyons": "^4.11.1", 120 | "three": "^0.107.0", 121 | "three-orbitcontrols": "^2.102.2", 122 | "ts-node": "^8.3.0", 123 | "underscore": "^1.9.1", 124 | "util": "^0.12.1" 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /setupEnzyme.js: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | import {configure} from 'enzyme'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | 5 | configure({ adapter: new Adapter()}); 6 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/.DS_Store -------------------------------------------------------------------------------- /src/client/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/.DS_Store -------------------------------------------------------------------------------- /src/client/assets/credsPage/aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/aws.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/azure.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/azure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/azure2.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/deploymentGCP.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/deploymentGCP.gif -------------------------------------------------------------------------------- /src/client/assets/credsPage/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/google.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/kub.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/kub.icns -------------------------------------------------------------------------------- /src/client/assets/credsPage/kub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/kub.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/kubernati image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/kubernati image.png -------------------------------------------------------------------------------- /src/client/assets/credsPage/kubernatiGif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/kubernatiGif.gif -------------------------------------------------------------------------------- /src/client/assets/credsPage/puttingAws.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/puttingAws.gif -------------------------------------------------------------------------------- /src/client/assets/credsPage/puttingCreds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/credsPage/puttingCreds.gif -------------------------------------------------------------------------------- /src/client/assets/visualizerPage/Basic_hexagon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/client/assets/visualizerPage/hexagon.ong.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/visualizerPage/hexagon.ong.gif -------------------------------------------------------------------------------- /src/client/assets/visualizerPage/hexagon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/KuberOptic/9b0392e8d49497c616a5545a455dabb6d8f8feb9/src/client/assets/visualizerPage/hexagon.png -------------------------------------------------------------------------------- /src/client/assets/visualizerPage/hexagon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 114 | 115 | -------------------------------------------------------------------------------- /src/client/components/DisplayContainer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Deploy from './gcpDeploy'; 3 | import { useContext } from 'react'; 4 | import {StoreContext} from '../../../store'; 5 | import Visualizer from './visualizer' 6 | 7 | const DisplayContainer = () => { 8 | const [Store, setStore] = useContext(StoreContext) 9 | 10 | return (
{ Store.gcpDeployPage ? : 11 |
12 | 13 |
14 | } 15 |
16 | ) 17 | } 18 | 19 | 20 | 21 | export default DisplayContainer; 22 | -------------------------------------------------------------------------------- /src/client/components/LandingPage.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from 'react'; 2 | import UploadPage from './UploadPage'; 3 | import UploadPage2 from './UploadPage2' 4 | import {StoreContext} from '../../../store'; 5 | 6 | const LandingPage = () => { 7 | const [Store, setStore] = useContext(StoreContext); 8 | 9 | const myFunctionG = () => { 10 | console.log(Store.landingPageState); 11 | setStore({...Store, landingPageState: true}) 12 | } 13 | const myFunctionA = () => { 14 | console.log(Store.landingPageState2); 15 | setStore({...Store, landingPageState2: true}) 16 | } 17 | return ( 18 |
19 | {Store.landingPageState ? : 20 | Store.landingPageState2 ? : 21 |
22 |
23 |
KuberOptic: The Kubernetes Visualizer
24 | 25 | 26 |
27 | } 28 |
29 | ) 30 | } 31 | 32 | 33 | export default LandingPage; 34 | -------------------------------------------------------------------------------- /src/client/components/UploadPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useState, useEffect, useContext } from 'react'; 3 | import DisplayContainer from './DisplayContainer'; 4 | import {StoreContext} from '../../../store'; 5 | const { ipcRenderer } = require('electron'); 6 | require('events').EventEmitter.defaultMaxListeners = 20; 7 | 8 | const UploadPage = () => { 9 | 10 | const [Store, setStore] = useContext(StoreContext); 11 | ipcRenderer.on('clusterClient', (event: any, arg: any) => { 12 | //logic incase we have more than one cluster already rendered 13 | if(Store.clusters != null){ 14 | let newClusters = Store.clusters; 15 | if(Store.clusters.length === Store.clusterCount){ 16 | arg.forEach(el=>{ 17 | newClusters.push(el) 18 | }) 19 | } 20 | setStore({...Store, clusters:newClusters}) 21 | } 22 | else{ 23 | setStore({...Store, clusters:arg, clusterCount:1}); 24 | 25 | } 26 | // setStore({...Store, clusters:arg}); 27 | event.returnValue = 'done'; 28 | }) 29 | 30 | const handleInput = (e: React.FormEvent) => { 31 | setStore({...Store, credentials:e.currentTarget.value}) 32 | } 33 | 34 | const handleBack = ()=>{ 35 | setStore({...Store, landingPageState:false}) 36 | } 37 | 38 | const handleSubmit = () => { 39 | const creds = JSON.parse(Store.credentials); 40 | if(typeof creds !== 'object'){ 41 | console.log('Enter a JSON object from GCP'); 42 | console.log('locStore: ', Store.gcploc) 43 | } 44 | else{ 45 | ipcRenderer.send('asynchronous-message', creds) 46 | setStore({...Store, uploadPageState: true}); 47 | } 48 | } 49 | 50 | const handleLoc = (event) => { 51 | setStore({...Store, gcploc: event.currentTarget.value}); 52 | } 53 | 54 | return
{Store.uploadPageState ? : 55 |
56 |
57 | 58 |
Google Cloud Platform
59 |
60 | 61 | 62 |
63 | 64 |   65 | 66 |
67 | 78 | 79 |
80 | }
81 | } 82 | 83 | export default UploadPage; 84 | -------------------------------------------------------------------------------- /src/client/components/UploadPage2.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useContext } from 'react'; 3 | import DisplayContainer from './DisplayContainer'; 4 | import {StoreContext} from '../../../store'; 5 | const { ipcRenderer } = require('electron'); 6 | 7 | const UploadPage = () => { 8 | 9 | const [Store, setStore] = useContext(StoreContext); 10 | 11 | ipcRenderer.on('clusterClient2', (event: any, arg: any) => { 12 | setStore({...Store, gcp: arg}); 13 | }) 14 | 15 | const handleKey = (e: React.FormEvent) => { 16 | setStore({...Store, awsKey:e.currentTarget.value}) 17 | } 18 | const handleSecret = (e: React.FormEvent) => { 19 | setStore({...Store, awsKey:e.currentTarget.value}) 20 | } 21 | const handleName = (e: React.FormEvent) => { 22 | setStore({...Store, awsKey:e.currentTarget.value}) 23 | } 24 | const handleBack = ()=>{ 25 | setStore({...Store, landingPageState2:false}) 26 | } 27 | const handleSubmit = () => { 28 | const creds = JSON.parse(Store.credentials); 29 | if(typeof creds !== 'object'){ 30 | console.log('Enter a JSON object from GCP'); 31 | } 32 | else{ 33 | ipcRenderer.send('asynchronous-message2', creds) 34 | setStore({...Store, uploadPageState: true}); 35 | } 36 | } 37 | return
{Store.uploadPageState ? : 38 |
39 |
40 | 41 |
Amazon Web Services
42 |
43 | 44 | 45 | 46 |
47 | 48 |   49 | 50 |
51 | 52 | 53 |
54 | }
55 | } 56 | 57 | export default UploadPage; 58 | -------------------------------------------------------------------------------- /src/client/components/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import LandingPage from './LandingPage'; 3 | import '../styles.css'; 4 | import { StoreContextProvider } from '../../../store';; 5 | import 'tachyons'; 6 | function App() { 7 | return ( 8 | 9 |
10 | 11 |
12 |
13 | ); 14 | 15 | 16 | 17 | 18 | } 19 | export default App; 20 | -------------------------------------------------------------------------------- /src/client/components/gcpDeploy.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useContext } from 'react'; 3 | import {StoreContext} from '../../../store' 4 | const [quickstart, create] = require('../../main/gcp/getGCPdata').default 5 | import 'tachyons' 6 | let input = {}; 7 | 8 | const gcpDeploy = () =>{ 9 | const [Store, setStore] = useContext(StoreContext); 10 | const handleType = (event) => { 11 | input['clusterType'] = event.currentTarget.value; 12 | } 13 | const handleName = (event) => { 14 | input['name'] = event.currentTarget.value; 15 | } 16 | const handleLoc = (event) => { 17 | 18 | input['zone'] = event.currentTarget.value; 19 | } 20 | const handleBack = ()=>{ 21 | setStore({...Store, gcpDeployPage:false}) 22 | } 23 | const handleSubmit = () =>{ 24 | create(Store.credentials, input['zone'], input) 25 | setStore({...Store, gcpDeployPage:false}) 26 | } 27 | 28 | return ( 29 |
30 |
31 | 32 |
33 | 34 | 43 | 44 | 55 | 56 |
57 | 58 |
59 | 60 | 61 |
62 |
63 | 64 |
65 | 66 |
67 |

68 | Affordable
69 |

70 |
71 |
72 | Good for starting your first cluster for lightweight apps
73 | Machine type:g1-small
74 | Autoscaling:Disabled
75 | Stackdriver Logging and Monitoring: Disabled
76 | Boot disk size: 30GB
77 |
78 | 79 |
80 |

81 | Standard
82 |

83 |
84 |
85 | Continuous integration, web serving, backend
86 | Machine type:n1-standard
87 | Autoscaling:Disabled
88 | Stackdriver Logging and Monitoring: Disabled
89 | Boot disk size: 100GB
90 |
91 | 92 |
93 |

94 | CPU-Intensive
95 |

96 |
97 |
98 | Web crawling or anything that requires more cpu
99 | Machine type:n1-highcpu-4
100 | Autoscaling:True
101 | Stackdriver Logging and Monitoring: Enabled
102 | Boot disk size: 100GB
103 |
104 | 105 |
106 |

107 | Memory-Intensive
108 |

109 |
110 |
111 | Databases, analytics, anything that takes memory
112 | Machine type:n1-highmem-2
113 | Autoscaling:True
114 | Stackdriver Logging and Monitoring: Enabled
115 | Boot disk size: 100GB
116 |
117 | 118 |
119 |

120 | GPU Accelerated Computing
121 |

122 |
123 |
124 | Machine Learning, video transcoding, scientific computations
125 | Machine type:n1-highmem-2 + GPU
126 | Autoscaling:True
127 | Stackdriver Logging and Monitoring: Enabled
128 | Boot disk size: 100GB
129 |
130 | 131 |
132 |

133 | Highly available
134 |

135 |
136 |
137 | Most demanding requirements
138 | Machine type:n1-highmem-2 + GPU
139 | Autoscaling:True
140 | Stackdriver Logging and Monitoring: Enabled
141 | Boot disk size: 100GB
142 |
143 | 144 |
145 | 146 |
147 | ) 148 | } 149 | 150 | export default gcpDeploy; 151 | -------------------------------------------------------------------------------- /src/client/components/sidebar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useState, useEffect, useContext } from 'react'; 3 | import {StoreContext} from '../../../store' 4 | 5 | const SideBar = () =>{ 6 | const [Store, setStore] = useContext(StoreContext); 7 | const handleDeploy = () =>{ 8 | setStore({...Store, gcpDeployPage:true}) 9 | } 10 | const handleBack = ()=>{ 11 | setStore({...Store, landingPageState2:false, landingPageState:false, 12 | uploadPageState:false, uploadPageState2:false}) 13 | } 14 | return( 15 |
16 | 17 | 18 |
19 | ) 20 | } 21 | 22 | export default SideBar; 23 | -------------------------------------------------------------------------------- /src/client/components/visualizer.tsx: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import React, { useEffect, useRef, useContext }from 'react' 3 | import * as d3 from 'd3'; 4 | import * as _ from 'underscore'; 5 | import SideBar from './sidebar'; 6 | import {StoreContext} from '../../../store'; 7 | 8 | const width = window.innerWidth; 9 | const height = window.innerHeight; 10 | const vizWidth = width; 11 | const fov = 100; 12 | const near = 50; 13 | const far = 5000; 14 | 15 | 16 | // -----------fakeStore----------- if needed to test 17 | 18 | 19 | // const store = [ 20 | // { 21 | // endpoint: '35.225.31.212', 22 | // clusterName: 'standard-cluster-1', 23 | // clusterDescription: '', 24 | // creationTime: '2019-08-27T23:21:01+00:00', 25 | // clusterStatus: 'RUNNING', 26 | // nodeCount: 7, 27 | // location: 'us-central1-a', 28 | // NodePool_0: [ 'default-pool', 'diskSize[Gb]: 100', 'MachineType: g1-small' ], 29 | // NodePool_1: [ 'pool-1', 'diskSize[Gb]: 100', 'MachineType: f1-micro' ], 30 | // NodePool_2: [ 'pool-2', 'diskSize[Gb]: 100', 'MachineType: f1-micro' ] 31 | // }, 32 | // { 33 | // endpoint: '34.70.204.169', 34 | // clusterName: 'weakclust', 35 | // clusterDescription: '', 36 | // creationTime: '2019-09-11T03:02:01+00:00', 37 | // clusterStatus: 'RUNNING', 38 | // nodeCount: 1, 39 | // location: 'us-central1-a', 40 | // NodePool_0: [ 'pool-1', 'diskSize[Gb]: 30', 'MachineType: g1-small' ] 41 | // } 42 | // ] 43 | 44 | 45 | const Visualizer = () => { 46 | 47 | let [store, setStore] = useContext(StoreContext); 48 | 49 | useEffect(() => { 50 | if(store.clusters){ 51 | const renderer = new THREE.WebGLRenderer(); 52 | renderer.setSize( width, height ); 53 | ref.current.appendChild(renderer.domElement); 54 | let camera = new THREE.PerspectiveCamera( fov, width / height, near, far ); 55 | //---------------number of hexagons---------------\\ 56 | const pointAmmount = store.clusters.length; 57 | 58 | // https://upload.wikimedia.org/wikipedia/commons/e/e6/Basic_hexagon.svg 59 | // https://fastforwardlabs.github.io/visualization_assets/circle-sprite.png 60 | const circleSprite = new THREE.TextureLoader().load(".././src/client/assets/visualizerPage/Basic_hexagon.svg") 61 | const testSprite = new THREE.TextureLoader().load('https://fastforwardlabs.github.io/visualization_assets/circle-sprite.png') 62 | const colorArray = ['skyblue', 'blue', 'lightblue', 'skyblue', 'blue', 'lightblue', ] 63 | const colorArray2 = ['red'] 64 | /* Testing to make random elements appear */ 65 | 66 | const randomPosition = (offset:number, radius?: number ) => { 67 | const ptAngle = Math.random() * 2 * Math.PI; 68 | const ptRadiusSq = Math.random() * radius * radius; 69 | const ptX = Math.sqrt(ptRadiusSq) * Math.cos(ptAngle); 70 | const ptY = Math.sqrt(ptRadiusSq) * Math.sin(ptAngle); 71 | return [ptX + offset, ptY]; 72 | } 73 | 74 | const pointInfo = []; 75 | const pointInfo2 = []; 76 | 77 | //generating shapes for cluster! 78 | for (let i = 0; i < pointAmmount; i++) { 79 | const position = [2400*i -2400,1] 80 | const group = i; 81 | const name = store.clusters[i].clusterName; 82 | const clusterStatus = store.clusters[i].clusterStatus; 83 | const creationTime = store.clusters[i].creationTime; 84 | const location = store.clusters[i].location; 85 | const nodeCount = store.clusters[i].nodeCount; 86 | const endpoint = store.clusters[i].endpoint 87 | const point = { position, name, clusterStatus, creationTime, location, nodeCount, endpoint, group }; 88 | pointInfo.push(point); 89 | } 90 | 91 | 92 | //for each cluster we must put nodes inside 93 | //omfg it works 94 | store.clusters.forEach(((cluster,i)=>{ 95 | for(let j = 0; j < cluster.nodeCount; j++){ 96 | const name2 = `Point` + j; 97 | const position = randomPosition(pointInfo[i].position[0], 300); 98 | const group = 0; 99 | const point2 = {position, name2, group} 100 | pointInfo2.push(point2) 101 | } 102 | })) 103 | 104 | const generatedPoints = pointInfo; 105 | const generatedPoints2 = pointInfo2; 106 | const pointsGeometry = new THREE.Geometry(); 107 | const pointsGeometry2 = new THREE.Geometry(); 108 | const colors = []; 109 | const colors2 = []; 110 | 111 | for (const point of generatedPoints) { 112 | const vertex = new THREE.Vector3(point.position[0], point.position[1]) 113 | pointsGeometry.vertices.push(vertex); 114 | const color = new THREE.Color(colorArray[point.group]); 115 | colors.push(color); 116 | } 117 | for (const point2 of generatedPoints2) { 118 | const vertex = new THREE.Vector3(point2.position[0], point2.position[1]) 119 | pointsGeometry2.vertices.push(vertex); 120 | const color = new THREE.Color(colorArray2[point2.group]); 121 | colors2.push(color); 122 | } 123 | pointsGeometry.colors = colors; 124 | pointsGeometry2.colors = colors2; 125 | //sizeAttenuation:true makes shakes bigger when zoom 126 | 127 | const pointsMaterial = new THREE.PointsMaterial({ size: 800, sizeAttenuation: true, 128 | vertexColors: THREE.VertexColors, map: circleSprite, transparent: true,}); 129 | const pointsMaterial2 = new THREE.PointsMaterial({ size: 100, sizeAttenuation: true, 130 | vertexColors: THREE.VertexColors, map: testSprite, transparent: true,}); 131 | //this where the shape is created 132 | 133 | const points = new THREE.Points(pointsGeometry, pointsMaterial); 134 | const points2 = new THREE.Points(pointsGeometry2, pointsMaterial2); 135 | const scene = new THREE.Scene(); 136 | 137 | scene.add(points); 138 | scene.add(points2) 139 | scene.background = new THREE.Color('black'); 140 | 141 | function toRadians (angle) { 142 | return angle * (Math.PI / 180); 143 | } 144 | 145 | const getScaleFromZ = (cameraZPosition) => { 146 | const halfFov = fov/2; 147 | const halfFovRadians = toRadians(halfFov); 148 | const halfFovHeight = Math.tan(halfFovRadians) * cameraZPosition; 149 | const fovHeight = halfFovHeight * 2; 150 | const scale = height / fovHeight; // Divide visualization height by height derived from field of view 151 | return scale; 152 | } 153 | 154 | function getZFromScale(scale) { 155 | const halfFov = fov/2; 156 | const halfFovRadians = toRadians(halfFov); 157 | let scaleHeight = height / scale; 158 | let cameraZPosition = scaleHeight / (2 * Math.tan(halfFovRadians)); 159 | return cameraZPosition; 160 | } 161 | 162 | function zoomHandler(d3_transform) { 163 | let scale = d3_transform.k; 164 | let x = -(d3_transform.x - vizWidth / 2) / scale; 165 | let y = (d3_transform.y - height / 2) / scale; 166 | let z = getZFromScale(scale); 167 | camera.position.set(x, y, z); 168 | } 169 | 170 | let zoom = d3.zoom() 171 | .scaleExtent([getScaleFromZ(far), getScaleFromZ(near)]) 172 | .on('zoom', () => { 173 | let d3_transform = d3.event.transform; 174 | zoomHandler(d3_transform); 175 | }); 176 | //d3 White space in the browser 177 | const view = d3.select(renderer.domElement); 178 | function setUpZoom() { 179 | view.call(zoom); 180 | const initialScale = getScaleFromZ(far); 181 | const initialTransform = d3.zoomIdentity.translate(vizWidth / 2, height / 2).scale(initialScale); 182 | zoom.transform(view, initialTransform); 183 | camera.position.set(0, 0, far); 184 | } 185 | 186 | setUpZoom(); 187 | 188 | const animate = function () { 189 | requestAnimationFrame(animate); 190 | renderer.render(scene, camera); 191 | }; 192 | animate(); 193 | 194 | const mouseToThree = (mouseX?: number, mouseY?: number) => { 195 | return new THREE.Vector3( mouseX / vizWidth * 2 - 1, - (mouseY / height) * 2 + 1, 1) 196 | } 197 | 198 | function sortIntersectsByDistanceToRay(intersects) { 199 | return _.sortBy(intersects, "distanceToRay"); 200 | } 201 | 202 | const hoverContainer = new THREE.Object3D(); 203 | const removeHighlights = () => { 204 | hoverContainer.remove(...hoverContainer.children); 205 | }; 206 | 207 | const tooltipState: {[k: string]: any} = { 208 | display: "none", 209 | } 210 | const grouptipState:{[k: string]: any} = { 211 | display: "none", 212 | } 213 | const toolTip = divRefOne.current; 214 | const pointTip = divRefTwo.current; 215 | const groupTip = divRefThree.current; 216 | 217 | //---------highlight functionality--------// 218 | const highlightPoint = (datum) => { 219 | removeHighlights(); 220 | const geometry = new THREE.Geometry(); 221 | geometry.vertices.push(new THREE.Vector3(datum.position[0], datum.position[1], 0)); 222 | geometry.colors = [ new THREE.Color(colorArray[datum.group])]; 223 | const material = new THREE.PointsMaterial({ 224 | size: 500, 225 | sizeAttenuation: false, 226 | vertexColors: THREE.VertexColors, 227 | map: circleSprite, 228 | transparent: false 229 | }); 230 | const point = new THREE.Points(geometry, material); 231 | hoverContainer.add(point); 232 | }; 233 | 234 | const updateTooltip = () => { 235 | toolTip.style.display = tooltipState.display; 236 | toolTip.style.left = tooltipState.left + 'px'; 237 | toolTip.style.top = tooltipState.top + 'px'; 238 | pointTip.innerText = tooltipState.name; 239 | pointTip.style.background = colorArray[tooltipState.group]; 240 | pStatus.current.textContent = tooltipState.clusterStatus //+ tooltipState.creationTime + tooltipState.location + tooltipState.nodeCount; 241 | pTime.current.textContent = tooltipState.creationTime; 242 | pLocation.current.textContent = tooltipState.location; 243 | pNode.current.textContent = tooltipState.nodeCount; 244 | pendpoint.current.textContent = tooltipState.endpoint; 245 | } 246 | const updateTooltip2 = () => { 247 | groupTip.style.display = grouptipState.display; 248 | groupTip.style.left = grouptipState.left + 'px'; 249 | groupTip.style.top = grouptipState.top + 'px'; 250 | pointTip.innerText = grouptipState.name; 251 | pointTip.style.background = colorArray[grouptipState.group]; 252 | pStatus.current.textContent = grouptipState.clusterStatus //+ grouptipState.creationTime + grouptipState.location + grouptipState.nodeCount; 253 | pTime.current.textContent = grouptipState.creationTime; 254 | pLocation.current.textContent = grouptipState.location; 255 | pNode.current.textContent = grouptipState.nodeCount; 256 | } 257 | function showTooltip(mousePosition, datum) { 258 | const tooltipWidth = 120; 259 | let xOffset = -tooltipWidth / 2; 260 | let yOffset = 30; 261 | tooltipState.display = "block"; 262 | tooltipState.left = mousePosition[0] + xOffset; 263 | tooltipState.top = mousePosition[1] + yOffset; 264 | tooltipState.name = datum.name; 265 | tooltipState.group = datum.group; 266 | tooltipState.clusterStatus = datum.clusterStatus; 267 | tooltipState.creationTime = datum.creationTime; 268 | tooltipState.location = datum.location; 269 | tooltipState.nodeCount = datum.nodeCount; 270 | tooltipState.endpoint = datum.endpoint 271 | updateTooltip(); 272 | } 273 | function showTooltip2(mousePosition, datum) { 274 | grouptipState.display = "block"; 275 | grouptipState.left = 0; 276 | grouptipState.top = 400; 277 | grouptipState.name = datum.name; 278 | grouptipState.group = datum.group; 279 | grouptipState.clusterStatus = datum.clusterStatus; 280 | grouptipState.clusterStatus = datum.clusterStatus; 281 | grouptipState.creationTime = datum.creationTime; 282 | grouptipState.location = datum.location; 283 | grouptipState.nodeCount = datum.nodeCount; 284 | updateTooltip2(); 285 | } 286 | 287 | //ray caster makes sure when we hover over shape we get it on dom element 288 | const raycaster = new THREE.Raycaster(); 289 | //this threshhold is what makes you hover over more than the centre 290 | raycaster.params.Points.threshold = 300; 291 | 292 | const checkCollission = (mousePosition) => { 293 | const mouseVector = mouseToThree(...mousePosition); 294 | raycaster.setFromCamera(mouseVector, camera); 295 | const intersects = raycaster.intersectObject(points); 296 | if (intersects[0]) { 297 | const sortedCollisions = sortIntersectsByDistanceToRay(intersects); 298 | const collision: any = sortedCollisions[0]; 299 | const index = collision.index 300 | const datum = generatedPoints[index]; 301 | showTooltip(mousePosition, datum); 302 | highlightPoint(datum); 303 | } else { 304 | removeHighlights(); 305 | hideTooltip(); 306 | } 307 | } 308 | 309 | // raycasting helper functions end 310 | view.on('mousemove', () => { 311 | const [mouseX, mouseY] = d3.mouse(view.node()); 312 | const mousePosition = [mouseX, mouseY]; 313 | checkCollission(mousePosition); 314 | }) 315 | 316 | // pointsContainer.add(points); 317 | view.on('mouseleave', () => { 318 | removeHighlights(); 319 | }); 320 | 321 | function hideTooltip() { 322 | tooltipState.display = 'none'; 323 | updateTooltip(); 324 | } 325 | } 326 | }) 327 | 328 | const ref = useRef(null) 329 | const divRefOne = useRef(null) 330 | const divRefTwo = useRef(null) 331 | const divRefThree = useRef(null) 332 | 333 | const pStatus = useRef(null) 334 | const pTime = useRef(null) 335 | const pLocation = useRef(null) 336 | const pNode = useRef(null) 337 | const pendpoint = useRef(null) 338 | 339 | return ( 340 | <> 341 | 342 |
343 |
344 |
345 |
status: 346 |
347 |
348 | Time Created: 349 |
350 |
351 | Cluster Location: 352 |
353 |
354 | nodeCount: 355 |
356 |
357 | Endpoint: 358 |
359 |
360 |
361 | 362 | ); 363 | }; 364 | 365 | export default Visualizer; 366 | -------------------------------------------------------------------------------- /src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | kubernati 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/client/renderer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import "./styles.css" 4 | import App from './components/app' 5 | 6 | const GOOGLE_APPLICATION_CREDENTIALS:object = { 7 | } 8 | const zone:string = 'us-central1-a' 9 | 10 | ReactDOM.render(, document.getElementById('root')); 11 | -------------------------------------------------------------------------------- /src/client/styles.css: -------------------------------------------------------------------------------- 1 | #info { 2 | position: absolute; 3 | top: 10px; 4 | width: 100%; 5 | text-align: center; 6 | z-index: 100; 7 | display:block; 8 | } 9 | #leCanvas{ 10 | float:left; 11 | width: 100%; 12 | height:500px; 13 | /* border: black; */ 14 | /* border-radius: 10px; */ 15 | } 16 | #leSidebar{ 17 | position: absolute; 18 | height:100%; 19 | widows: 200px; 20 | float:left; 21 | background-color: rgb(0, 26, 255); 22 | border:red 10px; 23 | border-radius: 10px; 24 | } 25 | #tool-tip { 26 | display: none; 27 | position: absolute; 28 | pointer-events: none; 29 | font-size: 14px; 30 | width: 250px; 31 | color: black; 32 | text-align: center; 33 | line-height: 1; 34 | padding: 6px; 35 | background: white; 36 | font-family: sans-serif; 37 | } 38 | #point-tip { 39 | padding: 4px; 40 | margin-bottom: 4px; 41 | } 42 | #group-tip { 43 | display: none; 44 | position: absolute; 45 | pointer-events: none; 46 | font-size: 14px; 47 | width: 250px; 48 | color: black; 49 | text-align: center; 50 | line-height: 1; 51 | padding: 6px; 52 | background: white; 53 | font-family: sans-serif; 54 | } 55 | /* 56 | .app { 57 | height: 100vh; 58 | background-color: rgb(0, 0, 0); 59 | } */ 60 | 61 | .text { 62 | color: aqua; 63 | margin-top: 20px; 64 | margin-left: 290px; 65 | font-size: 20px; 66 | } 67 | 68 | 69 | .displayContainer { 70 | color: aquamarine; 71 | } 72 | 73 | 74 | .kubLogo { 75 | transform: rotate(360deg); 76 | height: 300px; 77 | width: 300px; 78 | margin-top: 25px; 79 | margin-left: 240px; 80 | color: rgb(254, 254, 255); 81 | animation: rotation 2.5s infinite linear; 82 | } 83 | 84 | 85 | .logo { 86 | transform: rotate(360deg); 87 | height: 100px; 88 | width: 100px; 89 | margin-top: 35px; 90 | margin-left: 225px; 91 | background-color: oldlace; 92 | border: solid 5px black; 93 | border-radius: 20px; 94 | /* animation: rotation 4s infinite linear; */ 95 | } 96 | 97 | .logo1 { 98 | transform: rotate(360deg); 99 | height: 100px; 100 | width: 100px; 101 | margin-top: 35px; 102 | margin-left: 130px; 103 | border: solid 10px black; 104 | border-radius: 20px; 105 | /* animation: rotation 4s infinite linear; */ 106 | } 107 | 108 | .logo2 { 109 | transform: rotate(360deg); 110 | height: 100px; 111 | width: 100px; 112 | margin-top: 35px; 113 | margin-left: 130px; 114 | /* animation: rotation 4s infinite linear; */ 115 | background-color: red; 116 | border: solid 5px black; 117 | border-radius: 20px; 118 | } 119 | 120 | @keyframes rotation { 121 | from { 122 | transform: rotate(0deg); 123 | } 124 | to { 125 | transform: rotate(359deg); 126 | } 127 | } 128 | 129 | .uploadInput { 130 | height: 70px; 131 | width: 250px; 132 | border: dodgerblue solid 5px; 133 | border-radius: 5px; 134 | color: black; 135 | background-color: rgb(255, 255, 255); 136 | margin-left: 250px; 137 | margin-top: 30px; 138 | font-size: 30px; 139 | font-family: sans-serif; 140 | } 141 | 142 | .uploadButt { 143 | height: 50px; 144 | width: 75px; 145 | border: dodgerblue solid 5px; 146 | border-radius: 5px; 147 | margin-left: 30px; 148 | margin-top: 30px; 149 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 150 | font-weight: bold; 151 | font-size: 15px; 152 | background-color: rgb(255, 255, 255); 153 | } 154 | .backButton{ 155 | height: 50px; 156 | width: 75px; 157 | border: dodgerblue solid 5px; 158 | border-radius: 5px; 159 | margin-top: 30px; 160 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 161 | font-weight: bold; 162 | font-size: 15px; 163 | background-color: rgb(255, 255, 255); 164 | } 165 | 166 | .inputDeployPage{ 167 | display:flex; 168 | flex-direction: column; 169 | float:left; 170 | } 171 | 172 | 173 | .buts{ 174 | display:flex; 175 | align-items: flex-end; 176 | } 177 | #clicker { 178 | background-color:lightblue; 179 | outline:none; 180 | cursor:pointer; 181 | } 182 | #hiddenAf{ 183 | display:none; 184 | background-color:lightblue; 185 | } 186 | #clicker:focus+#hiddenAf{ 187 | display:block; 188 | } 189 | .loc{ 190 | /* height:20px; 191 | width:200px; 192 | font-size:15px; */ 193 | height: 50px; 194 | width: 175px; 195 | border: dodgerblue solid 5px; 196 | border-radius: 5px; 197 | margin-left: 30px; 198 | margin-top: 30px; 199 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 200 | font-weight: bold; 201 | font-size: 15px; 202 | background-color: rgb(255, 255, 255); 203 | } 204 | .clusterType{ 205 | height:20px; 206 | width:200px; 207 | font-size:15px; 208 | } 209 | .uploadDiv { 210 | height: 100vh; 211 | } 212 | .kubUpload { 213 | transform: rotate(360deg); 214 | height: 100px; 215 | width: 100px; 216 | margin-top: 60px; 217 | margin-left: 325px; 218 | color: rgb(254, 254, 255); 219 | /* animation: rotation 1s infinite linear; */ 220 | } 221 | 222 | .kubUploadText { 223 | height: 100px; 224 | width: 200px; 225 | margin-top: 15px; 226 | color: aquamarine; 227 | margin-left: 285px; 228 | } 229 | 230 | #root { 231 | background-color: black; 232 | position: absolute; 233 | top: 0; bottom: 0; right: 0; left: 0; 234 | outline: thin dashed green; 235 | display: flex; 236 | align-items: center; 237 | justify-content: center; 238 | } 239 | 240 | .mainDiv { 241 | 242 | margin-right: 200px; 243 | } 244 | 245 | 246 | .vizDiv { 247 | height: 100%; 248 | } 249 | 250 | .SB { 251 | height: 50px; 252 | width: 175px; 253 | border: rgb(7, 185, 255) solid 5px; 254 | border-radius: 5px; 255 | /* margin-left: 30px; 256 | margin-top: 30px; */ 257 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 258 | font-weight: bold; 259 | font-size: 15px; 260 | background-color: rgb(255, 2, 213); 261 | } 262 | 263 | .clusterType { 264 | height: 50px; 265 | width: 175px; 266 | border: dodgerblue solid 5px; 267 | border-radius: 5px; 268 | /* margin-left: 30px; 269 | margin-top: 30px; */ 270 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 271 | font-weight: bold; 272 | font-size: 15px; 273 | background-color: azure; 274 | } 275 | 276 | .uploadButtD { 277 | height: 50px; 278 | width: 175px; 279 | border: dodgerblue solid 5px; 280 | border-radius: 5px; 281 | /* margin-left: 30px; 282 | margin-top: 30px; */ 283 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 284 | font-weight: bold; 285 | font-size: 15px; 286 | background-color: azure; 287 | } 288 | 289 | #deployLoc { 290 | margin-bottom: 5px; 291 | } 292 | 293 | #infobox{ 294 | display:flex; 295 | flex-direction: column; 296 | float:right; 297 | /* margin-top: 50px; */ 298 | width: 450px; 299 | } 300 | 301 | #deployBack { 302 | margin-left: 30px; 303 | } 304 | 305 | #deploySubmit { 306 | margin-left: 40px; 307 | } 308 | 309 | #deployChooseClustType{ 310 | margin-left: 40px; 311 | } 312 | 313 | #deployClustName { 314 | margin-left: 42px; 315 | width: 375px; 316 | } 317 | 318 | #uploadDivForSubmitandBackButts { 319 | margin-left: 275px; 320 | } 321 | #uploadSelectMenu { 322 | margin-left: 230px; 323 | width: 300px; 324 | } 325 | 326 | #uploadPage2SubmitandBackButts { 327 | margin-top: 50px; 328 | margin-left: 275px; 329 | } 330 | -------------------------------------------------------------------------------- /src/main/aws/awsDataCLI.ts: -------------------------------------------------------------------------------- 1 | // // This allows to write CLI Bash commands in our scripts. 2 | // const util = require('util') 3 | // const exec = util.promisify(require('child_process').exec); 4 | 5 | // // This object will store the aws data entered when they begin the app 6 | 7 | // // Call this function whenever you want to run a command in the CLI; 8 | // async function runCommand(command: String, callback: Function){ 9 | // await exec(command, function(error: String, stdout: String, stderr: String) { 10 | // if (error) console.log(error, stderr) 11 | // console.log('stdout' , stdout) 12 | // // callback(stdout); 13 | // }) 14 | // } 15 | // /* This command is used to test wheethter the CLI responds with a prompt for more information. 16 | // Use this whenever you need to respond to any prompts */ 17 | // const respondCommand = (command: String) => { 18 | // return exec(command, function(error: String, stdout: String, stderr: String) { 19 | // if (error) console.log(error, stderr) 20 | // console.log(stdout); 21 | // }) 22 | // } 23 | 24 | // /* This is the first CLI command that needs to run, because is configures a user machine to use AWS 25 | // It will ask for four prompts the AWS Key, Secret, and Format */ 26 | // // In this case awsConfigure becomes an object with a series of keys that can be accessed. 27 | // const awsConfigure = respondCommand('aws configure'); 28 | 29 | // /* These are used to write to the Stdin key on the awsConfigure Object, 30 | // which respond to the prompts needed to properly configure the machine. */ 31 | // // awsConfigure.stdin.write(awsInfo.awsKey); 32 | // // awsConfigure.stdin.write(awsInfo.awsSecret); 33 | // // awsConfigure.stdin.write("us-east-1"); 34 | // // awsConfigure.stdin.write('json'); 35 | 36 | // /*This information is configured in the AWS Console. 37 | // It is called a VPC stack. The user must currently already have configured a VPC stack 38 | // to deploy a cluster thorugh the application. 39 | // <--------------------------------------------> 40 | // VPC Configuration Data 41 | // sg-00b65d65fb3c67cc7 42 | // subnet-0af1a965b1a5ec4da, subnet-003c64142f3d08046, subnet-07af232880f4ad84b 43 | // vpc-0baf1b99ffb8f0418 44 | // <--------------------------------------------> /* 45 | 46 | // /* This is the text needed to create a cluster. 47 | // If we implement the ability to configure IAM arn, roles, and vpc stack 48 | // then we will have to store that information in objects 49 | // and use template literals to add that user data to the string. */ 50 | // // const createClusterText: String = 'aws eks create-cluster --name TestKubernati \ 51 | // // --role-arn arn:aws:iam::467094939373:role/eksServiceRole --resources-vpc-config subnetIds=subnet-003c64142f3d08046,subnet-003c64142f3d08046,subnet-07af232880f4ad84b,securityGroupIds=sg-00b65d65fb3c67cc7'; 52 | 53 | // // This desployes the cluster using the createClusterText and logs the response. 54 | // // const deployCluster: void = runCommand(createClusterText, (data: String) => console.log(data)) 55 | 56 | // /*This describes the data. We will need to either have the user enter a name of a cluster they want to visualize 57 | // or we will ahve to find a way to see already deployed clusters. */ 58 | 59 | // // const describeCluster: void = runCommand(`aws eks describe-cluster --name ${awsInfo.clusterName}`, 60 | // // (data: String) => console.log(data)); 61 | // runCommand(`aws eks describe-cluster --name ${awsInfo.clusterName}`, (data: String) => { 62 | // console.log('hello') 63 | // }) 64 | // // console.log("dog: ", dog) 65 | // } 66 | // // quickstart() -------------------------------------------------------------------------------- /src/main/aws/getAWSData.ts: -------------------------------------------------------------------------------- 1 | // const AWS = require('aws-sdk') 2 | 3 | // let eks = new AWS.EKS({region: 'us-east-1'}); 4 | 5 | // // AWS.config.getCredentials((err) => { 6 | // // if (err) { 7 | // // console.log(err) 8 | // // } else { 9 | // // console.log('Access key:', AWS.config.credentials.accessKeyId); 10 | // // console.log('Secret access key:', AWS.config.credentials.secretAccessKey); 11 | // // console.log('Region', process.env.AWS_REGION); 12 | // // } 13 | // // }) 14 | 15 | // //-------------function to get clusters-------------\\ 16 | // async function quickstart(params){ 17 | // eks.describeCluster(params, function(err, data) { 18 | // if (err) { 19 | // console.log(err, err.stack); 20 | // } // an error occurred 21 | // else{ 22 | // console.log('awsDat["clusterName"]=',data.cluster.name); // successful response 23 | // console.log('awsDat["endpoint"]=',data.cluster.endpoint) 24 | // console.log('awsDat["creationTime"]=',data.cluster.createdAt); 25 | // console.log('awsDat["clusterStatus"]=',data.cluster.status); 26 | // console.log('awsDat["nodeCount"]=','1'); 27 | // console.log('awsDat["location"]=','us-east-1'); 28 | // return data; 29 | // } 30 | // }) 31 | // } 32 | 33 | // export default quickstart; -------------------------------------------------------------------------------- /src/main/gcp/getGCPdata.ts: -------------------------------------------------------------------------------- 1 | const container = require('@google-cloud/container'); 2 | 3 | // quickstart takes in the GCP credientials object and a timezone, defaults to central1-a if not specified 4 | async function quickstart(GOOGLE_APPLICATION_CREDENTIALS:object, zone:string='us-central1-a') { 5 | const client = new container.v1.ClusterManagerClient(GOOGLE_APPLICATION_CREDENTIALS); 6 | 7 | const projectId:string = GOOGLE_APPLICATION_CREDENTIALS['project_id']; 8 | const request:object = { 9 | projectId, 10 | zone 11 | }; 12 | //response returns an object that has all the info we need 13 | const [response] = await client.listClusters(request); 14 | const clusters:any = response.clusters; 15 | 16 | const clusterArray = []; 17 | 18 | clusters.forEach(cluster=>{ 19 | let gcpDat:object = {}; 20 | 21 | gcpDat["endpoint"] = cluster.endpoint 22 | gcpDat["clusterName"] = cluster.name; 23 | gcpDat["clusterDescription"] = cluster.description; 24 | gcpDat["creationTime"] = cluster.createTime; 25 | gcpDat["clusterStatus"] = cluster.status; 26 | gcpDat["nodeCount"] = cluster.currentNodeCount; 27 | gcpDat["location"] = cluster.location; 28 | cluster.nodePools.forEach((node, i)=>{ 29 | gcpDat[`NodePool_${i}`] = [node.name , `diskSize[Gb]: ${node.config.diskSizeGb}`, 30 | `MachineType: ${node.config.machineType}`] 31 | }) 32 | clusterArray.push(gcpDat) 33 | }) 34 | return clusterArray; 35 | } 36 | 37 | async function create(GOOGLE_APPLICATION_CREDENTIALS:any, zone:string ='us-central1-a', input:object = {'clusterType':'affordable', 'name':'deployCluster', 'zone':'us-central1-a'}){ 38 | const client:any = new container.v1.ClusterManagerClient(GOOGLE_APPLICATION_CREDENTIALS); 39 | GOOGLE_APPLICATION_CREDENTIALS = JSON.parse(GOOGLE_APPLICATION_CREDENTIALS); 40 | const projectId:string = GOOGLE_APPLICATION_CREDENTIALS["project_id"]; 41 | let cluster:object ={}; 42 | 43 | if(input['clusterType'] == 'affordable'){ 44 | cluster = { 45 | "name": input['name'], 46 | "masterAuth": { 47 | "clientCertificateConfig": {} 48 | }, 49 | "loggingService": "none", 50 | "monitoringService": "none", 51 | "network": `projects/${projectId}/global/networks/default`, 52 | "addonsConfig": { 53 | "httpLoadBalancing": {}, 54 | "horizontalPodAutoscaling": {}, 55 | "kubernetesDashboard": { 56 | "disabled": true 57 | }, 58 | "istioConfig": { 59 | "disabled": true 60 | } 61 | }, 62 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 63 | "nodePools": [ 64 | { 65 | "name": "pool-1", 66 | "config": { 67 | "machineType": "g1-small", 68 | "diskSizeGb": 30, 69 | "oauthScopes": [ 70 | "https://www.googleapis.com/auth/devstorage.read_only", 71 | "https://www.googleapis.com/auth/logging.write", 72 | "https://www.googleapis.com/auth/monitoring", 73 | "https://www.googleapis.com/auth/servicecontrol", 74 | "https://www.googleapis.com/auth/service.management.readonly", 75 | "https://www.googleapis.com/auth/trace.append" 76 | ], 77 | "imageType": "COS", 78 | "diskType": "pd-standard" 79 | }, 80 | "initialNodeCount": 1, 81 | "autoscaling": {}, 82 | "management": { 83 | "autoUpgrade": true, 84 | "autoRepair": true 85 | }, 86 | "version": "1.13.7-gke.24" 87 | } 88 | ], 89 | "networkPolicy": {}, 90 | "ipAllocationPolicy": { 91 | "useIpAliases": true 92 | }, 93 | "masterAuthorizedNetworksConfig": {}, 94 | "defaultMaxPodsConstraint": { 95 | "maxPodsPerNode": "110" 96 | }, 97 | "authenticatorGroupsConfig": {}, 98 | "privateClusterConfig": {}, 99 | "databaseEncryption": { 100 | "state": "DECRYPTED" 101 | }, 102 | "initialClusterVersion": "1.13.7-gke.24", 103 | "location": input['zone'] 104 | } 105 | } 106 | 107 | if(input['clusterType'] == 'standard'){ 108 | cluster = { 109 | "name": input['name'], 110 | "masterAuth": { 111 | "clientCertificateConfig": {} 112 | }, 113 | "loggingService": "logging.googleapis.com", 114 | "monitoringService": "monitoring.googleapis.com", 115 | "network": `projects/${projectId}/global/networks/default`, 116 | "addonsConfig": { 117 | "httpLoadBalancing": {}, 118 | "horizontalPodAutoscaling": {}, 119 | "kubernetesDashboard": { 120 | "disabled": true 121 | }, 122 | "istioConfig": { 123 | "disabled": true 124 | } 125 | }, 126 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 127 | "nodePools": [ 128 | { 129 | "name": "default-pool", 130 | "config": { 131 | "machineType": "n1-standard-1", 132 | "diskSizeGb": 100, 133 | "oauthScopes": [ 134 | "https://www.googleapis.com/auth/devstorage.read_only", 135 | "https://www.googleapis.com/auth/logging.write", 136 | "https://www.googleapis.com/auth/monitoring", 137 | "https://www.googleapis.com/auth/servicecontrol", 138 | "https://www.googleapis.com/auth/service.management.readonly", 139 | "https://www.googleapis.com/auth/trace.append" 140 | ], 141 | "imageType": "COS", 142 | "diskType": "pd-standard", 143 | "shieldedInstanceConfig": {} 144 | }, 145 | "initialNodeCount": 3, 146 | "autoscaling": {}, 147 | "management": { 148 | "autoUpgrade": true, 149 | "autoRepair": true 150 | }, 151 | "version": "1.12.8-gke.10" 152 | } 153 | ], 154 | "networkPolicy": {}, 155 | "ipAllocationPolicy": { 156 | "useIpAliases": true 157 | }, 158 | "masterAuthorizedNetworksConfig": {}, 159 | "defaultMaxPodsConstraint": { 160 | "maxPodsPerNode": "110" 161 | }, 162 | "authenticatorGroupsConfig": {}, 163 | "privateClusterConfig": {}, 164 | "databaseEncryption": { 165 | "state": "DECRYPTED" 166 | }, 167 | "initialClusterVersion": "1.12.8-gke.10", 168 | "location": input['zone'] 169 | } 170 | } 171 | 172 | if(input['clusterType'] == 'cpuIntensive'){ 173 | cluster = { 174 | "name": input['name'], 175 | "masterAuth": { 176 | "clientCertificateConfig": {} 177 | }, 178 | "loggingService": "logging.googleapis.com", 179 | "monitoringService": "monitoring.googleapis.com", 180 | "network": `projects/${projectId}/global/networks/default`, 181 | "addonsConfig": { 182 | "httpLoadBalancing": {}, 183 | "horizontalPodAutoscaling": {}, 184 | "kubernetesDashboard": { 185 | "disabled": true 186 | }, 187 | "istioConfig": { 188 | "disabled": true 189 | } 190 | }, 191 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 192 | "nodePools": [ 193 | { 194 | "name": "high-cpu-pool-1", 195 | "config": { 196 | "machineType": "n1-highcpu-4", 197 | "diskSizeGb": 100, 198 | "oauthScopes": [ 199 | "https://www.googleapis.com/auth/devstorage.read_only", 200 | "https://www.googleapis.com/auth/logging.write", 201 | "https://www.googleapis.com/auth/monitoring", 202 | "https://www.googleapis.com/auth/servicecontrol", 203 | "https://www.googleapis.com/auth/service.management.readonly", 204 | "https://www.googleapis.com/auth/trace.append" 205 | ], 206 | "imageType": "COS", 207 | "diskType": "pd-standard", 208 | "shieldedInstanceConfig": {} 209 | }, 210 | "initialNodeCount": 3, 211 | "autoscaling": { 212 | "enabled": true, 213 | "minNodeCount": 1, 214 | "maxNodeCount": 5 215 | }, 216 | "management": { 217 | "autoUpgrade": true, 218 | "autoRepair": true 219 | }, 220 | "version": "1.12.8-gke.10" 221 | } 222 | ], 223 | "networkPolicy": {}, 224 | "ipAllocationPolicy": { 225 | "useIpAliases": true 226 | }, 227 | "masterAuthorizedNetworksConfig": {}, 228 | "defaultMaxPodsConstraint": { 229 | "maxPodsPerNode": "110" 230 | }, 231 | "authenticatorGroupsConfig": {}, 232 | "privateClusterConfig": {}, 233 | "databaseEncryption": { 234 | "state": "DECRYPTED" 235 | }, 236 | "initialClusterVersion": "1.12.8-gke.10", 237 | "location": input['zone'] 238 | } 239 | } 240 | 241 | if(input['clusterType'] == 'memoryIntensive'){ 242 | cluster = { 243 | "name": input['name'], 244 | "masterAuth": { 245 | "clientCertificateConfig": {} 246 | }, 247 | "loggingService": "logging.googleapis.com", 248 | "monitoringService": "monitoring.googleapis.com", 249 | "network": `projects/${projectId}/global/networks/default`, 250 | "addonsConfig": { 251 | "httpLoadBalancing": {}, 252 | "horizontalPodAutoscaling": {}, 253 | "kubernetesDashboard": { 254 | "disabled": true 255 | }, 256 | "istioConfig": { 257 | "disabled": true 258 | } 259 | }, 260 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 261 | "nodePools": [ 262 | { 263 | "name": "high-mem-pool-1", 264 | "config": { 265 | "machineType": "n1-highmem-2", 266 | "diskSizeGb": 100, 267 | "oauthScopes": [ 268 | "https://www.googleapis.com/auth/devstorage.read_only", 269 | "https://www.googleapis.com/auth/logging.write", 270 | "https://www.googleapis.com/auth/monitoring", 271 | "https://www.googleapis.com/auth/servicecontrol", 272 | "https://www.googleapis.com/auth/service.management.readonly", 273 | "https://www.googleapis.com/auth/trace.append" 274 | ], 275 | "imageType": "COS", 276 | "diskType": "pd-standard", 277 | "shieldedInstanceConfig": {} 278 | }, 279 | "initialNodeCount": 3, 280 | "autoscaling": { 281 | "enabled": true, 282 | "minNodeCount": 1, 283 | "maxNodeCount": 5 284 | }, 285 | "management": { 286 | "autoUpgrade": true, 287 | "autoRepair": true 288 | }, 289 | "version": "1.12.8-gke.10" 290 | } 291 | ], 292 | "networkPolicy": {}, 293 | "ipAllocationPolicy": { 294 | "useIpAliases": true 295 | }, 296 | "masterAuthorizedNetworksConfig": {}, 297 | "defaultMaxPodsConstraint": { 298 | "maxPodsPerNode": "110" 299 | }, 300 | "authenticatorGroupsConfig": {}, 301 | "privateClusterConfig": {}, 302 | "databaseEncryption": { 303 | "state": "DECRYPTED" 304 | }, 305 | "initialClusterVersion": "1.12.8-gke.10", 306 | "location": input['zone'] 307 | } 308 | } 309 | 310 | if(input['clusterType'] == 'gpuAcceleratedComputing'){ 311 | cluster = { 312 | "name": input['name'], 313 | "masterAuth": { 314 | "clientCertificateConfig": {} 315 | }, 316 | "loggingService": "logging.googleapis.com", 317 | "monitoringService": "monitoring.googleapis.com", 318 | "network": `projects/${projectId}/global/networks/default`, 319 | "addonsConfig": { 320 | "httpLoadBalancing": {}, 321 | "horizontalPodAutoscaling": {}, 322 | "kubernetesDashboard": { 323 | "disabled": true 324 | }, 325 | "istioConfig": { 326 | "disabled": true 327 | } 328 | }, 329 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 330 | "nodePools": [ 331 | { 332 | "name": "standard-pool-1", 333 | "config": { 334 | "machineType": "n1-standard-1", 335 | "diskSizeGb": 100, 336 | "oauthScopes": [ 337 | "https://www.googleapis.com/auth/devstorage.read_only", 338 | "https://www.googleapis.com/auth/logging.write", 339 | "https://www.googleapis.com/auth/monitoring", 340 | "https://www.googleapis.com/auth/servicecontrol", 341 | "https://www.googleapis.com/auth/service.management.readonly", 342 | "https://www.googleapis.com/auth/trace.append" 343 | ], 344 | "imageType": "COS", 345 | "diskType": "pd-standard", 346 | "shieldedInstanceConfig": {} 347 | }, 348 | "initialNodeCount": 3, 349 | "autoscaling": {}, 350 | "management": { 351 | "autoUpgrade": true, 352 | "autoRepair": true 353 | }, 354 | "version": "1.12.8-gke.10" 355 | }, 356 | { 357 | "name": "gpu-pool-1", 358 | "config": { 359 | "machineType": "n1-highmem-2", 360 | "diskSizeGb": 100, 361 | "oauthScopes": [ 362 | "https://www.googleapis.com/auth/devstorage.read_only", 363 | "https://www.googleapis.com/auth/logging.write", 364 | "https://www.googleapis.com/auth/monitoring", 365 | "https://www.googleapis.com/auth/servicecontrol", 366 | "https://www.googleapis.com/auth/service.management.readonly", 367 | "https://www.googleapis.com/auth/trace.append" 368 | ], 369 | "imageType": "COS", 370 | "accelerators": [ 371 | { 372 | "acceleratorCount": "1", 373 | "acceleratorType": "nvidia-tesla-k80" 374 | } 375 | ], 376 | "diskType": "pd-standard", 377 | "shieldedInstanceConfig": {} 378 | }, 379 | "initialNodeCount": 1, 380 | "autoscaling": {}, 381 | "management": { 382 | "autoUpgrade": true, 383 | "autoRepair": true 384 | }, 385 | "version": "1.12.8-gke.10" 386 | } 387 | ], 388 | "networkPolicy": {}, 389 | "ipAllocationPolicy": { 390 | "useIpAliases": true 391 | }, 392 | "masterAuthorizedNetworksConfig": {}, 393 | "defaultMaxPodsConstraint": { 394 | "maxPodsPerNode": "110" 395 | }, 396 | "authenticatorGroupsConfig": {}, 397 | "privateClusterConfig": {}, 398 | "databaseEncryption": { 399 | "state": "DECRYPTED" 400 | }, 401 | "initialClusterVersion": "1.12.8-gke.10", 402 | "location": input['zone'] 403 | } 404 | } 405 | 406 | if(input['clusterType'] == 'highly_available'){ 407 | cluster = { 408 | "name": input['name'], 409 | "masterAuth": { 410 | "clientCertificateConfig": {} 411 | }, 412 | "loggingService": "logging.googleapis.com", 413 | "monitoringService": "monitoring.googleapis.com", 414 | "network": `projects/${projectId}/global/networks/default`, 415 | "addonsConfig": { 416 | "httpLoadBalancing": {}, 417 | "horizontalPodAutoscaling": {}, 418 | "kubernetesDashboard": { 419 | "disabled": true 420 | }, 421 | "istioConfig": { 422 | "disabled": true 423 | } 424 | }, 425 | "subnetwork": `projects/${projectId}/regions/${input['zone'].slice(0,-2)}/subnetworks/default`, 426 | "nodePools": [ 427 | { 428 | "name": "standard-pool-1", 429 | "config": { 430 | "machineType": "n1-standard-2", 431 | "diskSizeGb": 100, 432 | "oauthScopes": [ 433 | "https://www.googleapis.com/auth/devstorage.read_only", 434 | "https://www.googleapis.com/auth/logging.write", 435 | "https://www.googleapis.com/auth/monitoring", 436 | "https://www.googleapis.com/auth/servicecontrol", 437 | "https://www.googleapis.com/auth/service.management.readonly", 438 | "https://www.googleapis.com/auth/trace.append" 439 | ], 440 | "imageType": "COS", 441 | "diskType": "pd-standard", 442 | "shieldedInstanceConfig": {} 443 | }, 444 | "initialNodeCount": 3, 445 | "autoscaling": { 446 | "enabled": true, 447 | "minNodeCount": 1, 448 | "maxNodeCount": 5 449 | }, 450 | "management": { 451 | "autoUpgrade": true, 452 | "autoRepair": true 453 | }, 454 | "version": "1.12.8-gke.10" 455 | } 456 | ], 457 | "networkPolicy": {}, 458 | "ipAllocationPolicy": { 459 | "useIpAliases": true 460 | }, 461 | "masterAuthorizedNetworksConfig": {}, 462 | "maintenancePolicy": { 463 | "window": { 464 | "dailyMaintenanceWindow": { 465 | "startTime": "10:00" 466 | } 467 | } 468 | }, 469 | "defaultMaxPodsConstraint": { 470 | "maxPodsPerNode": "110" 471 | }, 472 | "authenticatorGroupsConfig": {}, 473 | "privateClusterConfig": {}, 474 | "databaseEncryption": { 475 | "state": "DECRYPTED" 476 | }, 477 | "initialClusterVersion": "1.12.8-gke.10", 478 | "location": input['zone'] 479 | } 480 | } 481 | //--------------After knowing input configuration----------\\ 482 | const request:object = { 483 | projectId, 484 | zone, 485 | cluster 486 | } 487 | client.createCluster(request) 488 | .then(responses => { 489 | var response = responses[0]; 490 | }) 491 | .catch(err => { 492 | console.error(err); 493 | }); 494 | } 495 | 496 | export default [quickstart,create]; -------------------------------------------------------------------------------- /src/main/local/local.ts: -------------------------------------------------------------------------------- 1 | const k8s = require('@kubernetes/client-node'); 2 | const kc = new k8s.KubeConfig(); 3 | kc.loadFromDefault(); 4 | const k8sApi = kc.makeApiClient(k8s.CoreV1Api); 5 | 6 | async function fetchLocal(data={}){ 7 | await k8sApi.listNamespacedPod('default').then((res) => { 8 | 9 | 10 | const metaDat = {}; 11 | for(let meta in res.body.items[0].metadata){ 12 | if(res.body.items[0].metadata[meta]){ 13 | metaDat[meta] = res.body.items[0].metadata[meta] 14 | } 15 | } 16 | 17 | const statusDat = {}; 18 | 19 | for(let stat in res.body.items[0].status){ 20 | if(res.body.items[0].status[stat] && typeof res.body.items[0].status[stat] !== 'object'){ 21 | statusDat[stat] = res.body.items[0].status[stat] 22 | } 23 | } 24 | data["endpoint"] = statusDat["hostIP"] 25 | data["clusterName"] = res.body.items[0].metadata.clusterName||'Minikube'; 26 | data["creationTime"] = res.body.items[0].metadata.creationTimestamp; 27 | data["metaDataNameSpace"] = res.body.items[0].metadata.namespace 28 | data["nodeName"] = res.body.items[0].spec.nodeName; 29 | data["nodeCount"] = 1; 30 | data["location"] = "localhost"; 31 | 32 | for(let i = 0; i < res.body.items.length; i++){ 33 | res.body.items[i].spec.containers.forEach( 34 | (el,j)=>data[`NodePool_${j}`] = {'podName':res.body.items[i].metadata.name,'image':el.image, 'containerName':el.name}) 35 | } 36 | 37 | }) 38 | let res = []; 39 | res.push(data) 40 | return res; 41 | } 42 | 43 | export default fetchLocal; 44 | -------------------------------------------------------------------------------- /src/main/main.ts: -------------------------------------------------------------------------------- 1 | const fetchLocal = require('./local/local').default 2 | const [fetchGCP, create] = require('./gcp/getGCPdata').default; 3 | // const fetchAws = require('./aws/getAWSData').default 4 | const { app, ipcMain, BrowserWindow } = require('electron'); 5 | // const electron = require('electron') 6 | // require('events').EventEmitter.defaultMaxListeners = 15; 7 | 8 | let dat = new Date() 9 | async function getLocal() { 10 | const res = await fetchLocal(); 11 | console.log('getting fetch Local at -------' , ' ', dat.getTime()) 12 | return res 13 | } 14 | 15 | async function getGcp(GOOGLE_APPLICATION_CREDENTIALS) { 16 | const res = await fetchGCP(GOOGLE_APPLICATION_CREDENTIALS); 17 | let dat = new Date() 18 | console.log('fetchGetgcp -------' , ' ', dat.getTime()) 19 | return res; 20 | } 21 | 22 | ipcMain.on('asynchronous-message', (event: any, arg: any) => { 23 | getLocal().then(res=>{ 24 | event.sender.send('clusterClient', res) 25 | }).catch((e)=>console.log(e)) 26 | getGcp(arg).then(res=>{ 27 | event.sender.send('clusterClient', res) 28 | }) 29 | .catch((e)=>console.log(e)) 30 | }) 31 | // 32 | // ipcMain.on('asynchronous-message2', (event: any, arg: any) => { 33 | // fetchAws(arg).then(res=>{ 34 | // event.sender.send('clusterClient2', res) 35 | // console.log('res in aws: ', res) 36 | // }) 37 | // .catch((e)=>console.log(e)) 38 | // }) 39 | app.on('ready', () => { 40 | // This creates a window on startup 41 | const window = new BrowserWindow({ 42 | webPreferences: { 43 | nodeIntegration: true // allow node integration on BrowserWindow 44 | }, 45 | }); 46 | window.maximize(); 47 | window.show(); 48 | 49 | 50 | // This loads the html page we bundled with webpack to display 51 | window.loadURL(`file://${__dirname}/index.html`); 52 | }); 53 | -------------------------------------------------------------------------------- /store.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext } from 'react'; 2 | 3 | export const StoreContext = createContext(null); 4 | 5 | export const StoreContextProvider = (props: any) => { 6 | 7 | const [Store, setStore] = useState({ 8 | landingPageState: false, 9 | uploadPageState: false, 10 | uploadPageState2:false, 11 | gcpDeployPage:false, 12 | credentials: {}, //google 13 | clusters: null, 14 | gcploc:null, 15 | clusterCount:0, 16 | awsKey:null, 17 | awsSecret:null, 18 | awsClusterName:null, 19 | awsLocation:null 20 | }) 21 | 22 | return ( 23 | 24 | {props.children} 25 | 26 | ) 27 | } 28 | 29 | export default StoreContext; 30 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .app { 2 | height: 100vh; 3 | background-color: rgb(0, 0, 0); 4 | } 5 | 6 | .text { 7 | color: aqua; 8 | margin-top: 20px; 9 | margin-left: 290px; 10 | font-size: 20px; 11 | } 12 | 13 | .displayContainer { 14 | color: aquamarine; 15 | } 16 | 17 | .kubLogo { 18 | transform: rotate(360deg); 19 | height: 300px; 20 | width: 300px; 21 | margin-top: 25px; 22 | margin-left: 240px; 23 | color: rgb(254, 254, 255); 24 | animation: rotation 2.5s infinite linear; 25 | } 26 | 27 | 28 | .logo { 29 | transform: rotate(360deg); 30 | height: 100px; 31 | width: 100px; 32 | margin-top: 35px; 33 | margin-left: 92px; 34 | background-color: oldlace; 35 | border: solid 5px black; 36 | border-radius: 20px; 37 | /* animation: rotation 4s infinite linear; */ 38 | } 39 | 40 | .logo1 { 41 | transform: rotate(360deg); 42 | height: 100px; 43 | width: 100px; 44 | margin-top: 35px; 45 | margin-left: 130px; 46 | border: solid 10px black; 47 | border-radius: 20px; 48 | /* animation: rotation 4s infinite linear; */ 49 | } 50 | 51 | .logo2 { 52 | transform: rotate(360deg); 53 | height: 100px; 54 | width: 100px; 55 | margin-top: 35px; 56 | margin-left: 130px; 57 | /* animation: rotation 4s infinite linear; */ 58 | background-color: red; 59 | border: solid 5px black; 60 | border-radius: 20px; 61 | } 62 | 63 | @keyframes rotation { 64 | from { 65 | transform: rotate(0deg); 66 | } 67 | to { 68 | transform: rotate(359deg); 69 | } 70 | } 71 | 72 | .uploadInput { 73 | height: 70px; 74 | width: 250px; 75 | border: dodgerblue solid 5px; 76 | border-radius: 5px; 77 | color: black; 78 | background-color: rgb(255, 255, 255); 79 | margin-left: 250px; 80 | margin-top: 30px; 81 | font-size: 30px; 82 | font-family: sans-serif; 83 | } 84 | 85 | .uploadButt { 86 | height: 50px; 87 | width: 75px; 88 | border: dodgerblue solid 5px; 89 | border-radius: 5px; 90 | margin-top: 30px; 91 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 92 | font-weight: bold; 93 | font-size: 15px; 94 | background-color: rgb(255, 255, 255); 95 | } 96 | 97 | .uploadDiv { 98 | height: 100vh; 99 | } 100 | 101 | .kubUpload { 102 | transform: rotate(360deg); 103 | height: 100px; 104 | width: 100px; 105 | margin-top: 60px; 106 | margin-left: 325px; 107 | color: rgb(254, 254, 255); 108 | animation: rotation 1s infinite linear; 109 | } 110 | 111 | .kubUploadText { 112 | height: 100px; 113 | width: 200px; 114 | margin-top: 15px; 115 | color: aquamarine; 116 | margin-left: 285px; 117 | } 118 | 119 | #info { 120 | position: absolute; 121 | top: 10px; 122 | width: 100%; 123 | text-align: center; 124 | z-index: 100; 125 | display:block; 126 | } 127 | 128 | #tool-tip { 129 | display: none; 130 | position: absolute; 131 | pointer-events: none; 132 | font-size: 14px; 133 | width: 250px; 134 | color: black; 135 | text-align: center; 136 | line-height: 1; 137 | padding: 6px; 138 | background: white; 139 | font-family: sans-serif; 140 | } 141 | 142 | #point-tip { 143 | padding: 4px; 144 | margin-bottom: 4px; 145 | } 146 | 147 | #group-tip { 148 | padding: 4px; 149 | height: 135px; 150 | font-size: 16px; 151 | font-weight: 400; 152 | color: black; 153 | } 154 | 155 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "types": ["node"], 5 | "sourceMap": true, 6 | "noImplicitAny": false, 7 | "noImplicitThis": true, 8 | "module": "commonjs", 9 | "target": "es6", 10 | "jsx": "react", 11 | "lib": ["es6", "dom", "es2017", "esnext"], 12 | "allowSyntheticDefaultImports": true, 13 | "esModuleInterop": true, 14 | "moduleResolution": "node", 15 | "baseUrl": "./src", 16 | }, 17 | "include": [ 18 | "./src/**/*", "src/Ambient-Types/External Modules/@deck.gl" 19 | ], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended","ts-lint-react","tslint-config-prettier"], 3 | "tslint.autoFixOnSave": true, 4 | "linterOptions": { 5 | 6 | }, 7 | "rules": { 8 | "jsx-boolean-value": false, 9 | "ordered-imports": false, 10 | "comment-format": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const CopyPkgJsonPlugin = require('copy-pkg-json-webpack-plugin'); 4 | const lodash = require('lodash'); 5 | 6 | function srcPaths(src) { 7 | return path.join(__dirname, src); 8 | } 9 | 10 | 11 | const isEnvProduction = process.env.NODE_ENV === 'production'; 12 | const isEnvDevelopment = process.env.NODE_ENV === 'development'; 13 | 14 | const commonConfig = { 15 | devtool: isEnvDevelopment ? 'source-map' : false, 16 | mode: isEnvProduction ? 'production' : 'development', 17 | externals: { 18 | '@google-cloud/container': 'commonjs @google-cloud/container' 19 | }, 20 | output: { path: srcPaths('dist') }, 21 | node: { __dirname: false, __filename: false }, 22 | // plugins: [ 23 | // new ElectronConnectWebpackPlugin({ 24 | // path: path.join(__dirname, 'dist'), 25 | // logLevel: 0, 26 | // }), 27 | // ], 28 | resolve: { 29 | extensions: ['.js', '.json', '.ts', '.tsx'], 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.(ts|tsx)$/, 35 | exclude: /node_modules/, 36 | loader: 'babel-loader', 37 | }, 38 | { 39 | test: /\.(scss|css)$/, 40 | use: ['style-loader', 'css-loader'], 41 | }, 42 | { 43 | test: /\.(jpg|png|svg|ico|icns)$/, 44 | loader: 'url-loader?limit=8192', 45 | options: { 46 | name: '[path][name].[ext]', 47 | }, 48 | }, 49 | ], 50 | }, 51 | watch: false 52 | }; 53 | // #endregion 54 | 55 | const mainConfig = lodash.cloneDeep(commonConfig); 56 | mainConfig.entry = ['babel-polyfill','./src/main/main.ts']; 57 | mainConfig.target = 'electron-main'; 58 | mainConfig.output.filename = 'main.bundle.js'; 59 | mainConfig.plugins = [ 60 | new CopyPkgJsonPlugin({ 61 | remove: ['scripts', 'devDependencies', 'build'], 62 | replace: { 63 | main: './main.bundle.js', 64 | scripts: { start: 'electron ./main.bundle.js' }, 65 | postinstall: 'electron-builder install-app-deps', 66 | }, 67 | }), 68 | // MainElectronReloadWebpackPlugin(), 69 | ]; 70 | 71 | const rendererConfig = lodash.cloneDeep(commonConfig); 72 | rendererConfig.entry = ['babel-polyfill','./src/client/renderer.tsx']; 73 | rendererConfig.target = 'electron-renderer'; 74 | rendererConfig.output.filename = 'renderer.bundle.js'; 75 | rendererConfig.plugins = [ 76 | new HtmlWebpackPlugin({ 77 | template: path.resolve(__dirname, './src/client/index.html'), 78 | }), 79 | ]; 80 | 81 | module.exports = [mainConfig, rendererConfig]; 82 | --------------------------------------------------------------------------------