From a68e5ae4f26a20f8d55339c1a1a57565040f2710 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 4 Nov 2023 15:18:28 -0300
Subject: [PATCH 01/16] remove infra from client, no more git credential and
git repository table
---
client/src/app_infra/Layout.js | 48 ---
client/src/app_infra/LayoutUnauthenticated.js | 31 --
client/src/app_infra/UserApp.js | 17 --
client/src/app_infra/footer.js | 118 --------
client/src/app_infra/index.js | 2 -
client/src/app_infra/infra/SelectRegion.js | 27 --
client/src/app_infra/infra/assets/aws.svg | 5 -
client/src/app_infra/infra/assets/azure.svg | 3 -
client/src/app_infra/infra/assets/gc.svg | 3 -
client/src/app_infra/infra/assets/gcp.svg | 7 -
client/src/app_infra/infra/assets/k8s.svg | 5 -
client/src/app_infra/infra/assets/ovh.svg | 1 -
.../src/app_infra/infra/assets/uploadIcon.svg | 47 ---
client/src/app_infra/infra/awsConfig.js | 192 ------------
client/src/app_infra/infra/azureConfig.js | 192 ------------
client/src/app_infra/infra/badgeRegion.js | 24 --
client/src/app_infra/infra/gcpConfig.js | 273 ------------------
.../app_infra/infra/gitCredentialConfig.js | 249 ----------------
.../app_infra/infra/gitRepositoryConfig.js | 233 ---------------
.../src/app_infra/infra/importProjectForm.js | 216 --------------
client/src/app_infra/infra/index.js | 2 -
client/src/app_infra/infra/infraDelete.js | 76 -----
client/src/app_infra/infra/infraDeleteLink.js | 33 ---
client/src/app_infra/infra/infraDetail.js | 185 ------------
client/src/app_infra/infra/infraList.js | 185 ------------
client/src/app_infra/infra/infraModule.js | 110 -------
client/src/app_infra/infra/infraRoutes.js | 139 ---------
client/src/app_infra/infra/infraSettings.js | 178 ------------
client/src/app_infra/infra/ovhConfig.js | 226 ---------------
client/src/app_infra/infra/ovhSelectRegion.js | 40 ---
client/src/app_infra/infra/projectList.js | 76 -----
.../app_infra/infra/providerConfigCommon.js | 108 -------
client/src/app_infra/infra/providerLogo.js | 37 ---
.../src/app_infra/infra/providerSelection.js | 90 ------
client/src/app_infra/infra/providerStore.js | 169 -----------
client/src/app_infra/infra/resourceTable.js | 40 ---
client/src/app_infra/infra/rulesForm.js | 23 --
client/src/app_infra/infra/wizardCreate.js | 252 ----------------
client/src/app_infra/menuItems.ts | 21 --
.../profile/components/profileForm.js | 115 --------
client/src/app_infra/profile/profileModule.js | 134 ---------
.../src/app_infra/profile/userDeleteView.js | 68 -----
.../app_infra/profile/views/profileView.js | 16 -
client/src/app_infra/routes.js | 44 ---
client/src/app_infra/test/app.spec.js | 13 -
client/src/app_infra/test/router.spec.js | 24 --
client/src/app_public/landing/content.js | 51 +---
client/webpack.config.js | 8 -
client/webpack.dev.js | 1 -
client/webpack.prod.js | 1 -
.../cloudDiagram/api/gitCredentialApi.js | 135 ---------
.../cloudDiagram/api/gitRepositoryApi.js | 128 --------
.../src/plugins/cloudDiagram/api/infraApi.js | 260 ++++++++---------
.../cloudDiagram/api/infraPushCodeApi.js | 162 +++++------
.../plugins/cloudDiagram/api/projectApi.js | 20 +-
server/src/plugins/cloudDiagram/index.js | 6 -
.../cloudDiagram/migrations/010.do.app.do.sql | 37 +--
.../migrations/011.do.app-seed.sql | 36 ---
.../cloudDiagram/sql/GitCredentialSql.js | 18 --
.../cloudDiagram/sql/GitRepositorySql.js | 15 -
.../cloudDiagram/test/testGitCredential.js | 111 -------
.../cloudDiagram/test/testGitRepository.js | 117 --------
62 files changed, 246 insertions(+), 4957 deletions(-)
delete mode 100644 client/src/app_infra/Layout.js
delete mode 100644 client/src/app_infra/LayoutUnauthenticated.js
delete mode 100644 client/src/app_infra/UserApp.js
delete mode 100644 client/src/app_infra/footer.js
delete mode 100644 client/src/app_infra/index.js
delete mode 100644 client/src/app_infra/infra/SelectRegion.js
delete mode 100644 client/src/app_infra/infra/assets/aws.svg
delete mode 100644 client/src/app_infra/infra/assets/azure.svg
delete mode 100644 client/src/app_infra/infra/assets/gc.svg
delete mode 100644 client/src/app_infra/infra/assets/gcp.svg
delete mode 100644 client/src/app_infra/infra/assets/k8s.svg
delete mode 100644 client/src/app_infra/infra/assets/ovh.svg
delete mode 100644 client/src/app_infra/infra/assets/uploadIcon.svg
delete mode 100644 client/src/app_infra/infra/awsConfig.js
delete mode 100644 client/src/app_infra/infra/azureConfig.js
delete mode 100644 client/src/app_infra/infra/badgeRegion.js
delete mode 100644 client/src/app_infra/infra/gcpConfig.js
delete mode 100644 client/src/app_infra/infra/gitCredentialConfig.js
delete mode 100644 client/src/app_infra/infra/gitRepositoryConfig.js
delete mode 100644 client/src/app_infra/infra/importProjectForm.js
delete mode 100644 client/src/app_infra/infra/index.js
delete mode 100644 client/src/app_infra/infra/infraDelete.js
delete mode 100644 client/src/app_infra/infra/infraDeleteLink.js
delete mode 100644 client/src/app_infra/infra/infraDetail.js
delete mode 100644 client/src/app_infra/infra/infraList.js
delete mode 100644 client/src/app_infra/infra/infraModule.js
delete mode 100644 client/src/app_infra/infra/infraRoutes.js
delete mode 100644 client/src/app_infra/infra/infraSettings.js
delete mode 100644 client/src/app_infra/infra/ovhConfig.js
delete mode 100644 client/src/app_infra/infra/ovhSelectRegion.js
delete mode 100644 client/src/app_infra/infra/projectList.js
delete mode 100644 client/src/app_infra/infra/providerConfigCommon.js
delete mode 100644 client/src/app_infra/infra/providerLogo.js
delete mode 100644 client/src/app_infra/infra/providerSelection.js
delete mode 100644 client/src/app_infra/infra/providerStore.js
delete mode 100644 client/src/app_infra/infra/resourceTable.js
delete mode 100644 client/src/app_infra/infra/rulesForm.js
delete mode 100644 client/src/app_infra/infra/wizardCreate.js
delete mode 100644 client/src/app_infra/menuItems.ts
delete mode 100644 client/src/app_infra/profile/components/profileForm.js
delete mode 100644 client/src/app_infra/profile/profileModule.js
delete mode 100644 client/src/app_infra/profile/userDeleteView.js
delete mode 100644 client/src/app_infra/profile/views/profileView.js
delete mode 100644 client/src/app_infra/routes.js
delete mode 100644 client/src/app_infra/test/app.spec.js
delete mode 100644 client/src/app_infra/test/router.spec.js
delete mode 100644 server/src/plugins/cloudDiagram/api/gitCredentialApi.js
delete mode 100644 server/src/plugins/cloudDiagram/api/gitRepositoryApi.js
delete mode 100644 server/src/plugins/cloudDiagram/sql/GitCredentialSql.js
delete mode 100644 server/src/plugins/cloudDiagram/sql/GitRepositorySql.js
delete mode 100644 server/src/plugins/cloudDiagram/test/testGitCredential.js
delete mode 100644 server/src/plugins/cloudDiagram/test/testGitRepository.js
diff --git a/client/src/app_infra/Layout.js b/client/src/app_infra/Layout.js
deleted file mode 100644
index f319aed9..00000000
--- a/client/src/app_infra/Layout.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React, { createElement as h } from "react";
-import { observer } from "mobx-react";
-import footer from "./footer";
-import MainView from "components/MainView";
-import navBar from "components/navbar";
-import userInfo from "components/UserInfo";
-
-import APP_MENU from "./menuItems";
-
-export default (context) => {
- const {
- alertStack: { View: AlertStack },
- } = context;
-
- const NavBar = navBar(context);
- const Footer = footer(context);
- const UserInfo = userInfo(context);
-
- const Layout = ({ children }) => (
-
- );
-
- return ({ children }) =>
- h(observer(Layout), {
- children,
- });
-};
diff --git a/client/src/app_infra/LayoutUnauthenticated.js b/client/src/app_infra/LayoutUnauthenticated.js
deleted file mode 100644
index f2b84d4e..00000000
--- a/client/src/app_infra/LayoutUnauthenticated.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { createElement as h } from "react";
-import { observer } from "mobx-react";
-import navBar from "components/navbar";
-import footer from "./footer";
-import RootView from "components/RootView";
-import MainView from "components/MainView";
-import authBar from "components/authBar";
-
-export default (context) => {
- const {
- alertStack: { View: AlertStack },
- } = context;
-
- const NavBar = navBar(context);
- const Footer = footer(context);
- const AuthBar = authBar(context);
-
- const Layout = ({ children }) => (
-
-
- {children}
-
-
-
- );
-
- return ({ children }) =>
- h(observer(Layout), {
- children,
- });
-};
diff --git a/client/src/app_infra/UserApp.js b/client/src/app_infra/UserApp.js
deleted file mode 100644
index a2f5ff87..00000000
--- a/client/src/app_infra/UserApp.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Context from "../context";
-import App from "../app";
-import layout from "./Layout";
-import createRoutes from "./routes";
-
-export default async () => {
- const context = await Context({
- config: {
- loginPath: "/auth/login",
- routeAfterLogin: "/infra",
- defaultPath: "/infra",
- title: "GruCloud",
- },
- });
-
- return App({ context, routes: createRoutes({ context }), layout });
-};
diff --git a/client/src/app_infra/footer.js b/client/src/app_infra/footer.js
deleted file mode 100644
index ae1a323d..00000000
--- a/client/src/app_infra/footer.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { useEffect } from "react";
-import { jsx, css } from "@emotion/react";
-import { observer } from "mobx-react";
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-
-import { RiTwitterFill, RiBugFill, RiMailSendLine } from "react-icons/ri";
-
-export default (context) => {
- const {
- tr,
- theme: { palette, shadows },
- rest,
- } = context;
- const versionStore = AsyncOp(context)(() => rest.get(`version`));
- const style = { color: palette.grey[500], fontSize: "0.8em" };
-
- const Footer = observer(() => {
- useEffect(() => {
- versionStore.fetch();
- }, []);
-
- return (
-
- );
- });
- return Footer;
-};
diff --git a/client/src/app_infra/index.js b/client/src/app_infra/index.js
deleted file mode 100644
index 79ba327e..00000000
--- a/client/src/app_infra/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import App from "./UserApp";
-App().catch(error => console.error(error));
diff --git a/client/src/app_infra/infra/SelectRegion.js b/client/src/app_infra/infra/SelectRegion.js
deleted file mode 100644
index 9cae6ecc..00000000
--- a/client/src/app_infra/infra/SelectRegion.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { jsx, css } from "@emotion/react";
-import select from "mdlean/lib/select";
-
-export default (context, { items } = {}) => {
- const Item = ({ item }) => (
-
- {item}
-
- );
-
- const SelectRegion = select(context, {
- items,
- renderItems: Item,
- cssOveride: css`
- width: 200px;
- `,
- });
-
- return SelectRegion;
-};
diff --git a/client/src/app_infra/infra/assets/aws.svg b/client/src/app_infra/infra/assets/aws.svg
deleted file mode 100644
index 37e1a909..00000000
--- a/client/src/app_infra/infra/assets/aws.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/client/src/app_infra/infra/assets/azure.svg b/client/src/app_infra/infra/assets/azure.svg
deleted file mode 100644
index 2193a2c6..00000000
--- a/client/src/app_infra/infra/assets/azure.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/client/src/app_infra/infra/assets/gc.svg b/client/src/app_infra/infra/assets/gc.svg
deleted file mode 100644
index ef26f65a..00000000
--- a/client/src/app_infra/infra/assets/gc.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/client/src/app_infra/infra/assets/gcp.svg b/client/src/app_infra/infra/assets/gcp.svg
deleted file mode 100644
index 92e4ddca..00000000
--- a/client/src/app_infra/infra/assets/gcp.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/client/src/app_infra/infra/assets/k8s.svg b/client/src/app_infra/infra/assets/k8s.svg
deleted file mode 100644
index 1a3e9034..00000000
--- a/client/src/app_infra/infra/assets/k8s.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/client/src/app_infra/infra/assets/ovh.svg b/client/src/app_infra/infra/assets/ovh.svg
deleted file mode 100644
index 67370c91..00000000
--- a/client/src/app_infra/infra/assets/ovh.svg
+++ /dev/null
@@ -1 +0,0 @@
-OVHcloud_master_logo_fullcolor_RGB
\ No newline at end of file
diff --git a/client/src/app_infra/infra/assets/uploadIcon.svg b/client/src/app_infra/infra/assets/uploadIcon.svg
deleted file mode 100644
index b37b77e8..00000000
--- a/client/src/app_infra/infra/assets/uploadIcon.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/src/app_infra/infra/awsConfig.js b/client/src/app_infra/infra/awsConfig.js
deleted file mode 100644
index 4c06184c..00000000
--- a/client/src/app_infra/infra/awsConfig.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe } from "rubico";
-import { isEmpty } from "rubico/x";
-
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-
-import { providerCreateStore } from "./providerStore";
-import {
- providerFormCreate,
- providerFormUpdate,
- providerConfigCreateFooter,
- providerConfigUpdateFooter,
-} from "./providerConfigCommon";
-
-const AWS_REGION = [
- "eu-north-1",
- "ap-south-1",
- "eu-west-3",
- "eu-west-2",
- "eu-west-1",
- "ap-northeast-3",
- "ap-northeast-2",
- "ap-northeast-1",
- "sa-east-1",
- "ca-central-1",
- "ap-southeast-1",
- "ap-southeast-2",
- "eu-central-1",
- "us-east-1",
- "us-east-2",
- "us-west-1",
- "us-west-2",
-];
-
-import selectRegion from "./SelectRegion";
-
-const rules = {
- AWSAccessKeyId: {
- presence: true,
- length: {
- minimum: 20,
- message: "must be at least 20 characters",
- },
- },
- AWSSecretKey: {
- presence: true,
- length: {
- minimum: 40,
- message: "must be at least 40 characters",
- },
- },
-};
-
-const defaultData = {
- id: "",
- AWSAccessKeyId: "",
- AWSSecretKey: "",
- AWS_REGION: "us-east-1",
-};
-
-export const createStoreAws = (
- context,
- {
- infraSettingsStore,
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- }
-) => {
- const core = providerCreateStore({
- context,
- defaultData,
- rules,
- infraSettingsStore,
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- });
- const store = observable({
- get isDisabled() {
- return or([
- pipe([get("AWSAccessKeyId"), isEmpty]),
- pipe([get("AWSSecretKey"), isEmpty]),
- ])(core.data);
- },
- buildPayload: ({ data }) => ({
- providerType: "aws",
- providerName: "aws",
- providerAuth: {
- AWSAccessKeyId: data.AWSAccessKeyId.trim(),
- AWSSecretKey: data.AWSSecretKey,
- AWS_REGION: data.AWS_REGION,
- },
- }),
- core,
- });
- return store;
-};
-
-export const awsConfigForm = (context) => {
- const { tr } = context;
- const FormGroup = formGroup(context);
- const AwsSelectRegion = selectRegion(context, { items: AWS_REGION });
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 300px;
- }
- `,
- });
-
- return observer(({ store }) => (
- <>
-
- store.onChange("AWSAccessKeyId", event)}
- autoComplete="off"
- label={tr.t("AWS Access Key Id")}
- error={get("AWSAccessKeyId[0]")(store.errors)}
- />
-
-
- store.onChange("AWSSecretKey", event)}
- label={tr.t("AWS Secret Key")}
- type="password"
- error={get("AWSSecretKey[0]")(store.errors)}
- />
-
-
- {
- store.data.AWS_REGION = region;
- }}
- />
-
- >
- ));
-};
-
-export const awsFormCreate = (context) => {
- const { tr } = context;
- const FormCreate = providerFormCreate(context);
- const Footer = providerConfigCreateFooter(context);
- const AwsConfigForm = awsConfigForm(context);
-
- return observer(({ store }) => (
-
-
- {tr.t("Create new AWS Infrastructure")}
-
-
-
- {tr.t(
- "Please provide the following information to create and scan a new infrastructure"
- )}
-
-
-
-
-
- ));
-};
-
-export const awsFormEdit = (context) => {
- const { tr } = context;
- const FormUpdate = providerFormUpdate(context);
- const AwsConfigForm = awsConfigForm(context);
- const Footer = providerConfigUpdateFooter(context);
-
- return observer(({ store, infraSettingsStore }) => (
-
-
- {tr.t("Update AWS Infrastructure")}
-
-
-
-
-
-
- ));
-};
diff --git a/client/src/app_infra/infra/azureConfig.js b/client/src/app_infra/infra/azureConfig.js
deleted file mode 100644
index 66090845..00000000
--- a/client/src/app_infra/infra/azureConfig.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { pipe, get, or, tap } from "rubico";
-import { isEmpty } from "rubico/x";
-
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-
-import { providerCreateStore } from "./providerStore";
-import {
- providerFormCreate,
- providerFormUpdate,
- providerConfigCreateFooter,
- providerConfigUpdateFooter,
-} from "./providerConfigCommon";
-
-export const createStoreAzure = (
- context,
- { infraSettingsStore, gitCredentialStore, gitRepositoryStore }
-) => {
- const core = providerCreateStore({
- context,
- defaultData: {},
- rules: {},
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
- });
-
- const store = observable({
- buildPayload: ({ data }) => ({
- providerType: "azure",
- providerName: "azure",
- providerAuth: data,
- }),
- get isDisabled() {
- return or([
- pipe([get("AZURE_SUBSCRIPTION_ID"), isEmpty]),
- pipe([get("AZURE_TENANT_ID"), isEmpty]),
- pipe([get("APP_ID"), isEmpty]),
- pipe([get("PASSWORD"), isEmpty]),
- ])(core.data);
- },
- core,
- });
- return store;
-};
-
-export const azureFormContent = (context) => {
- const {
- tr,
- theme: { palette },
- } = context;
- const FormGroup = formGroup(context);
- const Input = input(context, {
- cssOverride: css`
- input {
- width: 25rem;
- }
- `,
- });
- return observer(({ store }) => (
-
-
- Please follow the instructions to setup a service principal used by
- Grucloud to scan an Azure infrastructure.
-
- li {
- counter-increment: counter;
- margin: 0 0 0.5rem 0;
- position: relative;
- ::before {
- background-color: ${palette.primary.main};
- color: ${palette.primary.contrastText};
- content: counter(counter) ".";
- font-weight: bold;
- position: absolute;
- --size: 32px;
- left: calc(-1 * var(--size) - 10px);
- line-height: var(--size);
- width: var(--size);
- height: var(--size);
- top: -0.3rem;
- border-radius: 50%;
- text-align: center;
- }
- }
- `}
- >
-
- Subscription ID
-
- Retrieve the Subscription ID with the following command:{" "}
-
- az account show --query id -otsv
- store.onChange("AZURE_SUBSCRIPTION_ID", event)}
- label={tr.t("Subscription Id")}
- error={
- store.errors.AZURE_SUBSCRIPTION_ID &&
- store.errors.AZURE_SUBSCRIPTION_ID[0]
- }
- />
-
-
- Tenant ID
-
- Retrieve the AZURE_TENANT_ID with the following command:{" "}
-
- az account show
- store.onChange("AZURE_TENANT_ID", e)}
- label={tr.t("Tenant Id")}
- error={
- store.errors.AZURE_TENANT_ID && store.errors.AZURE_TENANT_ID[0]
- }
- />
-
-
- App ID and PASSWORD
-
- Retrieve the APP_ID and PASSWORD by creating a
- service principal called grucloud:
-
- az ad sp create-for-rbac -n "grucloud"
-
- store.onChange("APP_ID", e)}
- label={tr.t("App Id")}
- error={store.errors.APP_ID && store.errors.APP_ID[0]}
- />
-
-
- store.onChange("PASSWORD", e)}
- label={tr.t("Password")}
- error={store.errors.PASSWORD && store.errors.PASSWORD[0]}
- />
-
-
-
-
- ));
-};
-
-export const azureFormCreate = (context) => {
- const { tr } = context;
- const FormCreate = providerFormCreate(context);
- const Content = azureFormContent(context);
- const Footer = providerConfigCreateFooter(context);
-
- return observer(({ store }) => (
-
-
-
-
- ));
-};
-
-export const azureFormEdit = (context) => {
- const { tr } = context;
- const FormUpdate = providerFormUpdate(context);
-
- const Content = azureFormContent(context);
- const Footer = providerConfigUpdateFooter(context);
-
- return observer(({ store, infraSettingsStore }) => (
-
-
- {tr.t("Update Azure Infrastructure")}
-
-
-
-
- ));
-};
diff --git a/client/src/app_infra/infra/badgeRegion.js b/client/src/app_infra/infra/badgeRegion.js
deleted file mode 100644
index 8262da30..00000000
--- a/client/src/app_infra/infra/badgeRegion.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-
-const badgeRegion =
- ({ theme: { palette } }) =>
- ({ region }) =>
- (
-
- {region}
-
- );
-
-export default badgeRegion;
diff --git a/client/src/app_infra/infra/gcpConfig.js b/client/src/app_infra/infra/gcpConfig.js
deleted file mode 100644
index b152f5b8..00000000
--- a/client/src/app_infra/infra/gcpConfig.js
+++ /dev/null
@@ -1,273 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-
-import input from "mdlean/lib/input";
-
-import fileInput from "mdlean/lib/fileInput";
-import formGroup from "mdlean/lib/formGroup";
-
-import IconUpload from "./assets/uploadIcon.svg";
-
-import { providerCreateStore } from "./providerStore";
-import {
- providerFormCreate,
- providerFormUpdate,
- providerConfigCreateFooter,
- providerConfigUpdateFooter,
-} from "./providerConfigCommon";
-
-export const createStoreGoogle = (
- context,
- { infraSettingsStore, gitCredentialStore, gitRepositoryStore }
-) => {
- const core = providerCreateStore({
- context,
- defaultData: {},
- rules: {},
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
- });
-
- const store = observable({
- fileName: "",
- content: {},
- buildPayload: () => ({
- providerType: "google",
- providerName: "google",
- providerAuth: { credentials: store.content },
- }),
- get isDisabled() {
- return !store.content.project_id;
- },
- onChangeFile: (event) => {
- const file = event.target.files[0];
- if (file) {
- store.fileName = file.name;
- const reader = new FileReader();
- reader.readAsText(file);
- reader.onload = () => {
- try {
- store.content = JSON.parse(reader.result);
- } catch (error) {
- //TODO display error
- store.error = "Error parsing file";
- }
- };
-
- reader.onerror = () => {
- //TODO display error
- console.log(reader.error);
- };
- } else {
- //TODO
- store.input = "";
- }
- },
- core,
- });
-
- return store;
-};
-
-const credentialFile =
- ({ theme: { palette } }) =>
- ({ fileName, content }) =>
- (
-
-
-
- Credential File
- {fileName}
-
-
- Project Name
- {content.project_id}
-
-
- Service Account
- {content.client_email}
-
-
-
- );
-
-const fileInputLabel =
- ({ tr, theme: { palette } }) =>
- ({}) =>
- (
- * {
- margin: 1rem;
- }
- svg {
- height: 2rem;
- path {
- fill: ${palette.text.primary};
- }
- }
- `,
- ]}
- >
-
-
{tr.t("Choose a credential file to upload")}
-
- );
-
-export const gcpFormCreate = (context) => {
- const { tr } = context;
- const FormCreate = providerFormCreate(context);
-
- const FileInput = fileInput(context);
- const CredentialFile = credentialFile(context);
- const FileInputLabel = fileInputLabel(context);
- const Footer = providerConfigCreateFooter(context);
-
- return observer(({ store }) => (
-
-
-
- GruCloud requires a read-only service account to scan a project's
- architecture. Please select the service account credential JSON file
- for the project that will be scanned. Follow the following steps to
- create and upload this file.
-
- li {
- padding: 0.3rem 0;
- }
- `}
- >
-
- Visit the
-
- service account page
- {" "}
- on the google cloud console
-
- Select your project
-
- Click on CREATE SERVICE ACCOUNT
-
-
- Set the Service account name to 'grucloud' for instance
-
-
- Click on CREATE
-
- Select the basic role 'Viewer'
-
- Click on CONTINUE
-
-
- Click on DONE
-
-
- Go to the Actions column, click on the three dot icon of
- the newly created service account
-
-
- Click on Manage keys
-
-
- Click on ADD KEYS , then Create new key
-
-
- Click on CREATE to download the credential file in JSON
- format.
-
-
- }
- name="file"
- accept="application/JSON"
- onChange={(evt) => store.onChangeFile(evt)}
- />
-
- {!store.isDisabled && (
-
- )}
-
-
-
- ));
-};
-
-export const gcpFormEdit = (context) => {
- const { tr } = context;
- const FormUpdate = providerFormUpdate(context);
- const FormGroup = formGroup(context);
- const FileInput = fileInput(context);
- const Input = input(context, {
- cssOverride: css`
- input {
- width: 25rem;
- }
- `,
- });
- const CredentialFile = credentialFile(context);
- const FileInputLabel = fileInputLabel(context);
- const Footer = providerConfigUpdateFooter(context);
-
- return observer(({ store, infraSettingsStore }) => (
-
-
- {tr.t("Update GCP Infrastructure")}
-
-
-
-
-
- }
- name="file"
- accept="application/JSON"
- onChange={(evt) => store.onChangeFile(evt)}
- />
-
- {!store.isDisabled && (
-
- )}
-
-
-
- ));
-};
diff --git a/client/src/app_infra/infra/gitCredentialConfig.js b/client/src/app_infra/infra/gitCredentialConfig.js
deleted file mode 100644
index 96dc2557..00000000
--- a/client/src/app_infra/infra/gitCredentialConfig.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe, tap, switchCase, tryCatch } from "rubico";
-import { isEmpty, size, first, defaultsDeep } from "rubico/x";
-import validate from "validate.js";
-
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import button from "mdlean/lib/button";
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-import spinner from "mdlean/lib/spinner";
-import { buttonWizardBack, buttonHistoryBack } from "./wizardCreate";
-import form from "components/form";
-
-const rules = {
- username: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- password: {
- presence: true,
- length: {
- minimum: 6,
- message: "must be at least 6 characters",
- },
- },
-};
-
-export const gitCredentialCreateStore = ({ context, infraSettingsStore }) => {
- const { tr, history, alertStack, rest, emitter } = context;
- const asyncOpCreate = AsyncOp(context);
-
- const defaultData = {
- username: "",
- password: "",
- };
-
- const store = observable({
- id: undefined,
- data: defaultData,
- errors: {},
- setErrors: action((errors) => {
- store.errors = errors;
- }),
- setData: action((data = {}) => {
- store.data = defaultsDeep(defaultData)(data);
- }),
- onChange: action((field, event) => {
- store.errors = {};
- store.data[field] = event.target.value;
- }),
- opSave: asyncOpCreate((payload) => rest.post(`git_credential`, payload)),
- opUpdate: asyncOpCreate((payload) =>
- rest.patch(`git_credential/${store.data.id}`, payload)
- ),
- opGetAll: asyncOpCreate(() => rest.get(`git_credential`)),
- getAll: action(
- pipe([
- () => store.opGetAll.fetch(),
- tap((result) => {
- console.log("getAll result", result);
- }),
- first,
- //TODO check if empty
- tap((result) => {
- store.setData(result);
- }),
- ])
- ),
- get defaultCredential() {
- return first(store.opGetAll.data);
- },
- get isSaving() {
- return store.opSave.loading;
- },
- get isDisabled() {
- return or([
- pipe([get("username"), isEmpty]),
- pipe([get("password"), isEmpty]),
- ])(store.data);
- },
- validate: action(async ({ data }) => {
- store.setErrors({});
- const vErrors = validate(data, rules);
- if (vErrors) {
- store.setErrors(vErrors);
- return false;
- } else {
- return true;
- }
- }),
- save: action(
- pipe([
- tap(() => {
- console.log("save", store.data);
- }),
- switchCase([
- () => store.validate(store),
- tryCatch(
- pipe([
- switchCase([
- () => isEmpty(store.data.id),
- () => store.create(store.data),
- () => store.update(store.data),
- ]),
- tap(() => {
- emitter.emit("step.next");
- }),
- ]),
- (error) => {
- console.error("save error", error);
- }
- ),
- () => undefined,
- ]),
- ])
- ),
- create: action(
- pipe([
- tap((data) => {
- console.log("create ", data);
- }),
- (data) => store.opSave.fetch(data),
- tap(({ id }) => {
- console.log("created ", id);
- }),
- tap(({ id }) => {
- store.id = id;
- }),
- ])
- ),
- update: action(
- pipe([
- tap((data) => {
- console.log("update ", data);
- store.id = store.data.id;
- }),
- (data) => store.opUpdate.fetch(data),
- tap((result) => {
- console.log("updated ", result);
- }),
- ])
- ),
- skip: () => {
- emitter.emit("step.select", "Configuration");
- },
- });
-
- return store;
-};
-
-export const gitCredentialFormContent = (context) => {
- const {
- tr,
- theme: { palette },
- } = context;
- const FormGroup = formGroup(context);
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 400px;
- }
- `,
- });
-
- return observer(({ store }) => (
- <>
-
- store.onChange("username", event)}
- label={tr.t("Git username")}
- error={get("username[0]")(store.errors)}
- />
-
-
- store.onChange("password", event)}
- label={tr.t("Git password or Personnal access code")}
- error={get("password[0]")(store.errors)}
- type="password"
- />
-
- >
- ));
-};
-
-export const gitCredentialConfig = (context) => {
- const {
- tr,
- theme: { palette },
- emitter,
- } = context;
- const Form = form(context);
- const Spinner = spinner(context);
- const Button = button(context);
- const ButtonHistoryBack = buttonHistoryBack(context);
- const GitCredentialFormContent = gitCredentialFormContent(context);
-
- return observer(({ store }) => (
-
- ));
-};
diff --git a/client/src/app_infra/infra/gitRepositoryConfig.js b/client/src/app_infra/infra/gitRepositoryConfig.js
deleted file mode 100644
index 10c3868f..00000000
--- a/client/src/app_infra/infra/gitRepositoryConfig.js
+++ /dev/null
@@ -1,233 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe, tap, switchCase, tryCatch, eq } from "rubico";
-import { isEmpty } from "rubico/x";
-import validate from "validate.js";
-
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import button from "mdlean/lib/button";
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-import spinner from "mdlean/lib/spinner";
-import { buttonWizardBack } from "./wizardCreate";
-import form from "components/form";
-import alertAxios from "mdlean/lib/alertAjax";
-
-// TODO delete
-const rules = {
- url: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- branch: {
- presence: true,
- length: {
- minimum: 1,
- message: "must be at least 6 characters",
- },
- },
-};
-
-export const repositoryCreateStore = ({
- context,
- infraSettingsStore,
- gitCredentialStore,
-}) => {
- const { tr, history, alertStack, rest, emitter } = context;
- const asyncOpCreate = AsyncOp(context);
- const AlertAxios = alertAxios(context);
-
- const defaultData = {
- url: "",
- branch: "master",
- };
-
- const store = observable({
- id: undefined,
- data: defaultData,
- errors: {},
- setError: action((error) => {
- store.errors = error;
- }),
- setData: action((data) => {
- store.data = data;
- }),
- onChange: action((field, event) => {
- store.errors = {};
- store.data[field] = event.target.value;
- }),
- opSaveGitConfig: asyncOpCreate((gitConfig) =>
- rest.post(`git_repository`, gitConfig)
- ),
- opPatchInfra: asyncOpCreate(
- pipe([
- ({ id }) => ({
- id: infraSettingsStore.id,
- git_credential_id: gitCredentialStore.id,
- git_repository_id: id,
- }),
- tap((payload) => {
- console.log("patch infra ", infraSettingsStore.id, payload);
- }),
- (payload) => rest.patch(`infra/${infraSettingsStore.id}`, payload),
- ])
- ),
- opPushCode: asyncOpCreate(() =>
- rest.post(`infra/${infraSettingsStore.id}/push_code`)
- ),
- get isSaving() {
- return or([
- get("opSaveGitConfig.loading"),
- get("opPatchInfra.loading"),
- get("opPushCode.loading"),
- ])(store);
- },
- get isDisabled() {
- return or([pipe([get("url"), isEmpty])])(store.data);
- },
- validate: action(async ({ data }) => {
- store.errors = {};
- const vErrors = validate(data, rules);
- if (vErrors) {
- store.errors = vErrors;
- return false;
- } else {
- return true;
- }
- }),
- save: action(async () =>
- pipe([
- tap(() => {
- console.log("save", store.data);
- }),
- switchCase([
- () => store.validate({ data: store.data }),
- tryCatch(
- pipe([
- () => store.opSaveGitConfig.fetch(store.data),
- tap(({ id }) => {
- store.id = id;
- }),
- tap(({ id }) => store.opPatchInfra.fetch({ id })),
- tap(() => store.opPushCode.fetch()),
- tap(() => {
- emitter.emit("step.next");
- }),
- ]),
- (error) =>
- pipe([
- tap(() => {
- //console.error("save", error);
- }),
- () => error,
- switchCase([
- eq(get("response.data.code"), "UrlParseError"),
- () => {
- store.setError({ url: [error.response.data.message] });
- },
- eq(get("response.data.data.statusCode"), 404),
- () => {
- store.setError({
- url: [error.response.data.data.statusMessage],
- });
- },
- eq(get("response.data.data.statusCode"), 401),
- () => {
- gitCredentialStore.setErrors({
- username: [error.response.data.data.response],
- password: [error.response.data.data.response],
- });
- emitter.emit("step.previous");
- },
- tap(() => {
- console.error("save error.response", error.response);
- alertStack.add( );
- }),
- ]),
- ])()
- ),
- () => undefined,
- ]),
- ])()
- ),
- });
-
- return store;
-};
-
-export const repositoryConfig = (context) => {
- const {
- tr,
- theme: { palette },
- } = context;
- const Form = form(context);
- const Spinner = spinner(context);
- const Button = button(context);
- const FormGroup = formGroup(context);
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 500px;
- }
- `,
- });
- const ButtonWizardBack = buttonWizardBack(context);
-
- return observer(({ store }) => (
-
- ));
-};
diff --git a/client/src/app_infra/infra/importProjectForm.js b/client/src/app_infra/infra/importProjectForm.js
deleted file mode 100644
index 69d363f6..00000000
--- a/client/src/app_infra/infra/importProjectForm.js
+++ /dev/null
@@ -1,216 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe } from "rubico";
-import { isEmpty } from "rubico/x";
-import validate from "validate.js";
-import modal from "mdlean/lib/modal";
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import button from "mdlean/lib/button";
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-import spinner from "mdlean/lib/spinner";
-import { list, listItem } from "mdlean/lib/list";
-import { buttonHistoryBack } from "./wizardCreate";
-import form from "components/form";
-import { PROJECTS } from "./projectList";
-
-const projectId = (project) => `${project.url}${project.directory}`;
-
-const projectItem = (context) => {
- const ListItem = listItem(context);
- const ProjectItem = ({ item, store, ...leftOver }) => (
- store.onSelectProject(item)} {...leftOver} raised>
- {item.title}
- {item.description}
-
- );
- return ProjectItem;
-};
-
-const importTypeItem = (context) => {
- const ListItem = listItem(context);
- const ImportTypeItem = ({ item, onClick, ...leftOver }) => (
- onClick(item)} raised>
- {item.title}
- {item.description}
-
- );
- return ImportTypeItem;
-};
-
-export const importProjectCreateStore = (context) => {
- const { emitter } = context;
-
- const store = observable({
- project: {},
- modalOpenNewProjectFromTemplate: false,
- showNewProjectFromTemplate: action((show) => {
- store.modalOpenNewProjectFromTemplate = show;
- }),
- onSelectProject: (project) => {
- store.modalOpenNewProjectFromTemplate = false;
- store.project = project;
- emitter.emit("step.next");
- },
- modalImportFromCloud: false,
- showImportFromCloud: action((show) => {
- store.modalImportFromCloud = show;
- }),
- selectImportFormCloud: action((project) => {
- store.modalOpenNewProjectFromTemplate = false;
- emitter.emit("step.next", { pippo: "pippo" });
- }),
- });
-
- return store;
-};
-
-const modalNewFromTemplate = (context) => {
- const Modal = modal(context);
- const Button = button(context);
- const List = list(context);
- const ProjectItem = projectItem(context);
-
- return observer(({ store, projects = [] }) => (
- {
- store.showNewProjectFromTemplate(false);
- }}
- >
- New infrastructure from a template
-
- Select an infrastructure template from the list below.
- li {
- margin: 1rem 0;
- }
- `}
- >
- projectId(item)}
- itemRenderer={ProjectItem}
- store={store}
- />
-
-
-
- store.showNewProjectFromTemplate(false)}>
- Cancel
-
-
-
- ));
-};
-
-const modalImportFromCloud = (context) => {
- const Modal = modal(context);
- const Button = button(context);
-
- return observer(({ store }) => (
- {
- store.showNewProjectFromTemplate(false);
- }}
- >
-
-
- TODO
-
-
- store.showImportFromCloud(false)}>Cancel
-
-
- ));
-};
-
-export const importProjectForm = (context) => {
- const { tr, theme, emitter } = context;
- const ImportTypeItem = importTypeItem(context);
- const Form = form(context);
- const ButtonHistoryBack = buttonHistoryBack(context);
- const ModalNewFromTemplate = modalNewFromTemplate(context);
- const ModalImportFromCloud = modalImportFromCloud(context);
-
- return observer(({ store, storeProvider }) => (
-
- ));
-};
diff --git a/client/src/app_infra/infra/index.js b/client/src/app_infra/infra/index.js
deleted file mode 100644
index e4c3431d..00000000
--- a/client/src/app_infra/infra/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import wizard from "./wizard";
-export default wizard;
diff --git a/client/src/app_infra/infra/infraDelete.js b/client/src/app_infra/infra/infraDelete.js
deleted file mode 100644
index 445a96b5..00000000
--- a/client/src/app_infra/infra/infraDelete.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observer } from "mobx-react";
-
-import button from "mdlean/lib/button";
-import formGroup from "mdlean/lib/formGroup";
-import input from "mdlean/lib/input";
-
-import createForm from "components/form";
-
-export const createInfraDelete = (context) => {
- const { tr, history } = context;
- const Form = createForm(context);
- const FormGroup = formGroup(context);
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 300px;
- }
- `,
- });
- const Button = button(context, {
- cssOverride: css``,
- });
-
- const InfraDeleteForm = ({ store }) => (
-
- );
- return observer(InfraDeleteForm);
-};
diff --git a/client/src/app_infra/infra/infraDeleteLink.js b/client/src/app_infra/infra/infraDeleteLink.js
deleted file mode 100644
index d5ae8d44..00000000
--- a/client/src/app_infra/infra/infraDeleteLink.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { toJS } from "mobx";
-import { observer } from "mobx-react";
-
-export const infraDeleteLink = ({ history }) =>
- observer(({ store, infraSettingsStore }) => (
-
- {/*
- {JSON.stringify(infraSettingsStore.data, null, 4)}
- */}
- {
- history.push(`/infra/detail/${store.id}/delete`, {
- id: store.id,
- ...toJS(infraSettingsStore.data),
- });
- }}
- >
- Danger zone...
-
-
- ));
diff --git a/client/src/app_infra/infra/infraDetail.js b/client/src/app_infra/infra/infraDetail.js
deleted file mode 100644
index cb038a2f..00000000
--- a/client/src/app_infra/infra/infraDetail.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observer } from "mobx-react";
-import { get, eq, pipe, flatMap, fork, switchCase, pick, tap } from "rubico";
-import { size, isEmpty } from "rubico/x";
-import { MdEdit } from "react-icons/md";
-import formatDistance from "date-fns/formatDistance";
-
-import button from "mdlean/lib/button";
-
-import createForm from "components/form";
-import spinner from "mdlean/lib/spinner";
-import screenLoader from "components/screenLoader";
-
-import badgeRegion from "./badgeRegion";
-import providerLogo from "./providerLogo";
-import createResourcePerTypeTable from "./resourceTable";
-
-const createInfraDetail = (context) => {
- const {
- tr,
- history,
- theme: { palette },
- } = context;
- const Form = createForm(context);
- const BadgeRegion = badgeRegion(context);
- const ProviderLogo = providerLogo(context);
- const Spinner = spinner(context);
- const Button = button(context, {
- cssOverride: css``,
- });
- const ResourcePerTypeTable = createResourcePerTypeTable(context);
- const ScreenLoader = screenLoader(context);
- const InfraDetailContainer = observer(({ store }) => (
-
- {store.opGetById.data ? (
-
- ) : null}
-
-
- ));
- const ScanLastUpdated = ({ updatedAt }) => (
- div {
- margin: 0.4rem 0;
- }
- `}
- >
-
- Last Scan
-
-
{`${
- updatedAt && formatDistance(new Date(updatedAt), new Date())
- } ago`}
-
- );
-
- const InfraDetail = observer(({ store, detail }) => (
-
- ));
-
- return InfraDetailContainer;
-};
-
-export default createInfraDetail;
diff --git a/client/src/app_infra/infra/infraList.js b/client/src/app_infra/infra/infraList.js
deleted file mode 100644
index 1f0c411c..00000000
--- a/client/src/app_infra/infra/infraList.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observer } from "mobx-react";
-import { get, eq, pipe, flatMap, fork, switchCase, pick, tap } from "rubico";
-import { size, isEmpty } from "rubico/x";
-
-import button from "mdlean/lib/button";
-
-import createForm from "components/form";
-import page from "components/Page";
-import screenLoader from "components/screenLoader";
-import badgeRegion from "./badgeRegion";
-import providerLogo from "./providerLogo";
-
-const getLivesFromJob = get("result.list.result.results[0].results");
-
-const resourceStats = pipe([
- getLivesFromJob,
- fork({ types: size, resources: pipe([flatMap(get("resources")), size]) }),
- tap((xx) => {}),
-]);
-
-const createInfraItem = (context) => {
- const { tr, history, rest, theme } = context;
-
- const { palette } = theme;
- const BadgeRegion = badgeRegion(context);
- const ProviderLogo = providerLogo(context);
- const ResourceStat = ({ stats }) => (
- span {
- margin: 0.3rem;
- }
- `}
- >
-
-
{stats.resources}
-
- );
-
- const Label = ({ title }) => (
-
- {title}
-
- );
- const ProjectName = ({ name }) => (
-
- );
- const InfraItem = ({ item, store, onClick }) => {
- return (
- * {
- margin: 1rem;
- }
- `}
- onClick={(event) => {
- onClick(item);
- }}
- >
-
- {item.Jobs[0] && }
-
- {item.providerAuth?.AWS_REGION && (
-
- )}
-
- );
- };
- return observer(InfraItem);
-};
-
-export const createInfraList = (context) => {
- const { tr, history } = context;
- const Form = createForm(context);
- const Page = page(context);
- const Button = button(context, {
- cssOverride: css`
- width: 256px;
- `,
- });
- const ScreenLoader = screenLoader(context);
-
- const InfraItem = createInfraItem(context);
-
- const InfraListView = observer(({ store, items }) => (
-
- ));
-
- const InfraListContainer = observer(({ store }) => (
-
- {store.opGet.data && (
-
- )}
-
-
- ));
- return InfraListContainer;
-};
diff --git a/client/src/app_infra/infra/infraModule.js b/client/src/app_infra/infra/infraModule.js
deleted file mode 100644
index 71665ace..00000000
--- a/client/src/app_infra/infra/infraModule.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { observable, action, toJS } from "mobx";
-import { get } from "rubico";
-import { isEmpty } from "rubico/x";
-
-import alert from "mdlean/lib/alert";
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import { wizardStoreCreate } from "./wizardCreate";
-
-import { createRoutes } from "./infraRoutes";
-
-const getLivesFromJob = get("result.list.result.results[0].results");
-
-export default function (context) {
- const { rest, tr, history, alertStack, emitter } = context;
- const asyncOpCreate = AsyncOp(context);
- const Alert = alert(context);
- const wizardStore = wizardStoreCreate(context);
- function Stores() {
- const infraStore = observable({
- errors: {},
- opGet: asyncOpCreate(() => rest.get("infra")),
- get: action(async function () {
- const response = await this.opGet.fetch();
- if (isEmpty(response)) {
- context.history.push("/infra/create");
- }
- console.log(response);
- }),
- });
-
- const infraDetailStore = observable({
- id: "",
- lives: [],
- svg: "",
- opGetById: asyncOpCreate((id) => rest.get(`infra/${id}`)),
- getById: action(async (id) => {
- const infra = await infraDetailStore.opGetById.fetch(id);
- infraDetailStore.lives = getLivesFromJob(infra.Jobs[0]);
- infraDetailStore.svg = get("Jobs[0].result.svg")(infra);
- }),
- opScan: asyncOpCreate((infraItem) =>
- rest.post(`cloudDiagram`, { infra_id: infraItem.id })
- ),
- scan: action(async (infraItem) => {
- console.log("infraDetailStore scan", infraItem);
- await infraDetailStore.opScan.fetch(infraItem);
- await infraDetailStore.getById(infraItem.id);
- }),
- });
-
- const storeDelete = observable({
- name: "",
- setName: (name) => {
- storeDelete.name = name;
- },
- data: {},
- setData: (data) => {
- storeDelete.name = "";
- storeDelete.data = data;
- },
- errors: {},
- opDestroy: asyncOpCreate(() => rest.del(`infra/${storeDelete.data.id}`)),
- get nameMatch() {
- return (
- !isEmpty(storeDelete.name) &&
- storeDelete.name === storeDelete.data.name
- );
- },
- destroy: action(async () => {
- try {
- await storeDelete.opDestroy.fetch();
-
- alertStack.add(
-
- );
- history.push("/infra");
- emitter.emit("infra.deleted", storeDelete.data);
- } catch (error) {
- console.error(error);
- alertStack.add(
-
- );
- }
- }),
- });
-
- return {
- infra: infraStore,
- infraDetail: infraDetailStore,
- delete: storeDelete,
- wizard: wizardStore,
- };
- }
-
- const stores = Stores(context);
-
- return {
- stores: () => stores,
- routes: () => createRoutes({ context, stores }),
- };
-}
diff --git a/client/src/app_infra/infra/infraRoutes.js b/client/src/app_infra/infra/infraRoutes.js
deleted file mode 100644
index 6c4b0386..00000000
--- a/client/src/app_infra/infra/infraRoutes.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { createElement as h } from "react";
-
-import { wizardCreate } from "./wizardCreate";
-import createInfraDetail from "./infraDetail";
-import { awsFormEdit } from "./awsConfig";
-import { gcpFormEdit } from "./gcpConfig";
-import { azureFormEdit } from "./azureConfig";
-import { ovhFormEdit } from "./ovhConfig";
-
-import { createInfraDelete } from "./infraDelete";
-import { createInfraList } from "./infraList";
-
-export const createRoutes = ({ context, stores }) => {
- return [
- {
- path: "",
- protected: true,
- action: (routerContext) => {
- stores.infra.get();
- return {
- routerContext,
- title: "My Infra",
- component: h(createInfraList(context), {
- title: "Create",
- store: stores.infra,
- }),
- };
- },
- },
- {
- path: "/create",
- protected: true,
- action: (routerContext) => {
- return {
- routerContext,
- title: "Create Infrastructure",
- component: h(wizardCreate({ context, stores }), {
- title: "Create",
- buttonTitle: "Create Infrastructure",
- }),
- };
- },
- },
- {
- path: "/detail/:id/aws/edit",
- protected: true,
- action: async (routerContext) => {
- stores.wizard.infraSettingsStore.setData(window.history.state.usr);
- stores.wizard.aws.core.setData(window.history.state.usr);
- return {
- routerContext,
- title: "Edit Aws Infrastructure",
- component: h(awsFormEdit(context), {
- store: stores.wizard.aws,
- infraSettingsStore: stores.wizard.infraSettingsStore,
- }),
- };
- },
- },
- {
- path: "/detail/:id/google/edit",
- protected: true,
- action: async (routerContext) => {
- stores.wizard.infraSettingsStore.setData(window.history.state.usr);
- stores.wizard.google.core.setData(window.history.state.usr);
- return {
- routerContext,
- title: "Edit GCP Infrastructure",
- component: h(gcpFormEdit(context), {
- store: stores.wizard.google,
- infraSettingsStore: stores.wizard.infraSettingsStore,
- }),
- };
- },
- },
- {
- path: "/detail/:id/azure/edit",
- protected: true,
- action: async (routerContext) => {
- stores.wizard.infraSettingsStore.setData(window.history.state.usr);
- stores.wizard.azure.core.setData(window.history.state.usr);
- return {
- routerContext,
- title: "Edit Azure Infrastructure",
- component: h(azureFormEdit(context), {
- store: stores.wizard.azure,
- infraSettingsStore: stores.wizard.infraSettingsStore,
- }),
- };
- },
- },
- {
- path: "/detail/:id/ovh/edit",
- protected: true,
- action: async (routerContext) => {
- stores.wizard.infraSettingsStore.setData(window.history.state.usr);
- stores.wizard.ovh.core.setData(window.history.state.usr);
- return {
- routerContext,
- title: "Edit OVH Infrastructure",
- component: h(ovhFormEdit(context), {
- store: stores.wizard.ovh,
- infraSettingsStore: stores.wizard.infraSettingsStore,
- }),
- };
- },
- },
- {
- path: "/detail/:id/delete",
- protected: true,
- action: (routerContext) => {
- stores.delete.setData(window.history.state.usr);
- return {
- routerContext,
- title: "Delete Infrastructure",
- component: h(createInfraDelete(context), {
- store: stores.delete,
- }),
- };
- },
- },
- {
- path: "/detail/:id",
- protected: true,
- action: async (routerContext) => {
- await stores.infraDetail.getById(routerContext.params.id);
- return {
- routerContext,
- title: "Infrastructure Detail",
- component: h(createInfraDetail(context), {
- store: stores.infraDetail,
- detail: window.history.state.usr,
- }),
- };
- },
- },
- ];
-};
diff --git a/client/src/app_infra/infra/infraSettings.js b/client/src/app_infra/infra/infraSettings.js
deleted file mode 100644
index 41886ccd..00000000
--- a/client/src/app_infra/infra/infraSettings.js
+++ /dev/null
@@ -1,178 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe, tap, switchCase, tryCatch } from "rubico";
-import { isEmpty } from "rubico/x";
-import validate from "validate.js";
-
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import button from "mdlean/lib/button";
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-import spinner from "mdlean/lib/spinner";
-import createAlert from "mdlean/lib/alert";
-
-import { buttonWizardBack } from "./wizardCreate";
-import form from "components/form";
-
-const rules = {
- name: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- stage: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
-};
-
-const defaultData = {
- id: undefined,
- name: "",
- stage: "dev",
-};
-
-export const infraSettingsCreateStore = ({
- context,
- providerSelectionStore,
- importProjectStore,
-}) => {
- const { tr, history, alertStack, rest, emitter } = context;
- const asyncOpCreate = AsyncOp(context);
- const Alert = createAlert(context);
-
- const store = observable({
- id: undefined,
- data: defaultData,
- errors: {},
- setData: action((data) => {
- store.data = data;
- }),
- onChange: action((field, event) => {
- store.data[field] = event.target.value;
- }),
- opSave: asyncOpCreate((params) => rest.post(`infra`, params)),
- get isSaving() {
- return store.opSave.loading;
- },
- get isDisabled() {
- return or([pipe([get("name"), isEmpty])])(store.data);
- },
- validate: action(async ({ data }) => {
- store.errors = {};
- const vErrors = validate(data, rules);
- if (vErrors) {
- store.errors = vErrors;
- return false;
- } else {
- return true;
- }
- }),
- save: action(async ({ data }) =>
- pipe([
- tap(() => {
- console.log("save", data);
- }),
- switchCase([
- () => store.validate({ data }),
- tryCatch(
- pipe([
- () => ({
- ...store.data,
- ...providerSelectionStore.data,
- project: { ...importProjectStore.project },
- }),
- tap((payload) => {
- console.log("infra setting save payload", payload);
- }),
- (payload) => store.opSave.fetch(payload),
- tap((result) => {
- store.id = result.id;
- }),
- tap(() => {
- emitter.emit("step.next");
- }),
- ]),
- (error) =>
- pipe([
- tap(() => {
- console.error("save error", error);
- }),
- ])()
- ),
- () => undefined,
- ]),
- ])()
- ),
- });
-
- return store;
-};
-
-export const infraSettings = (context) => {
- const {
- tr,
- theme: { palette },
- } = context;
- const Form = form(context);
- const Spinner = spinner(context);
- const Button = button(context);
- const FormGroup = formGroup(context);
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 500px;
- }
- `,
- });
- const ButtonWizardBack = buttonWizardBack(context);
-
- return observer(({ store }) => (
-
- ));
-};
diff --git a/client/src/app_infra/infra/ovhConfig.js b/client/src/app_infra/infra/ovhConfig.js
deleted file mode 100644
index b3e5a765..00000000
--- a/client/src/app_infra/infra/ovhConfig.js
+++ /dev/null
@@ -1,226 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-import { get, or, pipe } from "rubico";
-import { isEmpty } from "rubico/x";
-
-import input from "mdlean/lib/input";
-import formGroup from "mdlean/lib/formGroup";
-import { providerCreateStore } from "./providerStore";
-
-import {
- providerFormCreate,
- providerFormUpdate,
- providerConfigCreateFooter,
- providerConfigUpdateFooter,
-} from "./providerConfigCommon";
-
-const OVH_REGION = [
- "UK1",
- "BHS5",
- "DE1",
- "GRA5",
- "GRA7",
- "GRA9",
- "GRA11",
- "SBG5",
- "WAW1",
- "SGP1",
- "SYD1",
-];
-
-import selectRegion from "./SelectRegion";
-
-const rules = {
- OS_PROJECT_NAME: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- OS_PROJECT_ID: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- OS_USERNAME: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
- OS_PASSWORD: {
- presence: true,
- length: {
- minimum: 2,
- message: "must be at least 2 characters",
- },
- },
-};
-
-const defaultData = {
- id: "",
- name: "",
- OS_AUTH_URL: "https://auth.cloud.ovh.net/v3",
- OS_PROJECT_NAME: "",
- OS_PROJECT_ID: "",
- OS_USERNAME: "",
- OS_PASSWORD: "",
- OS_REGION_NAME: "UK1",
-};
-
-export const createStoreOvh = (
- context,
- {
- infraSettingsStore,
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- }
-) => {
- const core = providerCreateStore({
- context,
- defaultData,
- rules,
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
- });
-
- const store = observable({
- buildPayload: ({ data }) => ({
- providerType: "openstack",
- providerName: "ovh",
- providerAuth: {
- OS_AUTH_URL: data.OS_AUTH_URL,
- OS_PROJECT_NAME: data.OS_PROJECT_NAME.trim(),
- OS_PROJECT_ID: data.OS_PROJECT_ID.trim(),
- OS_USERNAME: data.OS_USERNAME.trim(),
- OS_PASSWORD: data.OS_PASSWORD,
- OS_REGION_NAME: data.OS_REGION_NAME,
- },
- }),
- get isDisabled() {
- return or([
- pipe([get("OS_PROJECT_NAME"), isEmpty]),
- pipe([get("OS_PROJECT_ID"), isEmpty]),
- pipe([get("OS_USERNAME"), isEmpty]),
- pipe([get("OS_REGION_NAME"), isEmpty]),
- ])(core.data);
- },
- core,
- });
- return store;
-};
-
-export const ovhConfigForm = (context) => {
- const { tr } = context;
- const FormGroup = formGroup(context);
- const OvhSelectRegion = selectRegion(context, { items: OVH_REGION });
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 320px;
- }
- `,
- });
-
- return observer(({ store }) => (
- <>
-
- store.onChange("OS_PROJECT_NAME", event)}
- label={tr.t("OS_PROJECT_NAME")}
- error={get("OS_PROJECT_NAME[0]")(store.errors)}
- />
-
-
- store.onChange("OS_PROJECT_ID", event)}
- label={tr.t("OS_PROJECT_ID")}
- error={get("OS_PROJECT_ID[0]")(store.errors)}
- />
-
-
- store.onChange("OS_USERNAME", event)}
- label={tr.t("OS_USERNAME")}
- error={get("OS_USERNAME[0]")(store.errors)}
- />
-
-
- store.onChange("OS_PASSWORD", event)}
- label={tr.t("OS_PASSWORD")}
- type="password"
- error={get("OS_PASSWORD[0]")(store.errors)}
- />
-
-
- {
- store.data.OS_REGION_NAME = region;
- }}
- />
-
- >
- ));
-};
-
-export const ovhFormCreate = (context) => {
- const { tr } = context;
- const FormCreate = providerFormCreate(context);
- const OvhConfigForm = ovhConfigForm(context);
- const Footer = providerConfigCreateFooter(context);
-
- return observer(({ store }) => (
-
-
- {tr.t("Create new OVH Infrastructure")}
-
-
-
- {tr.t(
- "Please provide the following information to create and scan a new infrastructure"
- )}
-
-
-
-
-
- ));
-};
-
-export const ovhFormEdit = (context) => {
- const { tr } = context;
- const FormUpdate = providerFormUpdate(context);
- const OvhConfigForm = ovhConfigForm(context);
- const Footer = providerConfigUpdateFooter(context);
-
- return observer(({ store, infraSettingsStore }) => (
-
-
- {tr.t("Update OVH Infrastructure")}
-
-
-
-
-
-
- ));
-};
diff --git a/client/src/app_infra/infra/ovhSelectRegion.js b/client/src/app_infra/infra/ovhSelectRegion.js
deleted file mode 100644
index 1ff7641a..00000000
--- a/client/src/app_infra/infra/ovhSelectRegion.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { jsx, css } from "@emotion/react";
-import select from "mdlean/lib/select";
-
-const OVH_REGION = [
- "UK1",
- "BHS5",
- "DE1",
- "GRA5",
- "GRA7",
- "GRA9",
- "GRA11",
- "SBG5",
- "WAW1",
- "SGP1",
- "SYD1",
-];
-
-export default (context) => {
- const Item = ({ item }) => (
-
- {item}
-
- );
- const SelectRegion = select(context, {
- items: OVH_REGION,
- renderItems: Item,
- cssOveride: css`
- width: 200px;
- `,
- });
-
- return SelectRegion;
-};
diff --git a/client/src/app_infra/infra/projectList.js b/client/src/app_infra/infra/projectList.js
deleted file mode 100644
index b86a169f..00000000
--- a/client/src/app_infra/infra/projectList.js
+++ /dev/null
@@ -1,76 +0,0 @@
-const url = "https://github.com/grucloud/grucloud/";
-const branch = "main";
-
-export const PROJECTS = {
- aws: [
- {
- title: "EC2 an instance with public address",
- description:
- "Deploy a EC2 virtual machine attached to an elastic public address",
- url,
- branch,
- directory: "examples/aws/ec2",
- },
- {
- title: "EKS",
- description: "Deploy a kubernetes cluster with EKS",
- url,
- branch,
- directory: "examples/aws/EKS/eks-simple",
- },
- {
- title: "Route53 TXT Record",
- description: "Create an Hosted Zone and a TXT record",
- url,
- branch,
- directory: "examples/aws/route53/dns-validation-record-txt",
- },
- ],
- azure: [
- {
- title: "Virtual machine",
- description:
- "Deploy a virtual machine with a public address, protected by a firewall",
- url,
- branch,
- directory: "examples/azure/Compute/vm",
- },
- ],
- google: [
- {
- title: "Virtual machine",
- description: "Deploy a virtual machine on the default network",
- resources: ["compute.instance"],
- url,
- branch,
- directory: "examples/google/vm",
- },
- {
- title: "Virtual machine inside a network",
- description:
- "Create a network, a sub-network, a virtual machine and firewall rules for HTTP/HTTPS",
- url,
- branch,
- directory: "examples/google/vm-network",
- resources: [
- "compute.network",
- "compute.subnetwork",
- "compute.subnetwork",
- ],
- },
- {
- title: "Secure static website",
- description: "Deploy a static website served with HTTPS",
- url,
- branch,
- directory: "examples/google/storage/website-https",
- },
- {
- title: "DNS records",
- description: "Manages DNS records such as A, CNAME, TXT and MX records",
- url,
- branch,
- directory: "examples/google/dns/github-page",
- },
- ],
-};
diff --git a/client/src/app_infra/infra/providerConfigCommon.js b/client/src/app_infra/infra/providerConfigCommon.js
deleted file mode 100644
index a04dd423..00000000
--- a/client/src/app_infra/infra/providerConfigCommon.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observer } from "mobx-react";
-import { get, or, pipe } from "rubico";
-import { isEmpty } from "rubico/x";
-import createForm from "components/form";
-
-import button from "mdlean/lib/button";
-import spinner from "mdlean/lib/spinner";
-import { infraDeleteLink } from "./infraDeleteLink";
-import { buttonWizardBack, buttonHistoryBack } from "./wizardCreate";
-
-export const providerFormCreate = (context) => {
- const Form = createForm(context);
- return ({ children }) => (
-
- );
-};
-
-export const providerFormUpdate = (context) => {
- const Form = createForm(context);
- return ({ children }) => (
-
- );
-};
-
-export const providerConfigCreateFooter = (context) => {
- const {
- tr,
- history,
- theme: { palette },
- } = context;
-
- const Spinner = spinner(context);
- const Button = button(context, {
- cssOverride: css``,
- });
- const ButtonWizardBack = buttonWizardBack(context);
-
- return observer(({ store }) => (
-
-
-
- store.core.create({
- data: store.buildPayload({ data: store.core.data }),
- })
- }
- label={tr.t("Create Infrastructure")}
- />
-
-
- ));
-};
-
-export const providerConfigUpdateFooter = (context) => {
- const {
- tr,
- history,
- theme: { palette },
- } = context;
-
- const Spinner = spinner(context);
- const Button = button(context, {
- cssOverride: css``,
- });
- const ButtonHistoryBack = buttonHistoryBack(context);
- const InfraDeleteLink = infraDeleteLink(context);
-
- return observer(({ store, infraSettingsStore }) => (
- <>
-
-
-
- store.core.update({
- data: store.buildPayload({ data: store.core.data }),
- })
- }
- label={tr.t("Update Infrastructure")}
- />
-
-
-
- >
- ));
-};
diff --git a/client/src/app_infra/infra/providerLogo.js b/client/src/app_infra/infra/providerLogo.js
deleted file mode 100644
index 3ba0b489..00000000
--- a/client/src/app_infra/infra/providerLogo.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { get, eq, pipe, flatMap, fork, switchCase, pick, tap } from "rubico";
-
-import AwsLogo from "./assets/aws.svg";
-import GcpLogo from "./assets/gcp.svg";
-import AzureLogo from "./assets/azure.svg";
-import OvhLogo from "./assets/ovh.svg";
-
-const providerName2Logo = (name) =>
- switchCase([
- eq(name, "aws"),
- () => AwsLogo,
- eq(name, "google"),
- () => GcpLogo,
- eq(name, "azure"),
- () => AzureLogo,
- eq(name, "ovh"),
- () => OvhLogo,
- (type) => {type}
,
- ])();
-
-const providerLogo =
- ({ theme: { palette } }) =>
- ({ name }) =>
- (
-
- );
-
-export default providerLogo;
diff --git a/client/src/app_infra/infra/providerSelection.js b/client/src/app_infra/infra/providerSelection.js
deleted file mode 100644
index 00c41750..00000000
--- a/client/src/app_infra/infra/providerSelection.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observable, action } from "mobx";
-import { observer } from "mobx-react";
-
-import button from "mdlean/lib/button";
-
-import AwsLogo from "./assets/aws.svg";
-import GcpLogo from "./assets/gcp.svg";
-import AzureLogo from "./assets/azure.svg";
-import OvhLogo from "./assets/ovh.svg";
-
-export const providerSelectionCreateStore = ({ context }) => {
- const { emitter } = context;
- const store = observable({
- data: {},
- selectProvider: (provider) => {
- store.data = provider;
- if (!provider.providerType) {
- store.data.providerType = provider.providerName;
- }
- emitter.emit("step.next");
- },
- setProvider: (provider) => {
- store.data = provider;
- },
- get supportImport() {
- return store.providerType === "google";
- },
- });
- return store;
-};
-
-export const providerSelection = (context) => {
- const Button = button(context);
- return observer(({ store }) => (
-
- ));
-};
diff --git a/client/src/app_infra/infra/providerStore.js b/client/src/app_infra/infra/providerStore.js
deleted file mode 100644
index 5fe08918..00000000
--- a/client/src/app_infra/infra/providerStore.js
+++ /dev/null
@@ -1,169 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { observable, action } from "mobx";
-import validate from "validate.js";
-import { pipe, switchCase, tryCatch, tap } from "rubico";
-const { defaultsDeep } = require("rubico/x");
-
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import createAlert from "mdlean/lib/alert";
-
-export const providerCreateStore = ({
- context,
- defaultData,
- rules,
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
-}) => {
- const { tr, rest, emitter, alertStack, history } = context;
- const Alert = createAlert(context);
- const asyncOpCreate = AsyncOp(context);
-
- const store = observable({
- id: "",
- data: defaultData,
- errors: {},
- onChange: action((field, event) => {
- store.data[field] = event.target.value;
- }),
- reset: action(() => {
- store.data = defaultData;
- }),
- setData: action((data) => {
- store.id = data.id;
- store.data = defaultsDeep(defaultData)(data.providerAuth);
- }),
- get supportImport() {
- return store.providerName === "google";
- },
- opScan: asyncOpCreate((infraItem) =>
- rest.post(`cloudDiagram`, { infra_id: infraItem.id })
- ),
- op: asyncOpCreate((payload) => rest.post("infra", payload)),
- get isCreating() {
- return store.opScan.loading || store.opUpdate.loading;
- },
- validate: action(async ({ data }) => {
- store.errors = {};
- const vErrors = validate(
- { name: data.name, ...data.providerAuth },
- rules
- );
- if (vErrors) {
- store.errors = vErrors;
- return false;
- } else {
- return true;
- }
- }),
- create: action(async ({ data }) =>
- pipe([
- tap(() => {
- console.log("create", data);
- }),
- switchCase([
- () => store.validate({ data }),
- tryCatch(
- pipe([
- () => ({
- ...data,
- id: infraSettingsStore.id,
- git_credential_id: gitCredentialStore.id,
- git_repository_id: gitRepositoryStore.id,
- }),
- tap((payload) => {
- console.log("create payload", payload);
- }),
- (payload) => store.opUpdate.fetch(payload),
- tap(() => {
- alertStack.add(
-
- );
- }),
- tap((result) => {
- history.push(`/infra/detail/${result.id}`, result);
- }),
- tap((result) => {
- emitter.emit("infra.created", result);
- }),
- ]),
- (error) =>
- pipe([
- tap(() => {
- console.error("create", error);
- }),
- tap(() => {
- alertStack.add(
-
- );
- }),
- ])()
- ),
- () => undefined,
- ]),
- ])()
- ),
- //TODO use id in the payload
- opUpdate: asyncOpCreate((payload) =>
- rest.patch(`infra/${store.id || infraSettingsStore.id}`, payload)
- ),
- get isUpdating() {
- return store.opScan.loading || store.opUpdate.loading;
- },
- update: action(async ({ data }) =>
- pipe([
- tap(() => {
- console.log("update", data);
- }),
- switchCase([
- () => store.validate({ data }),
- tryCatch(
- pipe([
- () => store.opUpdate.fetch(data),
- tap(() => {
- alertStack.add(
-
- );
- }),
- tap((result) => {
- history.push(`/infra/detail/${result.id}`, result);
- }),
- tap((result) => {
- emitter.emit("infra.updated", result);
- }),
- ]),
- (error) =>
- pipe([
- tap(() => {
- console.error("update", error);
- }),
- tap(() => {
- alertStack.add(
-
- );
- }),
- ])()
- ),
- () => undefined,
- ]),
- ])()
- ),
- });
- return store;
-};
diff --git a/client/src/app_infra/infra/resourceTable.js b/client/src/app_infra/infra/resourceTable.js
deleted file mode 100644
index 69e25c2f..00000000
--- a/client/src/app_infra/infra/resourceTable.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-
-const createResourcePerTypeTable =
- ({ theme }) =>
- ({ lives }) =>
- (
-
-
-
- Resource Type
- Total
-
-
-
- {lives &&
- lives.map((live) => (
-
- {live.type}
- {live?.resources.length}
-
- ))}
-
-
- );
-
-export default createResourcePerTypeTable;
diff --git a/client/src/app_infra/infra/rulesForm.js b/client/src/app_infra/infra/rulesForm.js
deleted file mode 100644
index b317ccce..00000000
--- a/client/src/app_infra/infra/rulesForm.js
+++ /dev/null
@@ -1,23 +0,0 @@
-export default {
- infraName: {
- presence: true,
- length: {
- minimum: 3,
- message: "must be at least 3 characters",
- },
- },
- accessKeyId: {
- presence: true,
- length: {
- minimum: 20,
- message: "must be at least 20 characters",
- },
- },
- secretKey: {
- presence: true,
- length: {
- minimum: 40,
- message: "must be at least 40 characters",
- },
- },
-};
diff --git a/client/src/app_infra/infra/wizardCreate.js b/client/src/app_infra/infra/wizardCreate.js
deleted file mode 100644
index 6fe43353..00000000
--- a/client/src/app_infra/infra/wizardCreate.js
+++ /dev/null
@@ -1,252 +0,0 @@
-/** @jsxImportSource @emotion/react */
-import { css } from "@emotion/react";
-import { observer } from "mobx-react";
-
-import button from "mdlean/lib/button";
-import wizard from "mdlean/lib/wizard";
-import screenLoader from "components/screenLoader";
-
-import {
- providerSelection,
- providerSelectionCreateStore,
-} from "./providerSelection";
-import { awsFormCreate, createStoreAws } from "./awsConfig";
-import { gcpFormCreate, createStoreGoogle } from "./gcpConfig";
-import { azureFormCreate, createStoreAzure } from "./azureConfig";
-import { ovhFormCreate, createStoreOvh } from "./ovhConfig";
-
-import { repositoryConfig, repositoryCreateStore } from "./gitRepositoryConfig";
-import {
- gitCredentialConfig,
- gitCredentialCreateStore,
-} from "./gitCredentialConfig";
-import { infraSettings, infraSettingsCreateStore } from "./infraSettings";
-
-import {
- importProjectForm,
- importProjectCreateStore,
-} from "./importProjectForm";
-
-export const buttonWizardBack = (context) => {
- const Button = button(context);
- return () => (
- context.emitter.emit("step.previous")}>
- {"\u25c0"} Back
-
- );
-};
-
-export const buttonHistoryBack = (context) => {
- const Button = button(context);
- return () => (
- context.history.back()}>{"\u25c0"} Back
- );
-};
-
-export const wizardStoreCreate = (context) => {
- const providerSelectionStore = providerSelectionCreateStore({ context });
-
- const importProjectStore = importProjectCreateStore(context);
-
- const infraSettingsStore = infraSettingsCreateStore({
- context,
- providerSelectionStore,
- importProjectStore,
- });
-
- const gitCredentialStore = gitCredentialCreateStore({
- context,
- infraSettingsStore,
- });
-
- const gitRepositoryStore = repositoryCreateStore({
- context,
- infraSettingsStore,
- gitCredentialStore,
- });
-
- const aws = createStoreAws(context, {
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- infraSettingsStore,
- });
-
- const google = createStoreGoogle(context, {
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- infraSettingsStore,
- });
-
- const azure = createStoreAzure(context, {
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- infraSettingsStore,
- });
-
- const ovh = createStoreOvh(context, {
- importProjectStore,
- gitCredentialStore,
- gitRepositoryStore,
- infraSettingsStore,
- });
-
- return {
- providerSelectionStore,
- importProjectStore,
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
- aws,
- azure,
- google,
- ovh,
- };
-};
-
-export const wizardCreate = ({ context, stores }) => {
- const { tr, emitter } = context;
-
- const ScreenLoader = screenLoader(context);
-
- const ProviderSelection = providerSelection(context);
- const InfraSettings = infraSettings(context);
- const RepositoryConfig = repositoryConfig(context);
- const GitCredentialConfig = gitCredentialConfig(context);
- const ImportProjectForm = importProjectForm(context);
-
- const AwsFormCreate = awsFormCreate(context);
- const GcpFormCreate = gcpFormCreate(context);
- const AzureFormCreate = azureFormCreate(context);
- const OvhFormCreate = ovhFormCreate(context);
-
- const {
- providerSelectionStore,
- importProjectStore,
- infraSettingsStore,
- gitCredentialStore,
- gitRepositoryStore,
- aws,
- google,
- azure,
- ovh,
- } = stores.wizard;
-
- const configViewFromProvider = (providerName) => {
- switch (providerName) {
- case "aws":
- return ;
- case "google":
- return ;
- case "azure":
- return ;
- case "ovh":
- return ;
- default:
- throw Error(`invalid provider type`);
- }
- };
- const wizardDefs = [
- {
- name: "ProviderSelection",
- header: () => {tr.t("Select Provider")} ,
- content: () => ,
- enter: async () => {
- providerSelectionStore.setProvider("");
- },
- },
- {
- name: "Import",
- header: observer(() => ),
- content: ({}) => (
-
- ),
- enter: async () => {
- importProjectStore.project = {};
- },
- },
- {
- name: "Settings",
- header: observer(() => ),
- content: ({}) => (
-
- ),
- enter: async () => {
- infraSettingsStore.data.name = importProjectStore.project.title;
- },
- },
- {
- name: "GitCredential",
- header: observer(() => ),
- content: observer(({}) =>
- gitCredentialStore.opGetAll.loading ? (
-
- ) : (
-
- )
- ),
- enter: async () => {
- gitCredentialStore.getAll();
- },
- },
- {
- name: "GitRepository",
- header: observer(() => ),
- content: ({}) => ,
- },
- {
- name: "Configuration",
- header: observer(() => ),
- content: ({}) =>
- configViewFromProvider(providerSelectionStore.data.providerName),
- },
- ];
-
- const Wizard = wizard(context, { wizardDefs });
-
- //TODO only for testing
- const testWorkflow = async () => {
- providerSelectionStore.selectProvider({ providerName: "aws" });
- importProjectStore.showNewProjectFromTemplate(true);
- importProjectStore.onSelectProject({
- title: "EKS",
- description: "Deploy a kubernetes cluster with EKS",
- url: "https://github.com/grucloud/grucloud/",
- branch: "main",
- directory: "packages/modules/aws/eks/example",
- });
-
- infraSettingsStore.save({ data: { name: "EKS infra", stage: "dev" } });
- await gitCredentialStore.getAll();
- gitCredentialStore.setData({
- username: "TODO",
- password: "xxxxxx",
- });
- gitCredentialStore.save();
- gitRepositoryStore.setData({
- url: "https://github.com/FredericHeem/grucloud-aws-demo.git",
- branch: "master",
- });
- // gitRepositoryStore.save();
- };
- //testWorkflow();
-
- return observer(function WizardView() {
- return (
-
-
-
- );
- });
-};
diff --git a/client/src/app_infra/menuItems.ts b/client/src/app_infra/menuItems.ts
deleted file mode 100644
index dfd5f80c..00000000
--- a/client/src/app_infra/menuItems.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { createElement as h } from "react";
-import { BiLogOutCircle } from "react-icons/bi";
-import { CgProfile,CgCloud } from "react-icons/cg";
-
-export default () => [
- {
- route: "/infra",
- text: "INFRA",
- icon: h(CgCloud),
- },
- {
- route: "/profile",
- text: "PROFILE",
- icon: h(CgProfile),
- },
- {
- route: "/auth/logout",
- text: "LOGOUT",
- icon: h(BiLogOutCircle),
- },
-];
diff --git a/client/src/app_infra/profile/components/profileForm.js b/client/src/app_infra/profile/components/profileForm.js
deleted file mode 100644
index e1d4d855..00000000
--- a/client/src/app_infra/profile/components/profileForm.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { jsx, css } from "@emotion/react";
-import { createElement as h } from "react";
-import { toJS } from "mobx";
-import { observer } from "mobx-react";
-
-import input from "mdlean/lib/input";
-import button from "mdlean/lib/button";
-import formGroup from "mdlean/lib/formGroup";
-
-import spinner from "mdlean/lib/spinner";
-import paper from "components/Paper";
-
-export default (context) => {
- const { tr, history } = context;
- const FormGroup = formGroup(context);
- const Paper = paper(context);
- const Button = button(context, {
- cssOverride: css`
- width: 256px;
- `,
- });
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 256px;
- }
- `,
- });
-
- const UserDeleteLink = observer(({ store }) => (
-
- {
- history.push(`profile/delete`, toJS(store.data));
- }}
- >
- Danger zone...
-
-
- ));
-
- return observer(function ProfileForm({ store }) {
- const { errors } = store;
- if (store.opGet.loading) {
- return h(spinner(context));
- }
- return (
-
-
-
- );
- });
-};
diff --git a/client/src/app_infra/profile/profileModule.js b/client/src/app_infra/profile/profileModule.js
deleted file mode 100644
index d3451102..00000000
--- a/client/src/app_infra/profile/profileModule.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import { observable, action } from "mobx";
-import React, { createElement as h } from "react";
-import validate from "validate.js";
-import rules from "utils/rules";
-import AsyncOp from "mdlean/lib/utils/asyncOp";
-import alert from "mdlean/lib/alert";
-import profileView from "./views/profileView";
-import userDeleteView from "./userDeleteView";
-
-export default function (context) {
- const { rest, tr, config } = context;
- const asyncOpCreate = AsyncOp(context);
- const Alert = alert(context);
- function Routes(stores) {
- return [
- {
- path: "",
- protected: true,
- action: (routerContext) => {
- stores.profile.get();
- return {
- routerContext,
- title: "My Profile",
- component: h(profileView(context), { store: stores.profile }),
- };
- },
- },
- {
- path: "/delete",
- protected: true,
- action: (routerContext) => {
- return {
- routerContext,
- title: "Delete Profile",
- component: h(userDeleteView(context), { store: stores.userDelete }),
- };
- },
- },
- ];
- }
-
- function merge(profile, response) {
- profile.username = response.username;
- profile.email = response.email;
- profile.profile = response.profile || { biography: "" };
- profile.picture = response.picture;
- }
-
- function Stores() {
- const profileStore = observable({
- language: "US",
- errors: {},
- username: "",
- email: "",
- picture: null,
- profile: {
- biography: "",
- },
- opGet: asyncOpCreate(() => rest.get("me")),
- get: action(async function () {
- const response = await this.opGet.fetch();
- merge(profileStore, response);
- }),
- opUpdate: asyncOpCreate((payload) => rest.patch("me", payload)),
- update: action(async function () {
- this.errors = {};
- const payload = {
- biography: this.profile.biography || "",
- };
- const constraints = {
- biography: rules.biography,
- };
- const vErrors = validate(payload, constraints);
- if (vErrors) {
- this.errors = vErrors;
- return;
- }
- const response = await this.opUpdate.fetch(payload);
- merge(profileStore, response);
- context.alertStack.add(
-
- );
- }) /*,
- uploadPicture: action(async event => {
- const data = new FormData();
- const file = event.target.files[0];
- data.append("file", file);
- data.append("name", file.name);
- data.append("file-type", file.type);
- data.append("category", "profile-picture");
- try {
- await rest.upload("document/profile_picture", data);
- context.alertStack.add(
-
- );
- } catch (error) {
- console.error("uploadPicture ", error);
- context.alertStack.add(
-
- );
- }
- })*/,
- });
- const userDeleteStore = observable({
- input: "",
- setInput: (input) => {
- userDeleteStore.input = input;
- },
- opDestroy: asyncOpCreate(() => rest.del("me")),
- destroy: action(async () => {
- const response = await userDeleteStore.opDestroy.fetch();
- context.alertStack.add(
-
- );
- context.history.push(config.loginPath);
- }),
-
- get nameMatch() {
- return userDeleteStore.input === "delete";
- },
- });
- return {
- profile: profileStore,
- userDelete: userDeleteStore,
- };
- }
-
- const stores = Stores(context);
-
- return {
- stores: () => stores,
- routes: () => Routes(stores),
- };
-}
diff --git a/client/src/app_infra/profile/userDeleteView.js b/client/src/app_infra/profile/userDeleteView.js
deleted file mode 100644
index 7b67b8b6..00000000
--- a/client/src/app_infra/profile/userDeleteView.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/* @jsxImportSource @emotion/react */
-import { jsx, css } from "@emotion/react";
-import { observer } from "mobx-react";
-
-import input from "mdlean/lib/input";
-import button from "mdlean/lib/button";
-import form from "mdlean/lib/form";
-import formGroup from "mdlean/lib/formGroup";
-
-import paper from "components/Paper";
-
-export default (context) => {
- const { tr, history } = context;
- const FormGroup = formGroup(context);
- const Paper = paper(context);
- const Form = form(context);
- const Button = button(context, {
- cssOverride: css`
- width: 256px;
- `,
- });
-
- const Input = input(context, {
- cssOverride: css`
- > input {
- width: 256px;
- }
- `,
- });
-
- return observer(function UserDeleteForm({ store }) {
- return (
-
- );
- });
-};
diff --git a/client/src/app_infra/profile/views/profileView.js b/client/src/app_infra/profile/views/profileView.js
deleted file mode 100644
index 50b6d3e0..00000000
--- a/client/src/app_infra/profile/views/profileView.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from "react";
-import page from "components/Page";
-import profileForm from "../components/profileForm";
-
-export default context => {
- const Page = page(context);
- const ProfileForm = profileForm(context);
- function ProfileView(props) {
- return (
-
-
-
- );
- }
- return ProfileView;
-};
diff --git a/client/src/app_infra/routes.js b/client/src/app_infra/routes.js
deleted file mode 100644
index 30812001..00000000
--- a/client/src/app_infra/routes.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { createPart } from "../router";
-import Layout from "./LayoutUnauthenticated";
-
-export default ({ context }) => [
- {
- path: "",
- children: [
- {
- path: "/infra",
- children: [],
- action: async (routerContext) =>
- createPart({
- name: "infra",
- context,
- partCreate: await import("./infra/infraModule"),
- routerContext,
- }),
- },
- {
- path: "/profile",
- children: [],
- action: async (routerContext) =>
- createPart({
- name: "profile",
- context,
- partCreate: await import("./profile/profileModule"),
- routerContext,
- }),
- },
- {
- path: "/auth",
- children: [],
- action: async (routerContext) =>
- createPart({
- name: "auth",
- context,
- partCreate: await import("parts/auth/authModule"),
- routerContext,
- partParam: { Layout },
- }),
- },
- ],
- },
-];
diff --git a/client/src/app_infra/test/app.spec.js b/client/src/app_infra/test/app.spec.js
deleted file mode 100644
index 86175fc9..00000000
--- a/client/src/app_infra/test/app.spec.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { assert } from "chai";
-import App from "../UserApp";
-
-describe("App", function() {
- let app;
- before(async () => {
- app = await App();
- })
-
- it("1 parts", async () => {
- assert(true)
- });
-});
diff --git a/client/src/app_infra/test/router.spec.js b/client/src/app_infra/test/router.spec.js
deleted file mode 100644
index 7bebe66b..00000000
--- a/client/src/app_infra/test/router.spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import chai from "chai";
-import chaiAsPromised from "chai-as-promised";
-import UserApp from "../UserApp";
-
-chai.use(chaiAsPromised);
-const { expect, assert } = chai;
-
-describe("Router", function() {
- let app;
- let router;
- before(async () => {
- app = await UserApp();
- router = app.router
- })
- it("/login", async () => {
- const route = await router.instance.resolve("/auth/login");
- assert(route);
- assert(route.component)
- assert.equal(route.title, "Login");
- });
- it("/app/profile not authenticated", async () => {
- expect(router.instance.resolve("/profile")).to.be.rejectedWith(Error);
- });
-});
diff --git a/client/src/app_public/landing/content.js b/client/src/app_public/landing/content.js
index db6c77a4..20e387f9 100644
--- a/client/src/app_public/landing/content.js
+++ b/client/src/app_public/landing/content.js
@@ -3,15 +3,13 @@ export default () => ({
{
img: require("./img/stack.svg").default,
title: "Full Stack",
- text:
- "A complete frontend, backend and deployment solution to bootstrap your application",
+ text: "A complete frontend, backend and deployment solution to bootstrap your application",
height: "100",
},
{
img: require("./img/users.svg").default,
title: "Authentication",
- text:
- "Account registration with username and password, or with identity provider such as Google, Facebook, Twitter, GitHub etc ..",
+ text: "Account registration with username and password, or with identity provider such as Google, Facebook, Twitter, GitHub etc ..",
height: "100",
},
{
@@ -23,8 +21,7 @@ export default () => ({
{
img: require("./img/database.svg").default,
title: "Relational SQL Database",
- text:
- "The data are modeled with sequelize, an ORM which support PostgreSQL, MySQL, MariaDB, SQLite and MSSQL",
+ text: "The data are modeled with sequelize, an ORM which support PostgreSQL, MySQL, MariaDB, SQLite and MSSQL",
height: "100",
},
],
@@ -66,21 +63,12 @@ export default () => ({
link: "https://nodejs.org",
text: "A scalable javascript application server.",
},
- {
- img: require("./img/sequelize.svg").default,
- height: "120",
- title: "Sequelize",
- link: "http://docs.sequelizejs.com/en/latest/",
- text:
- "Sequelize is a promise-based ORM for Node.js and io.js. It supports the dialects PostgreSQL, MySQL, MariaDB, SQLite and MSSQL",
- },
{
img: require("./img/passportjs.png").default,
title: "Passportjs",
width: "64",
link: "http://passportjs.org/",
- text:
- "Simple, unobtrusive authentication for Node.js, supports more than 300 authentication stragegies such as username and password, Facebook, google etc ...",
+ text: "Simple, unobtrusive authentication for Node.js, supports more than 300 authentication stragegies such as username and password, Facebook, google etc ...",
},
],
tools: [
@@ -89,8 +77,7 @@ export default () => ({
title: "ESLint",
height: "120",
link: "http://eslint.org/",
- text:
- "The pluggable linting utility for JavaScript and JSX, find errors and coding style violation.",
+ text: "The pluggable linting utility for JavaScript and JSX, find errors and coding style violation.",
},
{
img: require("./img/mocha.svg").default,
@@ -103,38 +90,21 @@ export default () => ({
img: require("./img/nightwatch.png").default,
title: "Nightwatch",
link: "http://nightwatchjs.org/",
- text:
- "Write End-to-End tests in Node.js quickly and effortlessly that run against a Selenium server.",
+ text: "Write End-to-End tests in Node.js quickly and effortlessly that run against a Selenium server.",
},
{
img: require("./img/webpack.svg").default,
title: "Webpack",
height: "160",
link: "http://webpack.github.io/docs/",
- text:
- "A bundler for javascript and friends. Packs many modules into a few bundled assets.",
- },
- {
- img: require("./img/nodemon.svg").default,
- title: "Nodemon",
- height: "160",
- link: "http://nodemon.io/",
- text:
- "Monitors for any changes in your node.js application and automatically restart the server",
- },
- {
- img: require("./img/travis.png").default,
- title: "Travis CI",
- height: "160",
- link: "https://travis-ci.org/",
- text: "A continuous integration platform.",
+ text: "A bundler for javascript and friends. Packs many modules into a few bundled assets.",
},
+
{
img: require("./img/raml.png").default,
title: "RAML",
link: "http://raml.org",
- text:
- "RESTful API Modeling Language, model your API, generate html documentation, mock server for frontend, ensure the backend implements the API",
+ text: "RESTful API Modeling Language, model your API, generate html documentation, mock server for frontend, ensure the backend implements the API",
},
{
@@ -155,8 +125,7 @@ export default () => ({
img: require("./img/docker.png").default,
title: "Docker",
link: "https://www.docker.com/",
- text:
- "An open platform for distributed applications for developers and sysadmins",
+ text: "An open platform for distributed applications for developers and sysadmins",
},
],
});
diff --git a/client/webpack.config.js b/client/webpack.config.js
index 33f963c4..bac590ea 100644
--- a/client/webpack.config.js
+++ b/client/webpack.config.js
@@ -22,7 +22,6 @@ module.exports = function (options) {
{ from: /^\/user/, to: "/user/index.html" },
{ from: /^\/admin/, to: "/admin/index.html" },
{ from: /^\/public/, to: "/public/index.html" },
- { from: /^\/infra/, to: "/infra/index.html" },
],
},
proxy: {
@@ -63,13 +62,6 @@ module.exports = function (options) {
chunks: ["admin"],
filename: "admin/index.html",
}),
- new HtmlWebpackPlugin({
- template: "src/index.ejs",
- title: pkg.title,
- chunks: ["infra"],
- filename: "infra/index.html",
- }),
-
new webpack.DefinePlugin({
__VERSION__: JSON.stringify(pkg.version),
}),
diff --git a/client/webpack.dev.js b/client/webpack.dev.js
index d199872c..7dcfb3a4 100644
--- a/client/webpack.dev.js
+++ b/client/webpack.dev.js
@@ -11,7 +11,6 @@ const webpackDevConfig = {
public: ["./src/app_public/index.js"],
user: ["./src/app_user/index.js"],
admin: ["./src/app_admin/index.js"],
- infra: ["./src/app_infra/index.js"],
},
},
diff --git a/client/webpack.prod.js b/client/webpack.prod.js
index 9df8283c..7fe314d0 100644
--- a/client/webpack.prod.js
+++ b/client/webpack.prod.js
@@ -14,7 +14,6 @@ const webpackProdConfig = {
public: ["./src/app_public/index.js"],
user: ["./src/app_user/index.js"],
admin: ["./src/app_admin/index.js"],
- infra: ["./src/app_infra/index.js"],
},
output: {
path: path.join(__dirname, "dist"),
diff --git a/server/src/plugins/cloudDiagram/api/gitCredentialApi.js b/server/src/plugins/cloudDiagram/api/gitCredentialApi.js
deleted file mode 100644
index b155f75e..00000000
--- a/server/src/plugins/cloudDiagram/api/gitCredentialApi.js
+++ /dev/null
@@ -1,135 +0,0 @@
-const assert = require("assert");
-const { switchCase, fork, pipe, tap, get, assign } = require("rubico");
-const { isEmpty } = require("rubico/x");
-const { contextSet404, contextSetOk } = require("utils/koaCommon");
-
-const { middlewareUserBelongsToOrg } = require("../middleware");
-
-const gitCredentialAttribute = [
- "provider",
- "auth_type",
- "org_id",
- "git_credential_id",
- "username",
- "password",
-];
-
-const buildWhereFromContext = pipe([
- tap((context) => {
- assert(context);
- }),
- fork({
- org_id: pipe([get("params.org_id")]),
- git_credential_id: pipe([get("params.git_credential_id")]),
- }),
- tap(({ org_id, git_credential_id }) => {
- assert(org_id);
- // assert(git_credential_id);
- }),
-]);
-
-exports.GitCredentialApi = ({ app, models }) => {
- assert(models);
- return {
- pathname: "/org/:org_id/git_credential",
- middlewares: [
- app.server.auth.isAuthenticated, //
- middlewareUserBelongsToOrg(models),
- ],
- ops: [
- {
- pathname: "/",
- method: "post",
- handler: (context) =>
- pipe([
- tap(() => {
- assert(context.request.body);
- assert(context.state.user.user_id);
- }),
- () => context.request.body,
- assign({ org_id: () => context.params.org_id }),
- models.gitCredential.insert,
- tap((param) => {
- assert(true);
- }),
- contextSetOk({ context }),
- ])(),
- },
- {
- pathname: "/",
- method: "get",
- handler: (context) =>
- pipe([
- () => ({
- attributes: gitCredentialAttribute,
- where: {
- org_id: context.params.org_id,
- },
- }),
- models.gitCredential.findAll,
- tap((param) => {
- assert(true);
- }),
- contextSetOk({ context }),
- ])(),
- },
- {
- pathname: "/:git_credential_id",
- method: "get",
- handler: (context) =>
- pipe([
- tap(() => {
- assert(context.params.org_id);
- assert(context.params.git_credential_id);
- assert(context.state.user.user_id);
- }),
- () => ({
- attributes: gitCredentialAttribute,
- where: buildWhereFromContext(context),
- }),
- models.gitCredential.findOne,
- tap((param) => {
- assert(true);
- }),
- switchCase([
- isEmpty,
- tap(contextSet404({ context })),
- tap(contextSetOk({ context })),
- ]),
- ])(),
- },
- {
- pathname: "/:git_credential_id",
- method: "delete",
- handler: (context) =>
- pipe([
- () => ({
- where: buildWhereFromContext(context),
- }),
- models.gitCredential.destroy,
- () => {
- context.status = 204;
- },
- ])(),
- },
- {
- pathname: "/:git_credential_id",
- method: "patch",
- handler: (context) =>
- pipe([
- () => ({
- data: context.request.body,
- where: buildWhereFromContext(context),
- }),
- models.gitCredential.update,
- () => ({
- attributes: gitCredentialAttribute,
- where: buildWhereFromContext(context),
- }),
- models.gitCredential.findOne,
- contextSetOk({ context }),
- ])(),
- },
- ],
- };
-};
diff --git a/server/src/plugins/cloudDiagram/api/gitRepositoryApi.js b/server/src/plugins/cloudDiagram/api/gitRepositoryApi.js
deleted file mode 100644
index 7570e724..00000000
--- a/server/src/plugins/cloudDiagram/api/gitRepositoryApi.js
+++ /dev/null
@@ -1,128 +0,0 @@
-const assert = require("assert");
-const { switchCase, fork, pipe, tap, get, assign } = require("rubico");
-const { isEmpty } = require("rubico/x");
-const { contextSet404, contextSetOk } = require("utils/koaCommon");
-
-const { middlewareUserBelongsToOrg } = require("../middleware");
-
-const gitRepositoryAttributes = [
- "org_id",
- "project_id",
- "git_credential_id",
- "repository_url",
- "branch",
- "working_directory",
-];
-
-const buildWhereFromContext = pipe([
- tap((context) => {
- assert(context);
- }),
- fork({
- org_id: pipe([get("params.org_id")]),
- project_id: pipe([get("params.project_id")]),
- workspace_id: pipe([get("params.workspace_id")]),
- }),
- tap(({ org_id, project_id, workspace_id }) => {
- assert(org_id);
- assert(project_id);
- assert(workspace_id);
- }),
-]);
-
-exports.GitRepositoryApi = ({ app, models }) => {
- assert(models.gitRepository);
- return {
- pathname:
- "/org/:org_id/project/:project_id/workspace/:workspace_id/git_repository",
- middlewares: [
- app.server.auth.isAuthenticated, //
- middlewareUserBelongsToOrg(models),
- ],
- ops: [
- {
- pathname: "/",
- method: "post",
- handler: (context) =>
- pipe([
- tap(() => {
- assert(context.request.body);
- assert(context.state.user.user_id);
- assert(context.params.org_id);
- assert(context.params.project_id);
- assert(context.params.workspace_id);
- }),
- () => context.request.body,
- assign({
- org_id: () => context.params.org_id,
- project_id: () => context.params.project_id,
- workspace_id: () => context.params.workspace_id,
- }),
- models.gitRepository.insert,
- tap((param) => {
- assert(true);
- }),
- contextSetOk({ context }),
- ])(),
- },
- {
- pathname: "/",
- method: "get",
- handler: (context) =>
- pipe([
- tap(() => {
- assert(context.params.org_id);
- assert(context.params.project_id);
- assert(context.params.workspace_id);
- assert(context.state.user.user_id);
- }),
- () => ({
- attributes: gitRepositoryAttributes,
- where: buildWhereFromContext(context),
- }),
- models.gitRepository.findOne,
- tap((param) => {
- assert(true);
- }),
- switchCase([
- isEmpty,
- tap(contextSetOk({ context })),
- tap(contextSetOk({ context })),
- ]),
- ])(),
- },
- {
- pathname: "/",
- method: "delete",
- handler: (context) =>
- pipe([
- () => ({
- where: buildWhereFromContext(context),
- }),
- models.gitRepository.destroy,
- () => {
- context.status = 204;
- },
- ])(),
- },
- {
- pathname: "/",
- method: "patch",
- handler: (context) =>
- pipe([
- () => ({
- data: context.request.body,
- where: buildWhereFromContext(context),
- }),
- models.gitRepository.update,
- () => ({
- attributes: gitRepositoryAttributes,
- where: buildWhereFromContext(context),
- }),
- models.gitRepository.findOne,
- contextSetOk({ context }),
- ])(),
- },
- ],
- };
-};
diff --git a/server/src/plugins/cloudDiagram/api/infraApi.js b/server/src/plugins/cloudDiagram/api/infraApi.js
index a9da5d0e..a3931288 100644
--- a/server/src/plugins/cloudDiagram/api/infraApi.js
+++ b/server/src/plugins/cloudDiagram/api/infraApi.js
@@ -1,134 +1,134 @@
-const assert = require("assert");
-const path = require("path");
-const { pipe, tap, switchCase, map } = require("rubico");
-const { isEmpty, callProp, defaultsDeep } = require("rubico/x");
-const fs = require("fs");
-const pfs = fs.promises;
-const os = require("os");
-const { gitPush } = require("../gitUtils");
-const { createRestApiByUser } = require("../apiFactory");
+// const assert = require("assert");
+// const path = require("path");
+// const { pipe, tap, switchCase, map } = require("rubico");
+// const { isEmpty, callProp, defaultsDeep } = require("rubico/x");
+// const fs = require("fs");
+// const pfs = fs.promises;
+// const os = require("os");
+// const { gitPush } = require("../gitUtils");
+// const { createRestApiByUser } = require("../apiFactory");
-const infraFindOne = ({ models }) =>
- pipe([
- ({ id }) =>
- models.Infra.findOne({
- include: [
- {
- model: models.Job,
- limit: 1,
- order: [["created_at", "DESC"]],
- },
- {
- model: models.GitCredential,
- as: "gitCredential",
- },
- {
- model: models.GitRepository,
- as: "gitRepository",
- },
- {
- model: models.User,
- as: "user",
- },
- ],
- where: {
- id,
- },
- }),
- switchCase([isEmpty, () => undefined, callProp("toJSON")]),
- ]);
+// const infraFindOne = ({ models }) =>
+// pipe([
+// ({ id }) =>
+// models.Infra.findOne({
+// include: [
+// {
+// model: models.Job,
+// limit: 1,
+// order: [["created_at", "DESC"]],
+// },
+// {
+// model: models.GitCredential,
+// as: "gitCredential",
+// },
+// {
+// model: models.GitRepository,
+// as: "gitRepository",
+// },
+// {
+// model: models.User,
+// as: "user",
+// },
+// ],
+// where: {
+// id,
+// },
+// }),
+// switchCase([isEmpty, () => undefined, callProp("toJSON")]),
+// ]);
-exports.infraFindOne = infraFindOne;
+// exports.infraFindOne = infraFindOne;
-const InfraApi = ({ models, model, log }) => ({
- findOne: infraFindOne({ models }),
- findAll: ({ user_id }) =>
- pipe([
- () =>
- model.findAll({
- include: [
- {
- model: models.Job,
- limit: 1,
- order: [["created_at", "DESC"]],
- },
- {
- model: models.GitCredential,
- as: "gitCredential",
- },
- {
- model: models.GitRepository,
- as: "gitRepository",
- },
- {
- model: models.User,
- as: "user",
- },
- ],
- where: {
- user_id,
- },
- }),
- map(callProp("toJSON")),
- tap((xxx) => {
- assert(true);
- }),
- ])(),
- create: ({ data }) =>
- pipe([
- () => model.create(data),
- tap((xxx) => {
- assert(true);
- }),
- callProp("toJSON"),
- tap((param) => {
- log.debug(`created infra result: ${JSON.stringify(param, null, 4)}`);
- }),
- ({ id }) => infraFindOne({ models })({ id }),
- tap((param) => {
- log.debug(`created infraFindOne: ${JSON.stringify(param, null, 4)}`);
- }),
- tap(async (infra) =>
- gitPush({
- infra,
- dirTemplate: await path.join(
- os.tmpdir(),
- "grucloud-example-template"
- ),
- dir: await pfs.mkdtemp(path.join(os.tmpdir(), "grucloud-template")),
- message: "new infra project",
- })
- ),
- ])(),
- patch: ({ id, data }) =>
- pipe([
- () => infraFindOne({ models })({ id }),
- (current) => defaultsDeep(current)(data),
- tap((merged) =>
- model.update(merged, {
- where: {
- id,
- },
- })
- ),
- () => infraFindOne({ models })({ id }),
- tap((param) => {
- log.debug(`created infraFindOne: ${JSON.stringify(param, null, 4)}`);
- }),
- ])(),
- destroy: ({ id }) =>
- pipe([
- () =>
- model.destroy({
- where: {
- id,
- },
- }),
- ])(),
-});
+// const InfraApi = ({ models, model, log }) => ({
+// findOne: infraFindOne({ models }),
+// findAll: ({ user_id }) =>
+// pipe([
+// () =>
+// model.findAll({
+// include: [
+// {
+// model: models.Job,
+// limit: 1,
+// order: [["created_at", "DESC"]],
+// },
+// {
+// model: models.GitCredential,
+// as: "gitCredential",
+// },
+// {
+// model: models.GitRepository,
+// as: "gitRepository",
+// },
+// {
+// model: models.User,
+// as: "user",
+// },
+// ],
+// where: {
+// user_id,
+// },
+// }),
+// map(callProp("toJSON")),
+// tap((xxx) => {
+// assert(true);
+// }),
+// ])(),
+// create: ({ data }) =>
+// pipe([
+// () => model.create(data),
+// tap((xxx) => {
+// assert(true);
+// }),
+// callProp("toJSON"),
+// tap((param) => {
+// log.debug(`created infra result: ${JSON.stringify(param, null, 4)}`);
+// }),
+// ({ id }) => infraFindOne({ models })({ id }),
+// tap((param) => {
+// log.debug(`created infraFindOne: ${JSON.stringify(param, null, 4)}`);
+// }),
+// tap(async (infra) =>
+// gitPush({
+// infra,
+// dirTemplate: await path.join(
+// os.tmpdir(),
+// "grucloud-example-template"
+// ),
+// dir: await pfs.mkdtemp(path.join(os.tmpdir(), "grucloud-template")),
+// message: "new infra project",
+// })
+// ),
+// ])(),
+// patch: ({ id, data }) =>
+// pipe([
+// () => infraFindOne({ models })({ id }),
+// (current) => defaultsDeep(current)(data),
+// tap((merged) =>
+// model.update(merged, {
+// where: {
+// id,
+// },
+// })
+// ),
+// () => infraFindOne({ models })({ id }),
+// tap((param) => {
+// log.debug(`created infraFindOne: ${JSON.stringify(param, null, 4)}`);
+// }),
+// ])(),
+// destroy: ({ id }) =>
+// pipe([
+// () =>
+// model.destroy({
+// where: {
+// id,
+// },
+// }),
+// ])(),
+// });
-exports.InfraRestApi = ({ app, models }) => {
- const log = require("logfilename")(__filename);
- const api = InfraApi({ model: models.Infra, models, log });
- return createRestApiByUser({ pathname: "infra", api, app });
-};
+// exports.InfraRestApi = ({ app, models }) => {
+// const log = require("logfilename")(__filename);
+// const api = InfraApi({ model: models.Infra, models, log });
+// return createRestApiByUser({ pathname: "infra", api, app });
+// };
diff --git a/server/src/plugins/cloudDiagram/api/infraPushCodeApi.js b/server/src/plugins/cloudDiagram/api/infraPushCodeApi.js
index cca6916e..7e3053eb 100644
--- a/server/src/plugins/cloudDiagram/api/infraPushCodeApi.js
+++ b/server/src/plugins/cloudDiagram/api/infraPushCodeApi.js
@@ -1,85 +1,85 @@
-const assert = require("assert");
-const path = require("path");
-const { pipe, tap, tryCatch, switchCase, eq, get, or } = require("rubico");
-const uuid = require("uuid");
-const fs = require("fs");
-const pfs = fs.promises;
-const os = require("os");
+// const assert = require("assert");
+// const path = require("path");
+// const { pipe, tap, tryCatch, switchCase, eq, get, or } = require("rubico");
+// const uuid = require("uuid");
+// const fs = require("fs");
+// const pfs = fs.promises;
+// const os = require("os");
-const { contextSet400, contextSetOk } = require("utils/koaCommon");
-const { gitPush } = require("../gitUtils");
-const { infraFindOne } = require("./infraApi");
+// const { contextSet400, contextSetOk } = require("utils/koaCommon");
+// const { gitPush } = require("../gitUtils");
+// const { infraFindOne } = require("./infraApi");
-const InfraPushCodeApi = ({ models, log }) => ({
- create: ({ id }) =>
- pipe([
- () => infraFindOne({ models })({ id }),
- tap((infra) => {
- log.debug(`InfraPushCodeApi: ${JSON.stringify({ infra }, null, 4)}`);
- }),
- tap(async (infra) =>
- gitPush({
- infra,
- dirTemplate: await path.join(
- os.tmpdir(),
- "grucloud-example-template"
- ),
- dir: await pfs.mkdtemp(path.join(os.tmpdir(), "grucloud-user-dir")),
- message: "new infra project",
- })
- ),
- ])(),
-});
+// const InfraPushCodeApi = ({ models, log }) => ({
+// create: ({ id }) =>
+// pipe([
+// () => infraFindOne({ models })({ id }),
+// tap((infra) => {
+// log.debug(`InfraPushCodeApi: ${JSON.stringify({ infra }, null, 4)}`);
+// }),
+// tap(async (infra) =>
+// gitPush({
+// infra,
+// dirTemplate: await path.join(
+// os.tmpdir(),
+// "grucloud-example-template"
+// ),
+// dir: await pfs.mkdtemp(path.join(os.tmpdir(), "grucloud-user-dir")),
+// message: "new infra project",
+// })
+// ),
+// ])(),
+// });
-exports.InfraPushCodeRestApi = ({ app, models }) => {
- const log = require("logfilename")(__filename);
- const api = InfraPushCodeApi({ model: models.Infra, models, log });
- const apiSpec = {
- pathname: "/infra",
- middlewares: [
- app.server.auth.isAuthenticated /*,app.server.auth.isAuthorized*/,
- ],
- ops: [
- {
- pathname: "/:id/push_code",
- method: "post",
- handler: (context) =>
- tryCatch(
- pipe([
- tap(() => {
- assert(context.params.id);
- assert(context.state.user.user_id);
- }),
- switchCase([
- () => uuid.validate(context.params.id),
- // valid id
- pipe([
- () =>
- api.create({
- id: context.params.id,
- data: context.request.body,
- }),
- tap(contextSetOk({ context })),
- ]),
- // invalid uuid
- contextSet400({ context, message: "invalid uuid" }),
- ]),
- ]),
- (error) =>
- pipe([
- tap(() => {
- console.error(error);
- }),
- () => {
- context.status = 422;
- context.body = { ...error, message: error.toString() };
- },
- ])()
- )(),
- },
- ],
- };
+// exports.InfraPushCodeRestApi = ({ app, models }) => {
+// const log = require("logfilename")(__filename);
+// const api = InfraPushCodeApi({ model: models.Infra, models, log });
+// const apiSpec = {
+// pathname: "/infra",
+// middlewares: [
+// app.server.auth.isAuthenticated /*,app.server.auth.isAuthorized*/,
+// ],
+// ops: [
+// {
+// pathname: "/:id/push_code",
+// method: "post",
+// handler: (context) =>
+// tryCatch(
+// pipe([
+// tap(() => {
+// assert(context.params.id);
+// assert(context.state.user.user_id);
+// }),
+// switchCase([
+// () => uuid.validate(context.params.id),
+// // valid id
+// pipe([
+// () =>
+// api.create({
+// id: context.params.id,
+// data: context.request.body,
+// }),
+// tap(contextSetOk({ context })),
+// ]),
+// // invalid uuid
+// contextSet400({ context, message: "invalid uuid" }),
+// ]),
+// ]),
+// (error) =>
+// pipe([
+// tap(() => {
+// console.error(error);
+// }),
+// () => {
+// context.status = 422;
+// context.body = { ...error, message: error.toString() };
+// },
+// ])()
+// )(),
+// },
+// ],
+// };
- app.server.createRouter(apiSpec);
- return { api: apiSpec };
-};
+// app.server.createRouter(apiSpec);
+// return { api: apiSpec };
+// };
diff --git a/server/src/plugins/cloudDiagram/api/projectApi.js b/server/src/plugins/cloudDiagram/api/projectApi.js
index 1c6e9f28..00aad193 100644
--- a/server/src/plugins/cloudDiagram/api/projectApi.js
+++ b/server/src/plugins/cloudDiagram/api/projectApi.js
@@ -5,6 +5,21 @@ const { contextSet404, contextSetOk } = require("utils/koaCommon");
const { middlewareUserBelongsToOrg } = require("../middleware");
+const projectAttributes = [
+ "org_id",
+ "project_id",
+ "project_name",
+ "project_description",
+ "options",
+ "git_provider_type",
+ "git_auth_type",
+ "username",
+ "password",
+ "repository_url",
+ "branch",
+ "working_directory",
+];
+
const buildWhereFromContext = pipe([
tap((context) => {
assert(context);
@@ -52,7 +67,6 @@ exports.ProjectApi = ({ app, models }) => {
handler: (context) =>
pipe([
() => ({
- //attributes: ["org_id", "project_id", "project_name"],
where: {
org_id: context.params.org_id,
user_id: context.state.user.user_id,
@@ -76,7 +90,7 @@ exports.ProjectApi = ({ app, models }) => {
assert(context.state.user.user_id);
}),
() => ({
- attributes: ["org_id", "project_id", "project_name"],
+ attributes: projectAttributes,
where: buildWhereFromContext(context),
}),
models.project.findOne,
@@ -115,7 +129,7 @@ exports.ProjectApi = ({ app, models }) => {
}),
models.project.update,
() => ({
- attributes: ["project_name", "org_id", "project_id"],
+ attributes: projectAttributes,
where: buildWhereFromContext(context),
}),
models.project.findOne,
diff --git a/server/src/plugins/cloudDiagram/index.js b/server/src/plugins/cloudDiagram/index.js
index ea0049d0..a5576804 100644
--- a/server/src/plugins/cloudDiagram/index.js
+++ b/server/src/plugins/cloudDiagram/index.js
@@ -6,10 +6,8 @@ const { DockerClient } = require("@grucloud/docker-axios");
const { GetAllApi } = require("./api/getAllApi");
const { OrgApi } = require("./api/orgApi");
-const { GitCredentialApi } = require("./api/gitCredentialApi");
const { ProjectApi } = require("./api/projectApi");
const { WorkspaceApi } = require("./api/workspaceApi");
-const { GitRepositoryApi } = require("./api/gitRepositoryApi");
const { CloudAuthenticationApi } = require("./api/cloudAuthenticationApi");
const { RunApi } = require("./api/runApi");
const { DockerGcRun } = require("./utils/rungc");
@@ -83,9 +81,7 @@ module.exports = (app) => {
org: sqlAdaptor(require("./sql/OrganisationSql")({ sql })),
project: sqlAdaptor(require("./sql/ProjectSql")({ sql })),
workspace: sqlAdaptor(require("./sql/WorkspaceSql")({ sql })),
- gitRepository: sqlAdaptor(require("./sql/GitRepositorySql")({ sql })),
userOrg: sqlAdaptor(require("./sql/UserOrgSql")({ sql })),
- gitCredential: sqlAdaptor(require("./sql/GitCredentialSql")({ sql })),
run: sqlAdaptor(require("./sql/RunSql")({ sql })),
cloudAuthentication: sqlAdaptor(
require("./sql/CloudAuthenticationSql")({ sql })
@@ -205,10 +201,8 @@ module.exports = (app) => {
[
GetAllApi,
OrgApi,
- GitCredentialApi,
ProjectApi,
WorkspaceApi,
- GitRepositoryApi,
RunApi,
CloudAuthenticationApi,
].forEach((api) => app.server.createRouter(api({ app, models })));
diff --git a/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql b/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
index 00c3df2a..350b7ee9 100644
--- a/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
+++ b/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
@@ -16,28 +16,22 @@ CREATE TABLE IF NOT EXISTS user_orgs (
UNIQUE (user_id, org_id),
PRIMARY KEY (user_id, org_id)
);
--- git_credential
-CREATE TABLE IF NOT EXISTS git_credential (
- git_credential_id TEXT,
- provider TEXT NOT NULL DEFAULT 'GitHub',
- auth_type TEXT NOT NULL,
- username TEXT NOT NULL,
- password TEXT NOT NULL,
- options JSONB,
- created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
- updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
- org_id TEXT NOT NULL REFERENCES org (org_id) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY (git_credential_id)
-);
-- project
CREATE TABLE IF NOT EXISTS project (
+ org_id TEXT NOT NULL REFERENCES org (org_id) ON DELETE CASCADE ON UPDATE CASCADE,
project_id TEXT NOT NULL,
project_name TEXT,
project_description TEXT,
options JSONB,
+ git_provider_type TEXT,
+ git_auth_type TEXT,
+ username TEXT,
+ password TEXT,
+ repository_url TEXT,
+ branch TEXT NOT NULL DEFAULT 'main',
+ working_directory TEXT DEFAULT '',
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
- org_id TEXT NOT NULL REFERENCES org (org_id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (org_id, project_id)
);
-- workspace
@@ -54,21 +48,6 @@ CREATE TABLE IF NOT EXISTS workspace (
FOREIGN KEY(org_id, project_id) REFERENCES project ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (org_id, project_id, workspace_id)
);
--- git_repository
-CREATE TABLE IF NOT EXISTS git_repository (
- org_id TEXT NOT NULL,
- project_id TEXT NOT NULL,
- workspace_id TEXT NOT NULL,
- repository_url TEXT NOT NULL,
- branch TEXT NOT NULL DEFAULT 'main',
- working_directory TEXT DEFAULT '',
- options JSONB,
- created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
- updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
- FOREIGN KEY(org_id, project_id, workspace_id) REFERENCES workspace ON DELETE CASCADE,
- git_credential_id TEXT NOT NULL REFERENCES git_credential (git_credential_id) ON DELETE CASCADE ON UPDATE CASCADE,
- PRIMARY KEY (org_id, project_id, workspace_id)
-);
-- run
CREATE TABLE IF NOT EXISTS run (
org_id TEXT NOT NULL,
diff --git a/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql b/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
index d363b836..611d9852 100644
--- a/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
+++ b/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
@@ -4,23 +4,6 @@ INSERT INTO org (org_id, org_name)
VALUES ('org-alice', 'org alice');
INSERT INTO user_orgs (org_id, user_id)
VALUES ('org-alice', 'alice-1234567890');
--- git_credential
-INSERT INTO git_credential (
- git_credential_id,
- org_id,
- username,
- password,
- provider,
- auth_type
- )
-VALUES (
- 'cred-org-alice',
- 'org-alice',
- 'alice',
- 'password',
- 'GitHub',
- 'PersonalAccessCode'
- );
-- project aws
INSERT INTO project (org_id, project_id, project_name)
VALUES (
@@ -72,25 +55,6 @@ VALUES (
'started',
'list'
);
--- git_repository
-INSERT INTO git_repository (
- org_id,
- project_id,
- workspace_id,
- git_credential_id,
- repository_url,
- branch,
- working_directory
- )
-VALUES (
- 'org-alice',
- 'project-aws',
- 'dev',
- 'cred-org-alice',
- 'https://github.com/FredericHeem/grucloud-aws-demo',
- 'main',
- ''
- );
-- bob
INSERT INTO org (org_id, org_name)
VALUES ('org-bob', 'org bob');
diff --git a/server/src/plugins/cloudDiagram/sql/GitCredentialSql.js b/server/src/plugins/cloudDiagram/sql/GitCredentialSql.js
deleted file mode 100644
index e6373497..00000000
--- a/server/src/plugins/cloudDiagram/sql/GitCredentialSql.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { tap, pipe, fork } = require("rubico");
-const assert = require("assert");
-const { defaultsDeep, identity } = require("rubico/x");
-const nanoid = require("nanoid");
-const { insert } = require("utils/SqlOps");
-
-module.exports = ({ sql }) => {
- const tableName = "git_credential";
- return {
- tableName,
- insert: (data) =>
- pipe([
- () => data,
- defaultsDeep({ git_credential_id: `cred-${nanoid.nanoid(8)}` }),
- fork({ out: identity, query: insert({ tableName, sql }) }),
- ])(),
- };
-};
diff --git a/server/src/plugins/cloudDiagram/sql/GitRepositorySql.js b/server/src/plugins/cloudDiagram/sql/GitRepositorySql.js
deleted file mode 100644
index 60e5cd2a..00000000
--- a/server/src/plugins/cloudDiagram/sql/GitRepositorySql.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { tap, pipe, fork } = require("rubico");
-const { identity } = require("rubico/x");
-const { insert } = require("utils/SqlOps");
-
-module.exports = ({ sql }) => {
- const tableName = "git_repository";
- return {
- tableName,
- insert: (data) =>
- pipe([
- () => data,
- fork({ out: identity, query: insert({ tableName, sql }) }),
- ])(),
- };
-};
diff --git a/server/src/plugins/cloudDiagram/test/testGitCredential.js b/server/src/plugins/cloudDiagram/test/testGitCredential.js
deleted file mode 100644
index eaddcc6b..00000000
--- a/server/src/plugins/cloudDiagram/test/testGitCredential.js
+++ /dev/null
@@ -1,111 +0,0 @@
-const assert = require("assert");
-const { switchCase, tryCatch, pipe, tap, get } = require("rubico");
-const testMngr = require("test/testManager");
-
-const org_id = "org-alice";
-
-const payloadCreate = {
- provider: "GitHub",
- auth_type: "PersonalAccessCode",
- username: "username",
- password: "password",
-};
-
-describe("Git Credential No Auth", function () {
- let client;
- before(async function () {
- if (!testMngr.app.config.infra) {
- this.skip();
- }
- client = testMngr.client("bob");
- });
-
- it("should get a 401 when getting all git credentials", async () => {
- try {
- await client.get(`v1/org/${org_id}/git_credential`);
- assert(false);
- } catch (error) {
- assert.equal(error.response.data, "Unauthorized");
- assert.equal(error.response.status, 401);
- }
- });
- it("should get 403 when getting a org", async () => {
- try {
- await client.get(`v1/org/${org_id}/git_credential/123456`);
- assert(false);
- } catch (error) {
- assert.equal(error.response.data, "Unauthorized");
- assert.equal(error.response.status, 401);
- }
- });
-});
-
-describe("Git Credential", function () {
- let client;
- before(async function () {
- if (!testMngr.app.config.infra) {
- this.skip();
- }
- client = testMngr.client("alice");
- await client.login();
- });
- it("CRUD", async () => {
- try {
- // Create
- const gitCredential = await client.post(
- `v1/org/${org_id}/git_credential`,
- payloadCreate
- );
- assert(gitCredential);
- const { git_credential_id } = gitCredential;
- assert(git_credential_id);
-
- assert.equal(gitCredential.username, payloadCreate.username);
- // Get By Id
- {
- let getOneResult = await client.get(
- `v1/org/${org_id}/git_credential/${git_credential_id}`
- );
- assert(getOneResult);
- assert(getOneResult.git_credential_id);
- assert(getOneResult.org_id);
- assert(getOneResult.username);
- }
- // Update
- {
- const inputUpdated = {
- username: "newgitusername",
- };
- const updatedGitCredential = await client.patch(
- `v1/org/${org_id}/git_credential/${git_credential_id}`,
- inputUpdated
- );
- assert.equal(updatedGitCredential.username, inputUpdated.username);
- }
- // Get all git credentials by org id
- {
- let gitCredentials = await client.get(
- `v1/org/${org_id}/git_credential`
- );
- assert(gitCredentials);
- assert(Array.isArray(gitCredentials));
- }
- // Delete
- await client.delete(
- `v1/org/${org_id}/git_credential/${git_credential_id}`
- );
- } catch (error) {
- throw error;
- }
- });
- it("should get 404 when the credentials is not found", async () => {
- try {
- await client.get(`v1/org/${org_id}/git_credential/123456`);
- assert(false);
- } catch (error) {
- assert(error.response.data.error);
- assert.equal(error.response.data.error.name, "NotFound");
- assert.equal(error.response.status, 404);
- }
- });
-});
diff --git a/server/src/plugins/cloudDiagram/test/testGitRepository.js b/server/src/plugins/cloudDiagram/test/testGitRepository.js
deleted file mode 100644
index eeb1e80a..00000000
--- a/server/src/plugins/cloudDiagram/test/testGitRepository.js
+++ /dev/null
@@ -1,117 +0,0 @@
-const assert = require("assert");
-const testMngr = require("test/testManager");
-
-const org_id = "org-alice";
-const project_id = "project-aws";
-const workspace_id = "dev";
-
-const payloadCreate = {
- git_credential_id: "cred-org-alice",
- repository_url: "https://github.com/FredericHeem/grucloud-aws-demo",
- branch: "master",
-};
-
-describe("Git Repository No Auth", function () {
- let client;
- before(async function () {
- if (!testMngr.app.config.infra) {
- this.skip();
- }
- client = testMngr.client("bob");
- });
-
- it("should get a 401 when getting all git_repositories", async () => {
- try {
- await client.get(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`
- );
- assert(false);
- } catch (error) {
- assert.equal(error.response.data, "Unauthorized");
- assert.equal(error.response.status, 401);
- }
- });
- it("should get 403 when getting a git_repository", async () => {
- try {
- await client.get(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`
- );
- assert(false);
- } catch (error) {
- assert.equal(error.response.data, "Unauthorized");
- assert.equal(error.response.status, 401);
- }
- });
-});
-
-describe("Git Repository", function () {
- let client;
- before(async function () {
- if (!testMngr.app.config.infra) {
- this.skip();
- }
- client = testMngr.client("alice");
- await client.login();
- });
- it("CRUD", async () => {
- try {
- // Create
- try {
- const git_repository = await client.post(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`,
- payloadCreate
- );
- assert(git_repository);
-
- assert.equal(
- git_repository.repository_url,
- payloadCreate.repository_url
- );
- } catch (error) {
- // May already be created
- }
-
- // Get By Id
- {
- let getOneResult = await client.get(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`
- );
- assert(getOneResult);
- assert(getOneResult.branch);
- assert(getOneResult.git_credential_id);
- }
- // Update
- {
- const inputUpdated = {
- repository_url: "https://github.com/FredericHeem/grucloud-aws-demo1",
- };
- const updatedGitCredential = await client.patch(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`,
- inputUpdated
- );
- assert.equal(
- updatedGitCredential.repository_url,
- inputUpdated.repository_url
- );
- }
- // Delete
- await client.delete(
- `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/git_repository`
- );
- } catch (error) {
- throw error;
- }
- });
- it("should get 404 when the git_repository is not found", async () => {
- try {
- await client.get(
- `v1/org/${org_id}/project/${project_id}/workspace/idonotexist/git_repository`
- );
- assert(false);
- } catch (error) {
- assert(error.response.data.error);
- assert.equal(error.response.data.error.name, "NotFound");
- assert.equal(error.response.status, 404);
- }
- });
-});
From 838055b483f0d6e0e48aab24fbe460cef9f946d1 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Mon, 6 Nov 2023 17:52:28 -0300
Subject: [PATCH 02/16] reset github-access-token and gitlab-access-token on
logout
---
.../src/plugins/users/authentication/AuthenticationRouter.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/server/src/plugins/users/authentication/AuthenticationRouter.js b/server/src/plugins/users/authentication/AuthenticationRouter.js
index 48c7d887..d8ef0204 100644
--- a/server/src/plugins/users/authentication/AuthenticationRouter.js
+++ b/server/src/plugins/users/authentication/AuthenticationRouter.js
@@ -154,6 +154,9 @@ function AuthenticationHttpController({ app, models }) {
logout(ctx) {
log.debug("logout");
ctx.logout();
+ ctx.cookies.set("github-access-token", "");
+ ctx.cookies.set("gitlab-access-token", "");
+
ctx.body = {
success: true,
};
From 418116bd88b907ffb9a80a85e2f198bac84c6337 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Wed, 8 Nov 2023 18:49:24 -0300
Subject: [PATCH 03/16] --include-groups
---
server/src/plugins/cloudDiagram/utils/rungc.js | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index 266446a6..c7ab2d7e 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -1,5 +1,5 @@
const assert = require("assert");
-const { pipe, tap, assign, get, eq, map, pick } = require("rubico");
+const { pipe, tap, assign, get, eq, map, pick, flatMap } = require("rubico");
const { values, unless } = require("rubico/x");
const path = require("path");
@@ -140,9 +140,16 @@ exports.DockerGcCreate = ({ app }) => {
outputDot: `resources.dot`,
outputSvg: `resources.svg`,
}),
+ assign({
+ servicesCmd: pipe([
+ () => env_vars,
+ get("SERVICES", []),
+ flatMap((service) => ["--include-groups", service]),
+ ]),
+ }),
assign({
name: () => `${containerName}-${run_id}`,
- Cmd: ({ outputGcList, outputDot }) => [
+ Cmd: ({ outputGcList, servicesCmd }) => [
"list",
"--provider",
provider,
@@ -170,10 +177,7 @@ exports.DockerGcCreate = ({ app }) => {
//`${outputDot}`,
"--title",
"",
- "--include-groups",
- "EC2",
- "--include-groups",
- "ECS",
+ ...servicesCmd,
],
outputGcListLocalPath: ({ outputGcList }) =>
path.resolve(outputDir, outputGcList),
From 213cb2cdf36aa870feaeb20bb892e8bb2b1d3179 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sun, 12 Nov 2023 16:38:33 -0300
Subject: [PATCH 04/16] run ecs task with the set of service
---
server/src/plugins/cloudDiagram/api/runApi.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 8e2589e2..24958bf0 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -10,6 +10,8 @@ const {
assign,
pick,
map,
+ flatMap,
+ omit,
} = require("rubico");
const { isEmpty, values, defaultsDeep } = require("rubico/x");
const { contextSet404, contextSetOk } = require("utils/koaCommon");
@@ -179,6 +181,12 @@ exports.RunApi = ({ app, models }) => {
]),
// default is ecs
pipe([
+ assign({
+ servicesCmd: pipe([
+ get("env_vars.SERVICES", []),
+ flatMap((service) => ["--include-groups", service]),
+ ]),
+ }),
({
org_id,
project_id,
@@ -186,6 +194,7 @@ exports.RunApi = ({ app, models }) => {
run_id,
env_vars,
provider_type,
+ servicesCmd,
}) => ({
config,
container: {
@@ -211,9 +220,11 @@ exports.RunApi = ({ app, models }) => {
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
"--title",
"",
+ ...servicesCmd,
],
environment: pipe([
() => env_vars,
+ omit(["SERVICES"]),
transformEnv({
GRUCLOUD_OAUTH_SUBJECT: buildSubject({
org_id,
From ef1d670f1d79383ba0869d6c8f1e5154f754cea0 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Fri, 17 Nov 2023 14:59:17 -0300
Subject: [PATCH 05/16] use gc ci runner
---
server/config/default.json | 4 +
server/src/plugins/cloudDiagram/api/runApi.js | 203 +++++++++++++++---
.../migrations/011.do.app-seed.sql | 18 +-
.../migrations/012.do.app-seed-js.js | 3 +-
.../plugins/cloudDiagram/test/test005Run.js | 1 +
.../src/plugins/cloudDiagram/utils/rungc.js | 39 +---
server/src/server/koa/koaServer.js | 1 +
7 files changed, 190 insertions(+), 79 deletions(-)
diff --git a/server/config/default.json b/server/config/default.json
index dd053026..d6a250ba 100644
--- a/server/config/default.json
+++ b/server/config/default.json
@@ -1,5 +1,9 @@
{
"websiteUrl": "http://localhost:8080",
+ "infra": {
+ "wsUrl": "ws://host.docker.internal:9000",
+ "containerImage": "grucloud/grucloud-cli"
+ },
"log": {
"console": {
"level": "debug",
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 24958bf0..7e736690 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -13,7 +13,14 @@ const {
flatMap,
omit,
} = require("rubico");
-const { isEmpty, values, defaultsDeep } = require("rubico/x");
+const {
+ isEmpty,
+ values,
+ defaultsDeep,
+ append,
+ when,
+ callProp,
+} = require("rubico/x");
const { contextSet404, contextSetOk } = require("utils/koaCommon");
const { middlewareUserBelongsToOrg } = require("../middleware");
@@ -95,6 +102,96 @@ const buildS3SignedUrl = ({ config, context, filename }) =>
])()
),
]);
+
+const buildCmd = ({
+ servicesCmd,
+ bucketUpload,
+ wsUrl,
+ provider_type,
+ org_id,
+ project_id,
+ workspace_id,
+ run_id,
+}) =>
+ pipe([
+ tap((param) => {
+ assert(bucketUpload);
+ assert(wsUrl);
+ assert(provider_type);
+ assert(run_id);
+ }),
+ () => [
+ "list",
+ "--json",
+ "grucloud-result.json",
+ "--graph",
+ // "--infra",
+ // `/app/iac.js`,
+ // "--provider",
+ // provider_type,
+ "--s3-bucket",
+ bucketUpload,
+ "--s3-key",
+ `${org_id}/${project_id}/${workspace_id}/${run_id}`,
+ "--s3-local-dir",
+ //"/app/artifacts",
+ "artifacts",
+ "--ws-url",
+ wsUrl,
+ "--ws-room",
+ `${org_id}/${project_id}/${workspace_id}/${run_id}`,
+ "--title",
+ '""',
+ ...servicesCmd,
+ ],
+ callProp("join", " "),
+ ])();
+
+const buildGcFlow = ({
+ repository_url,
+ provider_type,
+ bucketUpload,
+ wsUrl,
+ servicesCmd,
+ org_id,
+ project_id,
+ workspace_id,
+ run_id,
+}) =>
+ pipe([
+ () => [],
+ when(
+ () => repository_url,
+ pipe([
+ append({
+ name: "Clone Repo",
+ run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 my-repo",
+ }),
+ append({
+ name: "npm install",
+ run: "npm install",
+ workingDirectory: "my-repo",
+ }),
+ ])
+ ),
+ append({
+ name: "gc list",
+ run: `node_modules/.bin/gc ${buildCmd({
+ servicesCmd,
+ bucketUpload,
+ wsUrl,
+ provider_type,
+ org_id,
+ project_id,
+ workspace_id,
+ run_id,
+ })}`,
+ workingDirectory: "my-repo",
+ }),
+ (steps) => ({ steps }),
+ JSON.stringify,
+ ])();
+
exports.RunApi = ({ app, models }) => {
const { config } = app;
const { aws, infra } = config;
@@ -129,9 +226,6 @@ exports.RunApi = ({ app, models }) => {
workspace_id: () => context.params.workspace_id,
status: () => "creating",
}),
- tap((param) => {
- assert(true);
- }),
models.run.insert,
tap((param) => {
assert(true);
@@ -139,15 +233,73 @@ exports.RunApi = ({ app, models }) => {
assign({
container_id: (data) =>
pipe([
- () => ({
- attributes: ["env_vars", "provider_type"],
- where: pick(["org_id", "project_id", "workspace_id"])(data),
+ fork({
+ cloudAuthentication: pipe([
+ () => ({
+ attributes: ["env_vars", "provider_type"],
+ where: pick(["org_id", "project_id", "workspace_id"])(
+ data
+ ),
+ }),
+ models.cloudAuthentication.findOne,
+ ]),
+ project: pipe([
+ () => ({
+ attributes: [
+ "repository_url",
+ "branch",
+ "working_directory",
+ "username",
+ "password",
+ ],
+ where: pick(["org_id", "project_id"])(data),
+ }),
+ models.project.findOne,
+ ]),
+ servicesCmd: pipe([
+ get("cloudAuthentication.env_vars.SERVICES", []),
+ flatMap((service) => ["--include-groups", service]),
+ ]),
}),
- models.cloudAuthentication.findOne,
tap((param) => {
assert(true);
}),
defaultsDeep(data),
+ assign({
+ env_vars: ({
+ cloudAuthentication,
+ project,
+ servicesCmd,
+ org_id,
+ project_id,
+ workspace_id,
+ run_id,
+ }) =>
+ pipe([
+ () => cloudAuthentication.env_vars,
+ defaultsDeep({
+ DB_URL: config.db.urlDocker ?? config.db.url,
+ S3_BUCKET: aws.bucketUpload,
+ S3_BUCKET_KEY: `${org_id}/${project_id}/${workspace_id}/${run_id}/steps.txt`,
+ GIT_REPO: project.repository_url,
+ GIT_BRANCH: project.branch,
+ GC_FLOW: buildGcFlow({
+ servicesCmd,
+ repository_url: project.repository_url,
+ provider_type: cloudAuthentication.provider_type,
+ bucketUpload: aws.bucketUpload,
+ wsUrl: infra.wsUrl,
+ org_id,
+ project_id,
+ workspace_id,
+ run_id,
+ }),
+ }),
+ ])(),
+ }),
+ tap((param) => {
+ assert(true);
+ }),
switchCase([
eq(get("engine"), "docker"),
pipe([
@@ -157,7 +309,8 @@ exports.RunApi = ({ app, models }) => {
workspace_id,
run_id,
env_vars,
- provider_type,
+ cloudAuthentication,
+ project,
}) => ({
containerImage: "grucloud/grucloud-cli",
org_id,
@@ -165,13 +318,14 @@ exports.RunApi = ({ app, models }) => {
workspace_id,
run_id,
env_vars,
- provider: provider_type,
+ provider: cloudAuthentication.provider_type,
dockerClient: app.dockerClient,
GRUCLOUD_OAUTH_SUBJECT: buildSubject({
org_id,
project_id,
workspace_id,
}),
+ project,
}),
dockerGcCreate,
get("Id"),
@@ -192,36 +346,15 @@ exports.RunApi = ({ app, models }) => {
project_id,
workspace_id,
run_id,
- env_vars,
- provider_type,
servicesCmd,
+ cloudAuthentication,
+ env_vars,
+ project,
}) => ({
config,
container: {
name: "grucloud-cli",
- command: [
- "list",
- "--json",
- "grucloud-result.json",
- "--graph",
- "--infra",
- `/app/iac.js`,
- "--provider",
- provider_type,
- "--s3-bucket",
- aws.bucketUpload,
- "--s3-key",
- `${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--s3-local-dir",
- "/app/artifacts",
- "--ws-url",
- infra.wsUrl,
- "--ws-room",
- `${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--title",
- "",
- ...servicesCmd,
- ],
+ command: [],
environment: pipe([
() => env_vars,
omit(["SERVICES"]),
diff --git a/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql b/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
index 611d9852..2593ff9a 100644
--- a/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
+++ b/server/src/plugins/cloudDiagram/migrations/011.do.app-seed.sql
@@ -5,25 +5,31 @@ VALUES ('org-alice', 'org alice');
INSERT INTO user_orgs (org_id, user_id)
VALUES ('org-alice', 'alice-1234567890');
-- project aws
-INSERT INTO project (org_id, project_id, project_name)
+INSERT INTO project (org_id, project_id, project_name, repository_url, branch)
VALUES (
'org-alice',
'project-aws',
- 'alice project'
+ 'alice project',
+ 'https://github.com/FredericHeem/grucloud-aws-demo',
+ 'main'
);
-- project azure
-INSERT INTO project (org_id, project_id, project_name)
+INSERT INTO project (org_id, project_id, project_name, repository_url, branch)
VALUES (
'org-alice',
'project-azure',
- 'project azure'
+ 'project azure',
+ 'https://github.com/FredericHeem/grucloud-azure-demo',
+ 'master'
);
-- project google
-INSERT INTO project (org_id, project_id, project_name)
+INSERT INTO project (org_id, project_id, project_name,repository_url, branch)
VALUES (
'org-alice',
'project-google',
- 'project google'
+ 'project google',
+ 'https://github.com/FredericHeem/grucloud-gcp-demo',
+ 'master'
);
-- workspace aws
INSERT INTO workspace (org_id, project_id, workspace_id)
diff --git a/server/src/plugins/cloudDiagram/migrations/012.do.app-seed-js.js b/server/src/plugins/cloudDiagram/migrations/012.do.app-seed-js.js
index bad3f903..92693a04 100644
--- a/server/src/plugins/cloudDiagram/migrations/012.do.app-seed-js.js
+++ b/server/src/plugins/cloudDiagram/migrations/012.do.app-seed-js.js
@@ -23,7 +23,8 @@ VALUES (
"AZURE_SUBSCRIPTION_ID": "${process.env.AZURE_SUBSCRIPTION_ID}",
"AZURE_CLIENT_ID": "${process.env.AZURE_CLIENT_ID}",
"AZURE_CLIENT_SECRET": "${process.env.AZURE_CLIENT_SECRET}",
- "AZURE_OBJECT_ID": "${process.env.AZURE_OBJECT_ID}"
+ "AZURE_OBJECT_ID": "${process.env.AZURE_OBJECT_ID}",
+ "AZURE_LOCATION": "${process.env.AZURE_LOCATION}"
}'
);
diff --git a/server/src/plugins/cloudDiagram/test/test005Run.js b/server/src/plugins/cloudDiagram/test/test005Run.js
index 1620e295..e7dcd7ee 100644
--- a/server/src/plugins/cloudDiagram/test/test005Run.js
+++ b/server/src/plugins/cloudDiagram/test/test005Run.js
@@ -6,6 +6,7 @@ const project_id = "project-aws";
const project_aws_id = "project-aws";
const project_azure_id = "project-azure";
+const project_google_id = "project-google";
const workspace_id = "dev";
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index c7ab2d7e..c478448a 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -140,45 +140,10 @@ exports.DockerGcCreate = ({ app }) => {
outputDot: `resources.dot`,
outputSvg: `resources.svg`,
}),
- assign({
- servicesCmd: pipe([
- () => env_vars,
- get("SERVICES", []),
- flatMap((service) => ["--include-groups", service]),
- ]),
- }),
+
assign({
name: () => `${containerName}-${run_id}`,
- Cmd: ({ outputGcList, servicesCmd }) => [
- "list",
- "--provider",
- provider,
- "--s3-bucket",
- //TODO configure
- "grucloud-console-dev",
- "--s3-key",
- `${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--s3-local-dir",
- `/app/${outputDir}`,
- "--ws-url",
- "ws://host.docker.internal:9000",
- "--ws-room",
- `${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--infra",
- `/app/iac_${provider}.js`,
- //"--config",
- //`/app/input/config_${provider}.js`,
- "--graph",
- "--types-exclude",
- "ServiceAccount",
- "--json",
- `${outputGcList}`,
- //"--dot-file",
- //`${outputDot}`,
- "--title",
- "",
- ...servicesCmd,
- ],
+ Cmd: () => [],
outputGcListLocalPath: ({ outputGcList }) =>
path.resolve(outputDir, outputGcList),
HostConfig: () => ({
diff --git a/server/src/server/koa/koaServer.js b/server/src/server/koa/koaServer.js
index f39443bb..de33aa89 100644
--- a/server/src/server/koa/koaServer.js
+++ b/server/src/server/koa/koaServer.js
@@ -12,6 +12,7 @@ const contextHandleError = (error, context) =>
tap(() => {
assert(context);
log.error(error);
+ error.response && log.error(error.response);
}),
() => {
context.status = 500;
From 4193afd01188cbba605a1d363b85aac6e632534d Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 25 Nov 2023 11:50:22 -0300
Subject: [PATCH 06/16] make it work
---
deploy/playbook/group_vars/all/vars.yml | 6 ++---
deploy/playbook/tasks/api.yml | 10 ++++++---
server/.dockerignore | 7 ++++--
server/package.json | 8 +++----
server/src/plugins/cloudDiagram/api/runApi.js | 22 +++++++------------
.../plugins/cloudDiagram/utils/ecsTaskRun.js | 5 ++++-
.../plugins/cloudDiagram/utils/envUtils.js | 2 +-
.../src/plugins/cloudDiagram/utils/rungc.js | 2 +-
8 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/deploy/playbook/group_vars/all/vars.yml b/deploy/playbook/group_vars/all/vars.yml
index 12a11efa..92d1c367 100644
--- a/deploy/playbook/group_vars/all/vars.yml
+++ b/deploy/playbook/group_vars/all/vars.yml
@@ -10,13 +10,13 @@ pip_install_packages:
docker_base_url: "http:/v1.41"
-grucloud_image: "grucloud/grucloud-cli:v12.10.2"
+grucloud_image: "grucloud/grucloud-cli:v13.0.0"
# Docker image tag names
api_image: "fredericheem/grucloud-api"
-api_tag: "10.50"
+api_tag: "13.0.0"
web_image: "fredericheem/grucloud-ui"
-web_tag: "12.21"
+web_tag: "13.0.0"
firewall_state: started
firewall_enabled_at_boot: true
diff --git a/deploy/playbook/tasks/api.yml b/deploy/playbook/tasks/api.yml
index 4b492976..0c5adb6e 100644
--- a/deploy/playbook/tasks/api.yml
+++ b/deploy/playbook/tasks/api.yml
@@ -24,9 +24,13 @@
- "9000:9000"
env:
NODE_ENV: "production"
- S3_AWS_REGION: "{{S3_AWS_REGION}}"
- S3_AWSAccessKeyId: "{{S3_AWSAccessKeyId}}"
- S3_AWSSecretKey: "{{S3_AWSSecretKey}}"
+ S3_AWS_REGION: "{{AWS_REGION}}"
+ S3_AWSAccessKeyId: "{{AWSAccessKeyId}}"
+ S3_AWSSecretKey: "{{AWSSecretKey}}"
+ AWS_REGION: "{{AWS_REGION}}"
+ AWSAccessKeyId: "{{AWSAccessKeyId}}"
+ AWSSecretKey: "{{AWSSecretKey}}"
+ GRUCLOUD_OAUTH_SERVER: "{{GRUCLOUD_OAUTH_SERVER}}"
GRUCLOUD_OAUTH_CLIENT_SECRET: "{{GRUCLOUD_OAUTH_CLIENT_SECRET}}"
networks:
diff --git a/server/.dockerignore b/server/.dockerignore
index 11fd42cf..73d2b83c 100644
--- a/server/.dockerignore
+++ b/server/.dockerignore
@@ -1,5 +1,5 @@
.git
-.env
+*env
.vscode
coverage
dist
@@ -7,4 +7,7 @@ builds
local_backup
node_modules
docs
-
+output
+config/development.json
+test
+*.log
diff --git a/server/package.json b/server/package.json
index 22c3e868..061cc2ac 100644
--- a/server/package.json
+++ b/server/package.json
@@ -1,7 +1,7 @@
{
"name": "starhackit-api",
"description": "The starhackit backend",
- "version": "10.41.0",
+ "version": "13.0.0",
"private": false,
"main": "src/index.js",
"repository": {
@@ -11,7 +11,7 @@
"license": "NLPL",
"scripts": {
"start": "NODE_PATH=src node --env-file env --watch src/index.js",
- "start:prod": "NODE_PATH=src NODE_ENV=production node --env-file env src/index.js",
+ "start:prod": "NODE_PATH=src NODE_ENV=production node src/index.js",
"test": "npm run mocha",
"mocha": "NODE_PATH=src node --env-file env node_modules/mocha/bin/_mocha --file test/setup.js 'src/**/test*.js' --exit",
"mocha:watch": "npm run mocha -- --watch",
@@ -24,8 +24,8 @@
"db:drop": "dropdb dev -p 6432 -h localhost -U postgres",
"db:recreate": "PGPASSWORD=password npm run db:drop && npm run db:create",
"docker:build": "docker build . -t grucloud-api",
- "docker:tag": "docker tag grucloud-api fredericheem/grucloud-api:10.50",
- "docker:push": "docker push fredericheem/grucloud-api:10.50",
+ "docker:tag": "docker tag grucloud-api fredericheem/grucloud-api:13.0.0",
+ "docker:push": "docker push fredericheem/grucloud-api:13.0.0",
"docker:btp": "npm run docker:build && npm run docker:tag && npm run docker:push",
"docker:up": "docker-compose up -d",
"docker:down": "docker-compose down",
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 7e736690..559cdeb5 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -123,7 +123,7 @@ const buildCmd = ({
() => [
"list",
"--json",
- "grucloud-result.json",
+ "artifacts/grucloud-result.json",
"--graph",
// "--infra",
// `/app/iac.js`,
@@ -134,8 +134,7 @@ const buildCmd = ({
"--s3-key",
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
"--s3-local-dir",
- //"/app/artifacts",
- "artifacts",
+ "/app/my-repo/artifacts",
"--ws-url",
wsUrl,
"--ws-room",
@@ -163,6 +162,10 @@ const buildGcFlow = ({
when(
() => repository_url,
pipe([
+ append({
+ name: "Env",
+ run: "env",
+ }),
append({
name: "Clone Repo",
run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 my-repo",
@@ -341,16 +344,7 @@ exports.RunApi = ({ app, models }) => {
flatMap((service) => ["--include-groups", service]),
]),
}),
- ({
- org_id,
- project_id,
- workspace_id,
- run_id,
- servicesCmd,
- cloudAuthentication,
- env_vars,
- project,
- }) => ({
+ ({ org_id, project_id, workspace_id, env_vars }) => ({
config,
container: {
name: "grucloud-cli",
@@ -451,7 +445,7 @@ exports.RunApi = ({ app, models }) => {
svgUrl: buildS3SignedUrl({
config,
context,
- filename: "artifacts/diagram-live.svg",
+ filename: "diagram-live.svg",
}),
}),
contextSetOk({ context }),
diff --git a/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js b/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
index 5ad5493c..5592d2b2 100644
--- a/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
+++ b/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
@@ -13,7 +13,10 @@ exports.ecsTaskRun = ({ config: { ecs }, container }) =>
pipe([
tap(() => {
log.debug(
- `ecsTaskRun cluster: ${ecs.cluster}, taskDefinition: ${ecs.taskDefinition}, subnets: ${ecs.subnets}, securityGroups: ${ecs.securityGroups}`
+ `ecsTaskRun cluster: ${ecs.cluster}, taskDefinition: ${ecs.taskDefinition}, subnets: ${ecs.subnets}, securityGroups: ${ecs.securityGroups}, AWS_REGION: ${AWS_REGION}`
+ );
+ log.debug(
+ `ecsTaskRun AWS_REGION: ${AWS_REGION}, AWSAccessKeyId: ${AWSAccessKeyId}`
);
assert(ecs);
assert(ecs.cluster);
diff --git a/server/src/plugins/cloudDiagram/utils/envUtils.js b/server/src/plugins/cloudDiagram/utils/envUtils.js
index 50d34632..9308097b 100644
--- a/server/src/plugins/cloudDiagram/utils/envUtils.js
+++ b/server/src/plugins/cloudDiagram/utils/envUtils.js
@@ -14,7 +14,7 @@ const defaultEnv = [
exports.transformEnv = ({ GRUCLOUD_OAUTH_SUBJECT }) =>
pipe([
defaultsDeep(pick(defaultEnv)(process.env)),
- defaultsDeep({ GRUCLOUD_OAUTH_SUBJECT }),
+ defaultsDeep({ GRUCLOUD_OAUTH_SUBJECT, CONTINUOUS_INTEGRATION: "1" }),
when(
get("GOOGLE_CREDENTIALS"),
assign({
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index c478448a..1de0f39f 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -172,7 +172,7 @@ exports.DockerGcCreate = ({ app }) => {
Cmd,
Env,
HostConfig,
- WorkingDir: `/app/${outputDir}`,
+ WorkingDir: `/app/`,
},
}),
tap((xxx) => {
From ec4cc6add69faa44a480a006b5ad35cb1c3498f5 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 25 Nov 2023 17:35:57 -0300
Subject: [PATCH 07/16] remove room on closed
---
server/src/plugins/cloudDiagram/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/src/plugins/cloudDiagram/index.js b/server/src/plugins/cloudDiagram/index.js
index a5576804..22aa0e0b 100644
--- a/server/src/plugins/cloudDiagram/index.js
+++ b/server/src/plugins/cloudDiagram/index.js
@@ -95,8 +95,8 @@ module.exports = (app) => {
const ws = ctx.websocket;
dockerGcRun = DockerGcRun({ app, models, ws });
ws.on("close", () => {
- console.log("ws close");
- const room = producerMap.get();
+ const room = producerMap.get(ws);
+ console.log("ws close room", room);
if (room) {
roomMap.delete(room);
}
From 17c581b422482abf809a4ed010a099dfedcd2097 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 25 Nov 2023 17:36:09 -0300
Subject: [PATCH 08/16] WS_URL and WS_ROOM
---
server/src/plugins/cloudDiagram/api/runApi.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 559cdeb5..241b6fdd 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -297,6 +297,8 @@ exports.RunApi = ({ app, models }) => {
workspace_id,
run_id,
}),
+ WS_URL: infra.wsUrl,
+ WS_ROOM: `${org_id}/${project_id}/${workspace_id}/${run_id}`,
}),
])(),
}),
From 01628bee755d0906998132dc315d6fafae915cfc Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Tue, 28 Nov 2023 13:39:11 -0300
Subject: [PATCH 09/16] close socket
---
server/src/plugins/cloudDiagram/api/runApi.js | 19 ++++++++++---------
server/src/plugins/cloudDiagram/index.js | 8 ++++++--
.../src/plugins/cloudDiagram/utils/rungc.js | 8 ++++----
3 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 241b6fdd..2782b4a5 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -135,10 +135,10 @@ const buildCmd = ({
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
"--s3-local-dir",
"/app/my-repo/artifacts",
- "--ws-url",
- wsUrl,
- "--ws-room",
- `${org_id}/${project_id}/${workspace_id}/${run_id}`,
+ // "--ws-url",
+ // wsUrl,
+ // "--ws-room",
+ // `${org_id}/${project_id}/${workspace_id}/${run_id}`,
"--title",
'""',
...servicesCmd,
@@ -162,21 +162,22 @@ const buildGcFlow = ({
when(
() => repository_url,
pipe([
- append({
- name: "Env",
- run: "env",
- }),
append({
name: "Clone Repo",
run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 my-repo",
}),
append({
name: "npm install",
- run: "npm install",
+ run: "npm install --loglevel=error",
workingDirectory: "my-repo",
}),
])
),
+ // append({
+ // name: "ls",
+ // run: "ls -l",
+ // workingDirectory: "my-repo",
+ // }),
append({
name: "gc list",
run: `node_modules/.bin/gc ${buildCmd({
diff --git a/server/src/plugins/cloudDiagram/index.js b/server/src/plugins/cloudDiagram/index.js
index 22aa0e0b..f186d8a7 100644
--- a/server/src/plugins/cloudDiagram/index.js
+++ b/server/src/plugins/cloudDiagram/index.js
@@ -94,9 +94,11 @@ module.exports = (app) => {
app.server.koa.ws.use((ctx) => {
const ws = ctx.websocket;
dockerGcRun = DockerGcRun({ app, models, ws });
- ws.on("close", () => {
+ ws.on("close", (event) => {
const room = producerMap.get(ws);
console.log("ws close room", room);
+ //console.log(ws);
+
if (room) {
roomMap.delete(room);
}
@@ -124,7 +126,7 @@ module.exports = (app) => {
}
producerMap.set(ws, options.room);
break;
- case "list": {
+ case "end": {
const { error } = data;
const room = producerMap.get(ws);
if (room) {
@@ -164,6 +166,8 @@ module.exports = (app) => {
console.log("sending back");
client.send(message.toString());
});
+ } else {
+ console.error("no client for room", room);
}
} else {
console.error("no room for log command");
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index 1de0f39f..0edea71b 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -36,21 +36,21 @@ exports.DockerGcRun = ({ app, models, ws }) => {
() => ({ name: container_id }),
dockerClient.container.start,
tap((params) => {
- ws.send("update status");
+ // ws.send("update status");
log.debug("DockerGcRun", container_id, "started, wait for completion");
}),
// Update status
() => ({ data: { status: "running" }, where: { container_id } }),
models.run.update,
tap((params) => {
- ws.send("wait for completion");
+ //ws.send("wait for completion");
}),
// Wait
() => ({ name: container_id }),
dockerClient.container.wait,
tap((params) => {
log.debug("DockerGcRun ", container_id, "ended");
- ws.send("getting container state");
+ //ws.send("getting container state");
}),
// Get container state
() => ({ id: container_id }),
@@ -58,7 +58,7 @@ exports.DockerGcRun = ({ app, models, ws }) => {
get("State"),
tap((State) => {
log.debug(`container state ${JSON.stringify(State)}`);
- ws.send("saving container state");
+ //ws.send("saving container state");
}),
// Save container_state and status to DB
(container_state) => ({
From d008b0ac21346b904cb09d4e0a01b163f0d2a127 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sun, 3 Dec 2023 20:29:19 -0300
Subject: [PATCH 10/16] run on lambda
---
deploy/grucloud-aws/.gitignore | 8 -
deploy/grucloud-aws/.npmrc | 1 -
deploy/grucloud-aws/.vscode/launch.json | 71 ---
deploy/grucloud-aws/README.md | 51 --
deploy/grucloud-aws/config.js | 8 -
deploy/grucloud-aws/default.templateenv | 5 -
deploy/grucloud-aws/diagram-live.svg | 472 ------------------
deploy/grucloud-aws/diagram-target.svg | 317 ------------
deploy/grucloud-aws/hooks.js | 97 ----
deploy/grucloud-aws/iac.js | 301 -----------
deploy/grucloud-aws/package.json | 17 -
deploy/grucloud-aws/resources-mindmap.puml | 45 --
deploy/grucloud-aws/resources-mindmap.svg | 55 --
deploy/playbook/group_vars/all/vars.yml | 4 +-
server/package.json | 1 +
server/src/plugins/cloudDiagram/api/runApi.js | 111 ++--
.../plugins/cloudDiagram/test/test005Run.js | 43 +-
.../plugins/cloudDiagram/test/testEcsTask.js | 48 +-
.../plugins/cloudDiagram/utils/ECSClient.js | 24 +
.../cloudDiagram/utils/LambdaClient.js | 24 +
.../plugins/cloudDiagram/utils/S3Client.js | 24 +
.../plugins/cloudDiagram/utils/ecsTaskRun.js | 16 +-
.../plugins/cloudDiagram/utils/lambdaRun.js | 57 +++
.../src/plugins/cloudDiagram/utils/rungc.js | 9 +-
24 files changed, 261 insertions(+), 1548 deletions(-)
delete mode 100644 deploy/grucloud-aws/.gitignore
delete mode 100644 deploy/grucloud-aws/.npmrc
delete mode 100644 deploy/grucloud-aws/.vscode/launch.json
delete mode 100644 deploy/grucloud-aws/README.md
delete mode 100644 deploy/grucloud-aws/config.js
delete mode 100644 deploy/grucloud-aws/default.templateenv
delete mode 100644 deploy/grucloud-aws/diagram-live.svg
delete mode 100644 deploy/grucloud-aws/diagram-target.svg
delete mode 100644 deploy/grucloud-aws/hooks.js
delete mode 100644 deploy/grucloud-aws/iac.js
delete mode 100644 deploy/grucloud-aws/package.json
delete mode 100644 deploy/grucloud-aws/resources-mindmap.puml
delete mode 100644 deploy/grucloud-aws/resources-mindmap.svg
create mode 100644 server/src/plugins/cloudDiagram/utils/ECSClient.js
create mode 100644 server/src/plugins/cloudDiagram/utils/LambdaClient.js
create mode 100644 server/src/plugins/cloudDiagram/utils/S3Client.js
create mode 100644 server/src/plugins/cloudDiagram/utils/lambdaRun.js
diff --git a/deploy/grucloud-aws/.gitignore b/deploy/grucloud-aws/.gitignore
deleted file mode 100644
index d138929c..00000000
--- a/deploy/grucloud-aws/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-*.csv
-*.pem
-node_modules/
-*.env
-.nyc_output
-coverage
-*.log
-*.dot
diff --git a/deploy/grucloud-aws/.npmrc b/deploy/grucloud-aws/.npmrc
deleted file mode 100644
index 43c97e71..00000000
--- a/deploy/grucloud-aws/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-package-lock=false
diff --git a/deploy/grucloud-aws/.vscode/launch.json b/deploy/grucloud-aws/.vscode/launch.json
deleted file mode 100644
index 145bd259..00000000
--- a/deploy/grucloud-aws/.vscode/launch.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Graph",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["graph"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- },
- {
- "name": "List -g -o",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["list", "-g", "-o"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- },
- {
- "name": "Plan",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["plan"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- },
- {
- "name": "Apply",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["apply", "-f"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- },
- {
- "name": "Destroy",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["destroy", "-f"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- }
- {
- "name": "Info",
- "type": "node",
- "request": "launch",
- "runtimeExecutable": "gc",
- "runtimeArgs": ["info"],
- "internalConsoleOptions": "openOnSessionStart",
- "console": "integratedTerminal",
- "cwd": "${workspaceRoot}",
- "port": 9229
- }
- ]
-}
diff --git a/deploy/grucloud-aws/README.md b/deploy/grucloud-aws/README.md
deleted file mode 100644
index 2d138394..00000000
--- a/deploy/grucloud-aws/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Deploy infrastructure on AWS with GruCloud
-
-This directory contains the code to deploy and destroy the instructure on AWS with [grucloud](https://grucloud.com).
-
-The following resources are defined in [iac](./iac.js):
-
-
-
-> Mindmap generated by `gc tree`
-
-Visit [AwsRequirements](https://www.grucloud.com/docs/aws/AwsRequirements) and ensure the _aws cli_ is configured properly.
-
-Edit [config.js](config.js) and change the domain name and the key pair name.
-
-Install the _gc CLI_ globally:
-
-```sh
-npm i -g @grucloud/core
-```
-
-Install the dependencies
-
-```sh
-npm i
-```
-
-Generate a graph of the infrastructure:
-
-```sh
-gc graph
-```
-
-
-
-Deploy the infrastructure with:
-
-```sh
-gc apply
-```
-
-List the running resources:
-
-```sh
-gc list
-```
-
-Destroy the running resources:
-
-```sh
-gc destroy
-```
diff --git a/deploy/grucloud-aws/config.js b/deploy/grucloud-aws/config.js
deleted file mode 100644
index 2d83a3a7..00000000
--- a/deploy/grucloud-aws/config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-const pkg = require("./package.json");
-
-module.exports = () => ({
- domainName: "grucloud.com",
- keyPairName: "grucloud-app",
- projectName: pkg.name,
- availabilityZoneSuffix: "b",
-});
diff --git a/deploy/grucloud-aws/default.templateenv b/deploy/grucloud-aws/default.templateenv
deleted file mode 100644
index 0bd0c95a..00000000
--- a/deploy/grucloud-aws/default.templateenv
+++ /dev/null
@@ -1,5 +0,0 @@
-AWSAccessKeyId=
-AWSSecretKey=
-AWS_REGION=us-east-1
-
-
diff --git a/deploy/grucloud-aws/diagram-live.svg b/deploy/grucloud-aws/diagram-live.svg
deleted file mode 100644
index eccfee87..00000000
--- a/deploy/grucloud-aws/diagram-live.svg
+++ /dev/null
@@ -1,472 +0,0 @@
-
-
-
-
-
-
-graphname
-
-Project grucloud-aws
-Live Diagram
-
-cluster_aws
-
-Provider aws
-
-
-cluster_aws_
-
-
-
-
-
-Volume::::vol-034a467db1e71e984
-
-Volume
-vol-034a467db1e71e984
-
-
-
-KeyPair::::grucloud-app
-
-KeyPair
-grucloud-app
-
-
-
-Route53Domain::::grucloud.com
-
-Route53Domain
-grucloud.com
-
-
-
-IamRole::::arn:aws:iam::161408406883:role/OrganizationAccountAccessRole
-
-IamRole
-OrganizationAccountAccessRole
-
-
-
-HostedZone::::/hostedzone/Z0829805257L0AS74FNR9
-
-HostedZone
-grucloud.com.
-
-
-
-Vpc::::vpc-0a3a7a91cb6b0dccb
-
-Vpc
-vpc
-
-
-
-Vpc::::vpc-280b8555
-
-Vpc
-default
-
-
-
-Image::::ami-0a7ce59297fb8a731
-
-Image
-ubuntu 20.04
-
-
-
-Subnet::::subnet-2c0e760d
-
-Subnet
-default
-
-
-
-Subnet::::subnet-2c0e760d->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-ed027cb2
-
-Subnet
-default
-
-
-
-Subnet::::subnet-ed027cb2->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-a14e43ec
-
-Subnet
-default
-
-
-
-Subnet::::subnet-a14e43ec->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-becd4c8f
-
-Subnet
-default
-
-
-
-Subnet::::subnet-becd4c8f->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-f46b5cfa
-
-Subnet
-default
-
-
-
-Subnet::::subnet-f46b5cfa->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-22c5b744
-
-Subnet
-default
-
-
-
-Subnet::::subnet-22c5b744->Vpc::::vpc-280b8555
-
-
-
-
-
-Subnet::::subnet-0357436d6b0748d2e
-
-Subnet
-subnet
-
-
-
-Subnet::::subnet-0357436d6b0748d2e->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-InternetGateway::::igw-0afcf265918398336
-
-InternetGateway
-ig
-
-
-
-InternetGateway::::igw-0afcf265918398336->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-InternetGateway::::igw-a50bf6df
-
-InternetGateway
-igw-a50bf6df
-
-
-
-InternetGateway::::igw-a50bf6df->Vpc::::vpc-280b8555
-
-
-
-
-
-Route53Record::::A::grucloud.com.
-
-Route53Record
-grucloud.com.-ipv4
-
-
-
-Route53Record::::A::grucloud.com.->HostedZone::::/hostedzone/Z0829805257L0AS74FNR9
-
-
-
-
-
-ElasticIpAddress::::eipalloc-07efbd8b54f12f828
-
-ElasticIpAddress
-ip
-
-
-
-RouteTable::::rtb-c05f4bbe
-
-RouteTable
-rtb-c05f4bbe
-
-
-
-RouteTable::::rtb-c05f4bbe->Vpc::::vpc-280b8555
-
-
-
-
-
-RouteTable::::rtb-c05f4bbe->InternetGateway::::igw-a50bf6df
-
-
-
-
-
-RouteTable::::rtb-06b8e49ef9c983e40
-
-RouteTable
-rtb-06b8e49ef9c983e40
-
-
-
-RouteTable::::rtb-06b8e49ef9c983e40->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-RouteTable::::rtb-097a54b361c1d896f
-
-RouteTable
-route-table
-
-
-
-RouteTable::::rtb-097a54b361c1d896f->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-RouteTable::::rtb-097a54b361c1d896f->InternetGateway::::igw-0afcf265918398336
-
-
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-ssh
-
-SecurityGroupRuleIngress
-sg-rule-ingress-ssh
-
-
-
-SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-SecurityGroup
-securityGroup
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-ssh->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-http
-
-SecurityGroupRuleIngress
-sg-rule-ingress-http
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-http->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-https
-
-SecurityGroupRuleIngress
-sg-rule-ingress-https
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-https->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-icmp
-
-SecurityGroupRuleIngress
-sg-rule-ingress-icmp
-
-
-
-SecurityGroupRuleIngress::::sg-rule-ingress-icmp->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-Route::::route-ig
-
-Route
-route-ig
-
-
-
-Route::::route-ig->InternetGateway::::igw-0afcf265918398336
-
-
-
-
-
-Route::::route-ig->RouteTable::::rtb-097a54b361c1d896f
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365
-
-EC2
-server
-
-
-
-EC2::::i-0c0c8b11cddee7365->Volume::::vol-034a467db1e71e984
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365->KeyPair::::grucloud-app
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365->Image::::ami-0a7ce59297fb8a731
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365->Subnet::::subnet-0357436d6b0748d2e
-
-
-
-
-
-NetworkInterface::::eni-009d9c6e09a0a6acc
-
-NetworkInterface
-eni-009d9c6e09a0a6acc
-
-
-
-EC2::::i-0c0c8b11cddee7365->NetworkInterface::::eni-009d9c6e09a0a6acc
-
-
-
-
-
-EC2::::i-0c0c8b11cddee7365->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-Volume::::vol-0716097719ad12517
-
-Volume
-volume
-
-
-
-NetworkInterface::::eni-009d9c6e09a0a6acc->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-NetworkInterface::::eni-009d9c6e09a0a6acc->Subnet::::subnet-0357436d6b0748d2e
-
-
-
-
-
-NetworkInterface::::eni-009d9c6e09a0a6acc->SecurityGroup::::sg-0aed7dee5b6d71e6e
-
-
-
-
-
-SecurityGroup::::sg-006766c368b7e81d1
-
-SecurityGroup
-default
-
-
-
-SecurityGroup::::sg-006766c368b7e81d1->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-SecurityGroup::::sg-006766c368b7e81d1->SecurityGroup::::sg-006766c368b7e81d1
-
-
-
-
-
-SecurityGroup::::sg-0aed7dee5b6d71e6e->Vpc::::vpc-0a3a7a91cb6b0dccb
-
-
-
-
-
-SecurityGroup::::sg-9643e293
-
-SecurityGroup
-default
-
-
-
-SecurityGroup::::sg-9643e293->Vpc::::vpc-280b8555
-
-
-
-
-
-SecurityGroup::::sg-9643e293->SecurityGroup::::sg-9643e293
-
-
-
-
-
diff --git a/deploy/grucloud-aws/diagram-target.svg b/deploy/grucloud-aws/diagram-target.svg
deleted file mode 100644
index acfcd9a4..00000000
--- a/deploy/grucloud-aws/diagram-target.svg
+++ /dev/null
@@ -1,317 +0,0 @@
-
-
-
-
-
-
-graphname
-
-Project grucloud-aws
-
-Target Diagram
-
-cluster_aws
-
-Provider aws
-
-
-cluster_aws_
-
-
-
-
-
-KeyPair::grucloud-app
-
-KeyPair
-grucloud-app
-
-
-
-Vpc::vpc
-
-Vpc
-vpc
-
-
-
-InternetGateway::ig
-
-InternetGateway
-ig
-
-
-
-InternetGateway::ig->Vpc::vpc
-
-
-
-
-
-Subnet::subnet
-
-Subnet
-subnet
-
-
-
-Subnet::subnet->Vpc::vpc
-
-
-
-
-
-RouteTable::route-table
-
-RouteTable
-route-table
-
-
-
-RouteTable::route-table->Vpc::vpc
-
-
-
-
-
-RouteTable::route-table->Subnet::subnet
-
-
-
-
-
-Route::route-ig
-
-Route
-route-ig
-
-
-
-Route::route-ig->InternetGateway::ig
-
-
-
-
-
-Route::route-ig->RouteTable::route-table
-
-
-
-
-
-SecurityGroup::securityGroup
-
-SecurityGroup
-securityGroup
-
-
-
-SecurityGroup::securityGroup->Vpc::vpc
-
-
-
-
-
-SecurityGroup::securityGroup->Subnet::subnet
-
-
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-ssh
-
-SecurityGroupRuleIngress
-sg-rule-ingress-ssh
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-ssh->SecurityGroup::securityGroup
-
-
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-http
-
-SecurityGroupRuleIngress
-sg-rule-ingress-http
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-http->SecurityGroup::securityGroup
-
-
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-https
-
-SecurityGroupRuleIngress
-sg-rule-ingress-https
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-https->SecurityGroup::securityGroup
-
-
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-icmp
-
-SecurityGroupRuleIngress
-sg-rule-ingress-icmp
-
-
-
-SecurityGroupRuleIngress::sg-rule-ingress-icmp->SecurityGroup::securityGroup
-
-
-
-
-
-ElasticIpAddress::ip
-
-ElasticIpAddress
-ip
-
-
-
-Image::ubuntu 20.04
-
-Image
-ubuntu 20.04
-
-
-
-Volume::volume
-
-Volume
-volume
-
-
-
-Instance::server
-
-Instance
-server
-
-
-
-Instance::server->KeyPair::grucloud-app
-
-
-
-
-
-Instance::server->Subnet::subnet
-
-
-
-
-
-Instance::server->SecurityGroup::securityGroup
-
-
-
-
-
-Instance::server->ElasticIpAddress::ip
-
-
-
-
-
-Instance::server->Image::ubuntu 20.04
-
-
-
-
-
-Instance::server->Volume::volume
-
-
-
-
-
-Domain::grucloud.com
-
-Domain
-grucloud.com
-
-
-
-HostedZone::grucloud.com.
-
-HostedZone
-grucloud.com.
-
-
-
-HostedZone::grucloud.com.->Domain::grucloud.com
-
-
-
-
-
-Record::app.grucloud.com.
-
-Record
-app.grucloud.com.
-
-
-
-Record::app.grucloud.com.->ElasticIpAddress::ip
-
-
-
-
-
-Record::app.grucloud.com.->HostedZone::grucloud.com.
-
-
-
-
-
-Record::grucloud.com.
-
-Record
-grucloud.com.
-
-
-
-Record::grucloud.com.->HostedZone::grucloud.com.
-
-
-
-
-
-Record::grucloud.com.-gitpage-record-www
-
-Record
-grucloud.com.-gitpage-record-www...
-
-
-
-Record::grucloud.com.-gitpage-record-www->HostedZone::grucloud.com.
-
-
-
-
-
-Record::grucloud.com.-mx
-
-Record
-grucloud.com.-mx
-
-
-
-Record::grucloud.com.-mx->HostedZone::grucloud.com.
-
-
-
-
-
diff --git a/deploy/grucloud-aws/hooks.js b/deploy/grucloud-aws/hooks.js
deleted file mode 100644
index 1b080f41..00000000
--- a/deploy/grucloud-aws/hooks.js
+++ /dev/null
@@ -1,97 +0,0 @@
-const assert = require("assert");
-const ping = require("ping");
-const path = require("path");
-const Client = require("ssh2").Client;
-const { retryCall } = require("@grucloud/core").Retry;
-
-const testPing = ({ host }) =>
- ping.promise.probe(host, {
- timeout: 10,
- });
-
-//const privateKey = require("fs").readFileSync(
-// path.resolve(__dirname, "../../../secrets/kp.pem")
-//);
-
-const testSsh = async ({ host, username = "ubuntu" }) =>
- await new Promise((resolve, reject) => {
- const conn = new Client();
- conn
- .on("ready", function () {
- //console.log(`ssh to ${host} ok`);
- conn.end();
- resolve();
- })
- .on("error", function (error) {
- // console.log(`cannot ssh to ${host}`, error);
- reject(error);
- })
- .connect({
- host,
- port: 22,
- username,
- agent: process.env.SSH_AUTH_SOCK,
- //privateKey,
- });
- });
-
-module.exports = ({ resources: { eip, server }, provider }) => {
- assert(provider);
- return {
- onDeployed: {
- init: async () => {
- const eipLive = await eip.getLive();
- const serverLive = await server.getLive();
- assert(serverLive, "server should be alive");
- //Static checks
- assert.equal(serverLive.PublicIpAddress, eipLive.PublicIp);
-
- const host = eipLive.PublicIp;
- return {
- host,
- };
- },
- actions: [
- //Cannot ping from CircleCI
- /*{
- name: "Ping",
- command: async ({ host }) => {
- const alive = await retryCall({
- name: `ping ${host}`,
- fn: async () => {
- const { alive } = await testPing({ host });
- if (!alive) {
- throw Error(`cannot ping ${host} yet`);
- }
- return alive;
- },
- shouldRetryOnException: () => true,
- retryCount: 40,
- retryDelay: 5e3,
- });
- assert(alive, `cannot ping ${host}`);
- },
- },*/
- {
- name: "SSH",
- command: async ({ host }) => {
- await retryCall({
- name: `ssh ${host}`,
- fn: async () => {
- await testSsh({ host });
- return true;
- },
- shouldRetryOnException: () => true,
- config: { retryCount: 40, retryDelay: 5e3 },
- });
- },
- },
- ],
- },
- onDestroyed: {
- init: () => {
- //console.log("ec2 onDestroyed");
- },
- },
- };
-};
diff --git a/deploy/grucloud-aws/iac.js b/deploy/grucloud-aws/iac.js
deleted file mode 100644
index 5935b0fe..00000000
--- a/deploy/grucloud-aws/iac.js
+++ /dev/null
@@ -1,301 +0,0 @@
-const { AwsProvider } = require("@grucloud/provider-aws");
-const assert = require("assert");
-
-const createResources = async ({ provider, resources: { keyPair } }) => {
- const { config } = provider;
- const { domainName, stage } = config;
-
- const AvailabilityZone = `${config.region}${config.availabilityZoneSuffix}`;
-
- const Device = "/dev/sdf";
- const deviceMounted = "/dev/xvdf";
- const mountPoint = "/data";
- const vpc = provider.EC2.makeVpc({
- name: "vpc",
- properties: () => ({
- CidrBlock: "10.1.0.0/16",
- }),
- });
- const ig = provider.EC2.makeInternetGateway({
- name: "ig",
- dependencies: { vpc },
- });
-
- const subnet = provider.EC2.makeSubnet({
- name: "subnet",
- dependencies: { vpc },
- properties: () => ({
- CidrBlock: "10.1.0.1/24",
- AvailabilityZone,
- }),
- });
-
- const routeTable = provider.EC2.makeRouteTable({
- name: "route-table",
- dependencies: { vpc, subnets: [subnet] },
- });
-
- const route = provider.EC2.makeRoute({
- name: "route-ig",
- dependencies: { routeTable, ig },
- });
-
- const securityGroup = provider.EC2.makeSecurityGroup({
- name: "securityGroup",
- dependencies: { vpc, subnet },
- properties: () => ({
- //https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#createSecurityGroup-property
- Description: "Security Group Description",
- }),
- });
- const sgRuleIngressSsh = provider.EC2.makeSecurityGroupRuleIngress({
- name: "sg-rule-ingress-ssh",
- dependencies: {
- securityGroup,
- },
- properties: () => ({
- IpPermission: {
- FromPort: 22,
- IpProtocol: "tcp",
- IpRanges: [
- {
- CidrIp: "0.0.0.0/0",
- },
- ],
- Ipv6Ranges: [
- {
- CidrIpv6: "::/0",
- },
- ],
- ToPort: 22,
- },
- }),
- });
- const sgRuleIngressHttp = provider.EC2.makeSecurityGroupRuleIngress({
- name: "sg-rule-ingress-http",
- dependencies: {
- securityGroup,
- },
- properties: () => ({
- IpPermission: {
- FromPort: 80,
- IpProtocol: "tcp",
- IpRanges: [
- {
- CidrIp: "0.0.0.0/0",
- },
- ],
- Ipv6Ranges: [
- {
- CidrIpv6: "::/0",
- },
- ],
- ToPort: 80,
- },
- }),
- });
- const sgRuleIngressHttps = provider.EC2.makeSecurityGroupRuleIngress({
- name: "sg-rule-ingress-https",
- dependencies: {
- securityGroup,
- },
- properties: () => ({
- IpPermission: {
- FromPort: 443,
- IpProtocol: "tcp",
- IpRanges: [
- {
- CidrIp: "0.0.0.0/0",
- },
- ],
- Ipv6Ranges: [
- {
- CidrIpv6: "::/0",
- },
- ],
- ToPort: 443,
- },
- }),
- });
- const sgRuleIngressIcmp = provider.EC2.makeSecurityGroupRuleIngress({
- name: "sg-rule-ingress-icmp",
- dependencies: {
- securityGroup,
- },
- properties: () => ({
- IpPermission: {
- FromPort: -1,
- IpProtocol: "icmp",
- IpRanges: [
- {
- CidrIp: "0.0.0.0/0",
- },
- ],
- Ipv6Ranges: [
- {
- CidrIpv6: "::/0",
- },
- ],
- ToPort: -1,
- },
- }),
- });
-
- const eip = provider.EC2.makeElasticIpAddress({
- name: "ip",
- });
-
- const image = provider.EC2.useImage({
- name: "ubuntu 20.04",
- properties: () => ({
- Filters: [
- {
- Name: "architecture",
- Values: ["x86_64"],
- },
- {
- Name: "description",
- Values: ["Canonical, Ubuntu, 20.04 LTS, amd64 focal*"],
- },
- ],
- }),
- });
-
- const volume = provider.EC2.makeVolume({
- name: "volume",
- properties: () => ({
- Size: 10,
- VolumeType: "standard",
- Device,
- AvailabilityZone,
- }),
- });
-
- // Allocate a server
- const server = provider.EC2.makeInstance({
- name: "server",
- dependencies: {
- keyPair,
- subnet,
- securityGroups: [securityGroup],
- eip,
- image,
- volumes: [volume],
- },
- properties: () => ({
- UserData: volume.spec.setupEbsVolume({ deviceMounted, mountPoint }),
- InstanceType: "t2.micro",
- Placement: { AvailabilityZone },
- }),
- });
-
- const domain = provider.Route53Domains.useDomain({
- name: domainName,
- });
-
- const hostedZoneName = `${domainName}.`;
- const hostedZone = provider.Route53.makeHostedZone({
- name: hostedZoneName,
- dependencies: { domain },
- properties: ({}) => ({}),
- });
-
- const recordA = provider.Route53.makeRecord({
- name: `app.${hostedZoneName}`,
- dependencies: { hostedZone, eip },
- properties: ({ dependencies: { eip } }) => {
- return {
- Name: `app.${hostedZoneName}`,
- Type: "A",
- ResourceRecords: [
- {
- Value: eip.live?.PublicIp,
- },
- ],
- TTL: 60,
- };
- },
- });
-
- const recordAGitPage = provider.Route53.makeRecord({
- name: `${hostedZoneName}`,
- dependencies: { hostedZone },
- properties: ({ dependencies }) => {
- return {
- Name: `${hostedZoneName}`,
- Type: "A",
- ResourceRecords: [
- {
- Value: "185.199.108.153",
- },
- {
- Value: "185.199.109.153",
- },
- ],
- TTL: 86400,
- };
- },
- });
- const recordWww = provider.Route53.makeRecord({
- name: `${hostedZoneName}-gitpage-record-www`,
- dependencies: { hostedZone },
- properties: () => {
- return {
- Name: `www.${hostedZoneName}`,
- Type: "CNAME",
- ResourceRecords: [
- {
- Value: "grucloud.github.io.",
- },
- ],
- TTL: 86400,
- };
- },
- });
-
- const recordMx = provider.Route53.makeRecord({
- name: `${hostedZoneName}-mx`,
- dependencies: { hostedZone },
- properties: () => {
- return {
- Name: `${hostedZoneName}`,
- Type: "MX",
- ResourceRecords: [
- {
- Value: "1 ASPMX.L.GOOGLE.COM.",
- },
- {
- Value: "5 ALT1.ASPMX.L.GOOGLE.COM.",
- },
- ],
- TTL: 86400,
- };
- },
- });
- return {
- vpc,
- ig,
- subnet,
- routeTable,
- securityGroup,
- eip,
- server,
- //hostedZone, recordA
- };
-};
-
-exports.createResources = createResources;
-
-//TODO
-exports.createStack = async ({ config, stage }) => {
- // Create a AWS provider
- const provider = AwsProvider({ config, stage });
- const { keyPairName } = provider.config;
- assert(keyPairName);
-
- const keyPair = provider.EC2.useKeyPair({
- name: keyPairName,
- });
- const resources = await createResources({ provider, resources: { keyPair } });
- return { provider, resources };
-};
diff --git a/deploy/grucloud-aws/package.json b/deploy/grucloud-aws/package.json
deleted file mode 100644
index cf69c5a4..00000000
--- a/deploy/grucloud-aws/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "grucloud-app",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "e2e": "gc d -a -f && gc d -a && gc l && gc a -f && gc a && gc d -f && gc d && gc l -o"
- },
- "author": "",
- "license": "ISC",
- "dependencies": {
- "@grucloud/core": "1.38.0",
- "@grucloud/provider-aws": "1.38.0",
- "ping": "^0.4.1",
- "ssh2": "^1.3.0"
- }
-}
diff --git a/deploy/grucloud-aws/resources-mindmap.puml b/deploy/grucloud-aws/resources-mindmap.puml
deleted file mode 100644
index b7ec56f4..00000000
--- a/deploy/grucloud-aws/resources-mindmap.puml
+++ /dev/null
@@ -1,45 +0,0 @@
-@startmindmap
-title Resources for project grucloud-aws
-skinparam monochrome true
-+ Infra
-++ aws
-+++ ec2
-++++ KeyPair (1)
-+++++ grucloud-app
-++++ Vpc (1)
-+++++ vpc
-++++ InternetGateway (1)
-+++++ ig
-++++ Subnet (1)
-+++++ subnet
-++++ RouteTable (1)
-+++++ route-table
-++++ Route (1)
-+++++ route-ig
-++++ SecurityGroup (1)
-+++++ securityGroup
-++++ SecurityGroupRuleIngress (4)
-+++++ sg-rule-ingress-ssh
-+++++ sg-rule-ingress-http
-+++++ sg-rule-ingress-https
-+++++ sg-rule-ingress-icmp
-++++ ElasticIpAddress (1)
-+++++ ip
-++++ Image (1)
-+++++ ubuntu 20.04
-++++ Volume (1)
-+++++ volume
-++++ Instance (1)
-+++++ server
-+++ route53Domain
-++++ Domain (1)
-+++++ grucloud.com
-+++ route53
-++++ HostedZone (1)
-+++++ grucloud.com.
-++++ Record (4)
-+++++ app.grucloud.com.
-+++++ grucloud.com.
-+++++ grucloud.com.-gitpage-record-www
-+++++ grucloud.com.-mx
-@endmindmap
\ No newline at end of file
diff --git a/deploy/grucloud-aws/resources-mindmap.svg b/deploy/grucloud-aws/resources-mindmap.svg
deleted file mode 100644
index de96534e..00000000
--- a/deploy/grucloud-aws/resources-mindmap.svg
+++ /dev/null
@@ -1,55 +0,0 @@
-Resources for project grucloud-aws Infra aws ec2 KeyPair (1) grucloud-app Vpc (1) vpc InternetGateway (1) ig Subnet (1) subnet RouteTable (1) route-table Route (1) route-ig SecurityGroup (1) securityGroup SecurityGroupRuleIngress (4) sg-rule-ingress-ssh sg-rule-ingress-http sg-rule-ingress-https sg-rule-ingress-icmp ElasticIpAddress (1) ip Image (1) ubuntu 20.04 Volume (1) volume Instance (1) server route53Domain Domain (1) grucloud.com route53 HostedZone (1) grucloud.com. Record (4) app.grucloud.com. grucloud.com. grucloud.com.-gitpage-record-www grucloud.com.-mx
\ No newline at end of file
diff --git a/deploy/playbook/group_vars/all/vars.yml b/deploy/playbook/group_vars/all/vars.yml
index 92d1c367..f28223e8 100644
--- a/deploy/playbook/group_vars/all/vars.yml
+++ b/deploy/playbook/group_vars/all/vars.yml
@@ -25,7 +25,9 @@ firewall_allowed_tcp_ports:
- "80"
- "443"
- "9000"
-
+firewall_additional_rules:
+ - "iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -j MASQUERADE"
+ - "iptables -A INPUT -p tcp -s 10.0.0.0/16 -j ACCEPT"
# Database settings
# External volume
diff --git a/server/package.json b/server/package.json
index 061cc2ac..47542f2a 100644
--- a/server/package.json
+++ b/server/package.json
@@ -34,6 +34,7 @@
},
"dependencies": {
"@aws-sdk/client-ecs": "3.332.0",
+ "@aws-sdk/client-lambda": "3.429.0",
"@aws-sdk/client-s3": "3.332.0",
"@aws-sdk/client-sts": "3.429.0",
"@aws-sdk/s3-request-presigner": "3.332.0",
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 2782b4a5..19ffcbf6 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -26,9 +26,12 @@ const { contextSet404, contextSetOk } = require("utils/koaCommon");
const { middlewareUserBelongsToOrg } = require("../middleware");
const { DockerGcCreate } = require("../utils/rungc");
const { ecsTaskRun } = require("../utils/ecsTaskRun");
+const { lambdaRun } = require("../utils/lambdaRun");
const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
-const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
+const { GetObjectCommand } = require("@aws-sdk/client-s3");
+
+const { createS3Client } = require("../utils/S3Client");
const logger = require("logfilename")(__filename);
const { transformEnv } = require("../utils/envUtils");
@@ -81,9 +84,12 @@ const buildS3SignedUrl = ({ config, context, filename }) =>
}),
tryCatch(
pipe([
- //TODO credentials
(input) =>
- getSignedUrl(new S3Client({}), new GetObjectCommand(input), {}),
+ getSignedUrl(
+ createS3Client(process.env),
+ new GetObjectCommand(input),
+ {}
+ ),
]),
(error, bucket) =>
pipe([
@@ -133,8 +139,8 @@ const buildCmd = ({
bucketUpload,
"--s3-key",
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--s3-local-dir",
- "/app/my-repo/artifacts",
+ //"--s3-local-dir",
+ //"/app/my-repo/artifacts",
// "--ws-url",
// wsUrl,
// "--ws-room",
@@ -148,6 +154,7 @@ const buildCmd = ({
const buildGcFlow = ({
repository_url,
+ working_directory,
provider_type,
bucketUpload,
wsUrl,
@@ -162,22 +169,27 @@ const buildGcFlow = ({
when(
() => repository_url,
pipe([
+ append({
+ name: "rm",
+ run: `rm -rf /tmp/my-repo/`,
+ workingDirectory: `/tmp/`,
+ }),
append({
name: "Clone Repo",
- run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 my-repo",
+ run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 /tmp/my-repo",
+ }),
+ append({
+ name: "ls",
+ run: "ls -l",
+ workingDirectory: `/tmp/my-repo/${working_directory}`,
}),
append({
name: "npm install",
run: "npm install --loglevel=error",
- workingDirectory: "my-repo",
+ workingDirectory: `/tmp/my-repo/${working_directory}`,
}),
])
),
- // append({
- // name: "ls",
- // run: "ls -l",
- // workingDirectory: "my-repo",
- // }),
append({
name: "gc list",
run: `node_modules/.bin/gc ${buildCmd({
@@ -190,12 +202,36 @@ const buildGcFlow = ({
workspace_id,
run_id,
})}`,
- workingDirectory: "my-repo",
+ workingDirectory: `/tmp/my-repo/${working_directory}`,
}),
(steps) => ({ steps }),
JSON.stringify,
])();
+const grucloudEcsTask = ({ config }) =>
+ pipe([
+ ({ env_vars }) => ({
+ config,
+ container: {
+ name: "grucloud-cli",
+ command: [],
+ environment: pipe([
+ () => env_vars,
+ omit(["SERVICES"]),
+ map.entries(([name, value]) => [name, { name, value }]),
+ values,
+ ])(),
+ },
+ }),
+ tap((param) => {
+ assert(true);
+ }),
+ ecsTaskRun,
+ tap((param) => {
+ assert(true);
+ }),
+ ]);
+
exports.RunApi = ({ app, models }) => {
const { config } = app;
const { aws, infra } = config;
@@ -290,6 +326,7 @@ exports.RunApi = ({ app, models }) => {
GC_FLOW: buildGcFlow({
servicesCmd,
repository_url: project.repository_url,
+ working_directory: project.working_directory,
provider_type: cloudAuthentication.provider_type,
bucketUpload: aws.bucketUpload,
wsUrl: infra.wsUrl,
@@ -301,6 +338,13 @@ exports.RunApi = ({ app, models }) => {
WS_URL: infra.wsUrl,
WS_ROOM: `${org_id}/${project_id}/${workspace_id}/${run_id}`,
}),
+ transformEnv({
+ GRUCLOUD_OAUTH_SUBJECT: buildSubject({
+ org_id,
+ project_id,
+ workspace_id,
+ }),
+ }),
])(),
}),
tap((param) => {
@@ -339,45 +383,10 @@ exports.RunApi = ({ app, models }) => {
assert(Id);
}),
]),
+ eq(get("engine"), "lambda"),
+ lambdaRun(config),
// default is ecs
- pipe([
- assign({
- servicesCmd: pipe([
- get("env_vars.SERVICES", []),
- flatMap((service) => ["--include-groups", service]),
- ]),
- }),
- ({ org_id, project_id, workspace_id, env_vars }) => ({
- config,
- container: {
- name: "grucloud-cli",
- command: [],
- environment: pipe([
- () => env_vars,
- omit(["SERVICES"]),
- transformEnv({
- GRUCLOUD_OAUTH_SUBJECT: buildSubject({
- org_id,
- project_id,
- workspace_id,
- }),
- }),
- map.entries(([name, value]) => [
- name,
- { name, value },
- ]),
- values,
- ])(),
- },
- }),
- tap((param) => {
- assert(true);
- }),
- ecsTaskRun,
- tap((param) => {
- assert(true);
- }),
- ]),
+ grucloudEcsTask({ config }),
]),
])(),
}),
diff --git a/server/src/plugins/cloudDiagram/test/test005Run.js b/server/src/plugins/cloudDiagram/test/test005Run.js
index e7dcd7ee..93323d93 100644
--- a/server/src/plugins/cloudDiagram/test/test005Run.js
+++ b/server/src/plugins/cloudDiagram/test/test005Run.js
@@ -14,13 +14,19 @@ const payloadCreateDocker = {
reason: "my reason",
kind: "list",
status: "creating",
- engine: "docker", // ecs or docker
+ engine: "docker",
};
const payloadCreateEcs = {
reason: "my reason",
kind: "list",
status: "creating",
- engine: "ecs", // ecs or docker
+ engine: "ecs",
+};
+const payloadCreateLambda = {
+ reason: "my reason",
+ kind: "list",
+ status: "creating",
+ engine: "lambda",
};
const WebSocket = require("ws");
@@ -70,25 +76,25 @@ describe("Run No Auth", function () {
});
});
-const runCrudDocker = async ({
+const runCrud = async ({
client,
org_id,
project_id,
workspace_id,
- payloadCreateDocker,
+ payloadCreate,
}) => {
try {
// Create
const run = await client.post(
`v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/run`,
- payloadCreateDocker
+ payloadCreate
);
assert(run);
const { run_id, container_id } = run;
assert(run_id);
assert(container_id);
- assert.equal(run.reason, payloadCreateDocker.reason);
+ assert.equal(run.reason, payloadCreate.reason);
const ws = new WebSocket(`ws://localhost:9000`);
ws.on("open", () => {
@@ -181,23 +187,40 @@ describe("Run", function () {
await client.login();
});
it("CRUD aws docker", async () => {
- await runCrudDocker({
+ await runCrud({
client,
org_id,
project_id: project_aws_id,
workspace_id,
- payloadCreateDocker,
+ payloadCreate: payloadCreateDocker,
});
});
it("CRUD azure docker", async () => {
- await runCrudDocker({
+ await runCrud({
client,
org_id,
project_id: project_azure_id,
workspace_id,
- payloadCreateDocker,
+ payloadCreate: payloadCreateDocker,
});
});
+ it("CRUD aws lamda", async () => {
+ try {
+ // Create
+ const run = await client.post(
+ `v1/org/${org_id}/project/${project_id}/workspace/${workspace_id}/run`,
+ payloadCreateLambda
+ );
+ assert(run);
+ const { run_id, container_id } = run;
+ assert(run_id);
+ assert(container_id);
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+ });
+
it("CRUD ecs task", async () => {
try {
// Create
diff --git a/server/src/plugins/cloudDiagram/test/testEcsTask.js b/server/src/plugins/cloudDiagram/test/testEcsTask.js
index 746badf3..339cceaa 100644
--- a/server/src/plugins/cloudDiagram/test/testEcsTask.js
+++ b/server/src/plugins/cloudDiagram/test/testEcsTask.js
@@ -21,30 +21,32 @@ describe("EcsTask", function () {
config,
container: {
name: "grucloud-cli",
- command: [
- "list",
- "--json",
- "grucloud-result.json",
- "--infra",
- `/app/iac.js`,
- "--provider",
- "aws",
- "--s3-bucket",
- aws.bucketUpload,
- "--s3-key",
- "my-org/my-project/my-workspace/3",
- "--s3-local-dir",
- "/app/artifacts",
- "--ws-url",
- infra.wsUrl,
- "--ws-room",
- "my-org/my-project/my-workspace/3",
- ],
+ command: [],
environment: [
- { name: "AWSAccessKeyId", value: process.env.AWSAccessKeyId },
- { name: "AWSSecretKey", value: process.env.AWSSecretKey },
- { name: "AWS_REGION", value: process.env.AWS_REGION },
- { name: "CONTINUOUS_INTEGRATION", value: "1" },
+ {
+ name: "GC_FLOW",
+ value: '{"steps":[{"name":"Env","run":"env"}]}',
+ },
+ {
+ name: "S3_BUCKET",
+ value: aws.bucketUpload,
+ },
+ {
+ name: "S3_BUCKET_KEY",
+ value: "test/steps.txt",
+ },
+ {
+ name: "S3_AWS_REGION",
+ value: process.env.S3_AWS_REGION,
+ },
+ {
+ name: "WS_URL",
+ value: infra.wsUrl,
+ },
+ {
+ name: "WS_ROOM",
+ value: "room-test",
+ },
],
},
});
diff --git a/server/src/plugins/cloudDiagram/utils/ECSClient.js b/server/src/plugins/cloudDiagram/utils/ECSClient.js
new file mode 100644
index 00000000..30fbd025
--- /dev/null
+++ b/server/src/plugins/cloudDiagram/utils/ECSClient.js
@@ -0,0 +1,24 @@
+const assert = require("assert");
+const { pipe, tap } = require("rubico");
+const { defaultsDeep, when } = require("rubico/x");
+
+const { ECSClient } = require("@aws-sdk/client-ecs");
+
+exports.createECSClient = (env) =>
+ pipe([
+ tap((params) => {
+ assert(env);
+ assert(env.AWS_REGION);
+ }),
+ () => ({ region: env.AWS_REGION }),
+ when(
+ () => env.AWSAccessKeyId,
+ defaultsDeep({
+ credentials: {
+ accessKeyId: env.AWSAccessKeyId,
+ secretAccessKey: env.AWSSecretKey,
+ },
+ })
+ ),
+ (params) => new ECSClient(params),
+ ])();
diff --git a/server/src/plugins/cloudDiagram/utils/LambdaClient.js b/server/src/plugins/cloudDiagram/utils/LambdaClient.js
new file mode 100644
index 00000000..f91a6f32
--- /dev/null
+++ b/server/src/plugins/cloudDiagram/utils/LambdaClient.js
@@ -0,0 +1,24 @@
+const assert = require("assert");
+const { pipe, tap } = require("rubico");
+const { defaultsDeep, when } = require("rubico/x");
+
+const { LambdaClient } = require("@aws-sdk/client-lambda");
+
+exports.createLambdaClient = (env) =>
+ pipe([
+ tap((params) => {
+ assert(env);
+ assert(env.AWS_REGION);
+ }),
+ () => ({ region: env.AWS_REGION }),
+ when(
+ () => env.AWSAccessKeyId,
+ defaultsDeep({
+ credentials: {
+ accessKeyId: env.AWSAccessKeyId,
+ secretAccessKey: env.AWSSecretKey,
+ },
+ })
+ ),
+ (params) => new LambdaClient(params),
+ ])();
diff --git a/server/src/plugins/cloudDiagram/utils/S3Client.js b/server/src/plugins/cloudDiagram/utils/S3Client.js
new file mode 100644
index 00000000..d15bcfcb
--- /dev/null
+++ b/server/src/plugins/cloudDiagram/utils/S3Client.js
@@ -0,0 +1,24 @@
+const assert = require("assert");
+const { pipe, tap } = require("rubico");
+const { defaultsDeep, when } = require("rubico/x");
+
+const { S3Client } = require("@aws-sdk/client-s3");
+
+exports.createS3Client = (env) =>
+ pipe([
+ tap((params) => {
+ assert(env);
+ assert(env.S3_AWS_REGION);
+ }),
+ () => ({ region: env.S3_AWS_REGION }),
+ when(
+ () => env.S3_AWSAccessKeyId,
+ defaultsDeep({
+ credentials: {
+ accessKeyId: env.S3_AWSAccessKeyId,
+ secretAccessKey: env.S3_AWSSecretKey,
+ },
+ })
+ ),
+ (params) => new S3Client(params),
+ ])();
diff --git a/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js b/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
index 5592d2b2..1fe17024 100644
--- a/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
+++ b/server/src/plugins/cloudDiagram/utils/ecsTaskRun.js
@@ -2,7 +2,9 @@ const assert = require("assert");
const { pipe, tap, get, tryCatch, switchCase } = require("rubico");
const { first } = require("rubico/x");
const { inspect } = require("node:util");
-const { RunTaskCommand, ECSClient } = require("@aws-sdk/client-ecs");
+const { RunTaskCommand } = require("@aws-sdk/client-ecs");
+
+const { createECSClient } = require("./ECSClient");
const { AWSAccessKeyId, AWSSecretKey, AWS_REGION } = process.env;
@@ -20,6 +22,9 @@ exports.ecsTaskRun = ({ config: { ecs }, container }) =>
);
assert(ecs);
assert(ecs.cluster);
+ assert(ecs.subnets);
+ assert(ecs.securityGroups);
+
assert(AWSAccessKeyId);
assert(AWSSecretKey);
assert(AWS_REGION);
@@ -43,14 +48,7 @@ exports.ecsTaskRun = ({ config: { ecs }, container }) =>
log.debug(`RunTaskCommand: ${JSON.stringify(input)}`);
}),
(input) => new RunTaskCommand(input),
- (command) =>
- new ECSClient({
- region: process.env.AWS_REGION,
- credentials: {
- accessKeyId: process.env.AWSAccessKeyId,
- secretAccessKey: process.env.AWSSecretKey,
- },
- }).send(command),
+ (command) => createECSClient(process.env).send(command),
tap((params) => {
assert(params);
}),
diff --git a/server/src/plugins/cloudDiagram/utils/lambdaRun.js b/server/src/plugins/cloudDiagram/utils/lambdaRun.js
new file mode 100644
index 00000000..015d1d00
--- /dev/null
+++ b/server/src/plugins/cloudDiagram/utils/lambdaRun.js
@@ -0,0 +1,57 @@
+const assert = require("assert");
+const { pipe, tap, get, eq, tryCatch, switchCase } = require("rubico");
+const { InvokeCommand } = require("@aws-sdk/client-lambda");
+const { createLambdaClient } = require("./LambdaClient");
+const { AWSAccessKeyId, AWSSecretKey, AWS_REGION } = process.env;
+
+const log = require("logfilename")(__filename);
+
+exports.lambdaRun = ({ ecs }) =>
+ tryCatch(
+ pipe([
+ tap((params) => {
+ assert(ecs.subnets);
+ assert(ecs.securityGroups);
+ log.debug(
+ `lambdaRun subnets: ${ecs.subnets}, securityGroups: ${ecs.securityGroups}, AWS_REGION: ${AWS_REGION}`
+ );
+ assert(AWSAccessKeyId);
+ assert(AWSSecretKey);
+ assert(AWS_REGION);
+ }),
+ get("env_vars"),
+ tap((params) => {
+ assert(params);
+ }),
+ JSON.stringify,
+ (Payload) => ({
+ FunctionName: "grucloud",
+ InvocationType: "Event",
+ Payload,
+ }),
+ tap((input) => {
+ log.debug(`RunTaskCommand: ${JSON.stringify(input)}`);
+ }),
+ (input) => new InvokeCommand(input),
+ (command) => createLambdaClient(process.env).send(command),
+ tap((params) => {
+ assert(params);
+ }),
+ switchCase([
+ pipe([eq(get("StatusCode"), 202)]),
+ pipe([
+ tap((params) => {
+ assert(true);
+ }),
+ ]),
+ pipe([
+ tap((params) => {
+ log.error(`lambdaRun `, params);
+ }),
+ ]),
+ ]),
+ ]),
+ (error) => {
+ throw error;
+ }
+ );
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index 0edea71b..2ecd0acc 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -1,10 +1,8 @@
const assert = require("assert");
-const { pipe, tap, assign, get, eq, map, pick, flatMap } = require("rubico");
+const { pipe, tap, assign, get, eq, map, pick } = require("rubico");
const { values, unless } = require("rubico/x");
const path = require("path");
-const { transformEnv } = require("./envUtils");
-
exports.DockerGcRun = ({ app, models, ws }) => {
assert(app);
assert(models);
@@ -140,10 +138,9 @@ exports.DockerGcCreate = ({ app }) => {
outputDot: `resources.dot`,
outputSvg: `resources.svg`,
}),
-
assign({
name: () => `${containerName}-${run_id}`,
- Cmd: () => [],
+ Cmd: () => ["app.handler"],
outputGcListLocalPath: ({ outputGcList }) =>
path.resolve(outputDir, outputGcList),
HostConfig: () => ({
@@ -155,7 +152,6 @@ exports.DockerGcCreate = ({ app }) => {
Env: () =>
pipe([
() => env_vars,
- transformEnv({ GRUCLOUD_OAUTH_SUBJECT }),
map.entries(([key, value]) => [key, `${key}=${value}`]),
values,
])(),
@@ -173,6 +169,7 @@ exports.DockerGcCreate = ({ app }) => {
Env,
HostConfig,
WorkingDir: `/app/`,
+ Entrypoint: "/var/task/src/index.js",
},
}),
tap((xxx) => {
From 2c75af3834953e0ebbbbfd6a0b92c28200223671 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Mon, 4 Dec 2023 17:51:18 -0300
Subject: [PATCH 11/16] kind = plan
---
.travis.yml | 34 -------------------
server/src/plugins/cloudDiagram/api/runApi.js | 25 ++++++--------
.../plugins/cloudDiagram/test/test005Run.js | 16 ++++++++-
3 files changed, 25 insertions(+), 50 deletions(-)
delete mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index fceef307..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-sudo: required
-dist: bionic
-language: node_js
-node_js:
- - "13"
-
-services:
- - xvfb
- - postgresql
- - redis
-
-addons:
- chrome: stable
- postgresql: "10"
- apt:
- packages:
- - postgresql-10-postgis-2.4
-
-install:
- - cd client
- - npm i
- - cd ../server
- - npm i
-
-before_script:
- - psql -c 'create database dev;' -U postgres
- - psql -c 'create extension postgis;' -d dev -U postgres
-
-after_script:
- - cd client
- - npm run build
- - npm test
- - cd ../server
- - npm test
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 19ffcbf6..a4b7c97b 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -118,6 +118,7 @@ const buildCmd = ({
project_id,
workspace_id,
run_id,
+ kind,
}) =>
pipe([
tap((param) => {
@@ -125,30 +126,20 @@ const buildCmd = ({
assert(wsUrl);
assert(provider_type);
assert(run_id);
+ assert(kind);
}),
() => [
- "list",
+ kind,
"--json",
"artifacts/grucloud-result.json",
- "--graph",
- // "--infra",
- // `/app/iac.js`,
- // "--provider",
- // provider_type,
"--s3-bucket",
bucketUpload,
"--s3-key",
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
- //"--s3-local-dir",
- //"/app/my-repo/artifacts",
- // "--ws-url",
- // wsUrl,
- // "--ws-room",
- // `${org_id}/${project_id}/${workspace_id}/${run_id}`,
- "--title",
- '""',
+
...servicesCmd,
],
+ when(() => kind == "list", append(["--graph", "--title", '""'])),
callProp("join", " "),
])();
@@ -163,6 +154,7 @@ const buildGcFlow = ({
project_id,
workspace_id,
run_id,
+ kind,
}) =>
pipe([
() => [],
@@ -191,7 +183,7 @@ const buildGcFlow = ({
])
),
append({
- name: "gc list",
+ name: `gc ${kind}`,
run: `node_modules/.bin/gc ${buildCmd({
servicesCmd,
bucketUpload,
@@ -201,6 +193,7 @@ const buildGcFlow = ({
project_id,
workspace_id,
run_id,
+ kind,
})}`,
workingDirectory: `/tmp/my-repo/${working_directory}`,
}),
@@ -314,6 +307,7 @@ exports.RunApi = ({ app, models }) => {
project_id,
workspace_id,
run_id,
+ kind,
}) =>
pipe([
() => cloudAuthentication.env_vars,
@@ -334,6 +328,7 @@ exports.RunApi = ({ app, models }) => {
project_id,
workspace_id,
run_id,
+ kind,
}),
WS_URL: infra.wsUrl,
WS_ROOM: `${org_id}/${project_id}/${workspace_id}/${run_id}`,
diff --git a/server/src/plugins/cloudDiagram/test/test005Run.js b/server/src/plugins/cloudDiagram/test/test005Run.js
index 93323d93..a0a52d39 100644
--- a/server/src/plugins/cloudDiagram/test/test005Run.js
+++ b/server/src/plugins/cloudDiagram/test/test005Run.js
@@ -186,7 +186,7 @@ describe("Run", function () {
client = testMngr.client("alice");
await client.login();
});
- it("CRUD aws docker", async () => {
+ it("CRUD aws docker list", async () => {
await runCrud({
client,
org_id,
@@ -195,6 +195,20 @@ describe("Run", function () {
payloadCreate: payloadCreateDocker,
});
});
+ it("CRUD aws docker plan", async () => {
+ await runCrud({
+ client,
+ org_id,
+ project_id: project_aws_id,
+ workspace_id,
+ payloadCreate: {
+ reason: "my reason",
+ kind: "plan",
+ status: "creating",
+ engine: "docker",
+ },
+ });
+ });
it("CRUD azure docker", async () => {
await runCrud({
client,
From 9176d08c3e9b9166f08390029193b984c841b58f Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Tue, 5 Dec 2023 13:41:30 -0300
Subject: [PATCH 12/16] add apply and destroy
---
server/src/plugins/cloudDiagram/api/runApi.js | 14 +++++++++++++-
server/src/plugins/cloudDiagram/test/test005Run.js | 14 ++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index a4b7c97b..eee8f48c 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -20,6 +20,7 @@ const {
append,
when,
callProp,
+ isIn,
} = require("rubico/x");
const { contextSet404, contextSetOk } = require("utils/koaCommon");
@@ -47,6 +48,7 @@ const runAttributes = [
"status",
"engine",
"error",
+ "kind",
];
const buildSubject = ({ org_id, project_id, workspace_id, phase = "plan" }) =>
@@ -140,6 +142,8 @@ const buildCmd = ({
...servicesCmd,
],
when(() => kind == "list", append(["--graph", "--title", '""'])),
+ when(() => isIn(["apply", "destroy"])(kind), append("--force")),
+
callProp("join", " "),
])();
@@ -166,6 +170,14 @@ const buildGcFlow = ({
run: `rm -rf /tmp/my-repo/`,
workingDirectory: `/tmp/`,
}),
+ append({
+ name: "echo $GIT_REPO",
+ run: "echo $GIT_REPO",
+ }),
+ append({
+ name: "echo $GIT_BRANCH",
+ run: "echo $GIT_BRANCH",
+ }),
append({
name: "Clone Repo",
run: "git clone $GIT_REPO -b $GIT_BRANCH --depth 1 /tmp/my-repo",
@@ -177,7 +189,7 @@ const buildGcFlow = ({
}),
append({
name: "npm install",
- run: "npm install --loglevel=error",
+ run: "npm install --loglevel=error --no-audit",
workingDirectory: `/tmp/my-repo/${working_directory}`,
}),
])
diff --git a/server/src/plugins/cloudDiagram/test/test005Run.js b/server/src/plugins/cloudDiagram/test/test005Run.js
index a0a52d39..eb48973d 100644
--- a/server/src/plugins/cloudDiagram/test/test005Run.js
+++ b/server/src/plugins/cloudDiagram/test/test005Run.js
@@ -209,6 +209,20 @@ describe("Run", function () {
},
});
});
+ it("CRUD aws docker apply", async () => {
+ await runCrud({
+ client,
+ org_id,
+ project_id: project_aws_id,
+ workspace_id,
+ payloadCreate: {
+ reason: "my reason",
+ kind: "apply",
+ status: "creating",
+ engine: "docker",
+ },
+ });
+ });
it("CRUD azure docker", async () => {
await runCrud({
client,
From e2d22c10e8319d8db1683ffe47e70abdcae42073 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Thu, 7 Dec 2023 18:17:52 -0300
Subject: [PATCH 13/16] run api created at
---
server/src/plugins/cloudDiagram/api/runApi.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index eee8f48c..57b08431 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -49,6 +49,7 @@ const runAttributes = [
"engine",
"error",
"kind",
+ "created_at",
];
const buildSubject = ({ org_id, project_id, workspace_id, phase = "plan" }) =>
From 89614400e8ce6be41f9a7a08b8d04a250ba5ed82 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Fri, 8 Dec 2023 19:40:52 -0300
Subject: [PATCH 14/16] updated_at
---
server/src/plugins/cloudDiagram/api/runApi.js | 1 +
server/src/plugins/cloudDiagram/utils/rungc.js | 1 +
2 files changed, 2 insertions(+)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 57b08431..6339552d 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -50,6 +50,7 @@ const runAttributes = [
"error",
"kind",
"created_at",
+ "updated_at",
];
const buildSubject = ({ org_id, project_id, workspace_id, phase = "plan" }) =>
diff --git a/server/src/plugins/cloudDiagram/utils/rungc.js b/server/src/plugins/cloudDiagram/utils/rungc.js
index 2ecd0acc..66b52ff3 100644
--- a/server/src/plugins/cloudDiagram/utils/rungc.js
+++ b/server/src/plugins/cloudDiagram/utils/rungc.js
@@ -62,6 +62,7 @@ exports.DockerGcRun = ({ app, models, ws }) => {
(container_state) => ({
status: "completed",
container_state,
+ updated_at: new Date().toUTCString(),
}),
unless(
eq(get("container_state.ExitCode"), 0),
From 6e8ccf139a006df99c4a8d830c6d0c883e7386f3 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 9 Dec 2023 10:17:05 -0300
Subject: [PATCH 15/16] gzip_types
---
deploy/playbook/templates/web.nginx.conf.j2 | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/deploy/playbook/templates/web.nginx.conf.j2 b/deploy/playbook/templates/web.nginx.conf.j2
index 35410760..4f282210 100644
--- a/deploy/playbook/templates/web.nginx.conf.j2
+++ b/deploy/playbook/templates/web.nginx.conf.j2
@@ -24,7 +24,22 @@ http {
access_log /var/log/nginx/access.log main;
sendfile on;
gzip on;
-
+ gzip_types
+ # text/html is always compressed by HttpGzipModule
+ text/css
+ text/javascript
+ text/xml
+ text/plain
+ text/x-component
+ application/javascript
+ application/json
+ application/xml
+ application/rss+xml
+ font/truetype
+ font/opentype
+ application/vnd.ms-fontobject
+ image/svg+xml;
+
server {
listen 443 ssl;
http2 on;
From 811d1c14bcb362e95154e350bacb3f5b78499529 Mon Sep 17 00:00:00 2001
From: Frederic Heem
Date: Sat, 16 Dec 2023 19:03:19 -0300
Subject: [PATCH 16/16] run args
---
server/src/plugins/cloudDiagram/api/runApi.js | 8 +++++++-
.../src/plugins/cloudDiagram/migrations/010.do.app.do.sql | 1 +
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/server/src/plugins/cloudDiagram/api/runApi.js b/server/src/plugins/cloudDiagram/api/runApi.js
index 6339552d..b409e21c 100644
--- a/server/src/plugins/cloudDiagram/api/runApi.js
+++ b/server/src/plugins/cloudDiagram/api/runApi.js
@@ -49,6 +49,7 @@ const runAttributes = [
"engine",
"error",
"kind",
+ "args",
"created_at",
"updated_at",
];
@@ -114,6 +115,7 @@ const buildS3SignedUrl = ({ config, context, filename }) =>
]);
const buildCmd = ({
+ args = "",
servicesCmd,
bucketUpload,
wsUrl,
@@ -140,8 +142,8 @@ const buildCmd = ({
bucketUpload,
"--s3-key",
`${org_id}/${project_id}/${workspace_id}/${run_id}`,
-
...servicesCmd,
+ args,
],
when(() => kind == "list", append(["--graph", "--title", '""'])),
when(() => isIn(["apply", "destroy"])(kind), append("--force")),
@@ -161,6 +163,7 @@ const buildGcFlow = ({
workspace_id,
run_id,
kind,
+ args,
}) =>
pipe([
() => [],
@@ -199,6 +202,7 @@ const buildGcFlow = ({
append({
name: `gc ${kind}`,
run: `node_modules/.bin/gc ${buildCmd({
+ args,
servicesCmd,
bucketUpload,
wsUrl,
@@ -322,6 +326,7 @@ exports.RunApi = ({ app, models }) => {
workspace_id,
run_id,
kind,
+ args,
}) =>
pipe([
() => cloudAuthentication.env_vars,
@@ -343,6 +348,7 @@ exports.RunApi = ({ app, models }) => {
workspace_id,
run_id,
kind,
+ args,
}),
WS_URL: infra.wsUrl,
WS_ROOM: `${org_id}/${project_id}/${workspace_id}/${run_id}`,
diff --git a/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql b/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
index 350b7ee9..59827746 100644
--- a/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
+++ b/server/src/plugins/cloudDiagram/migrations/010.do.app.do.sql
@@ -56,6 +56,7 @@ CREATE TABLE IF NOT EXISTS run (
run_id SERIAL,
reason TEXT,
kind TEXT NOT NULL,
+ args TEXT,
engine TEXT,
container_id TEXT,
container_state JSONB,