configure aws config on builds

This commit is contained in:
mbecker20
2023-02-22 20:49:56 +00:00
parent 07d723a748
commit f2166c8435
24 changed files with 511 additions and 239 deletions

View File

@@ -89,19 +89,31 @@ fn default_core_mongo_db_name() -> String {
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AwsBuilderConfig {
#[serde(skip_serializing)]
pub access_key_id: String,
#[serde(skip_serializing)]
pub secret_access_key: String,
pub default_ami_id: String,
pub default_subnet_id: String,
pub default_key_pair_name: String,
#[serde(default)]
pub available_ami_accounts: AvailableAmiAccounts,
#[serde(default = "default_aws_region")]
pub default_region: String,
#[serde(default = "default_volume_gb")]
pub default_volume_gb: i32,
#[serde(default = "default_instance_type")]
pub default_instance_type: String,
#[serde(default)]
pub default_security_group_ids: Vec<String>,
#[serde(default)]
pub default_assign_public_ip: bool,
}
@@ -118,6 +130,17 @@ fn default_instance_type() -> String {
String::from("m5.2xlarge")
}
pub type AvailableAmiAccounts = HashMap<String, AmiAccounts>; // (ami_id, AmiAccounts)
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AmiAccounts {
pub name: String,
#[serde(default)]
pub github: Vec<String>,
#[serde(default)]
pub docker: Vec<String>,
}
pub type GithubUsername = String;
pub type GithubToken = String;
pub type GithubAccounts = HashMap<GithubUsername, GithubToken>;

View File

@@ -43,6 +43,9 @@ default_subnet_id = "your_default_subnet_id"
default_security_group_ids = ["sg_id_1", "sg_id_2"]
default_assign_public_ip = false
[aws.available_ami_accounts]
your_periphery_ami = { name = "default ami", github = ["github_username"], docker = ["docker_username"] }
[github_oauth]
enabled = true
id = "your_github_client_id"

View File

@@ -298,8 +298,8 @@ impl State {
self.update_update(update).await?;
return Err(e);
}
let (server, aws_client, log) = res.unwrap();
update.logs.push(log);
let (server, aws_client, logs) = res.unwrap();
update.logs.extend(logs);
self.update_update(update.clone()).await?;
(server, aws_client)
} else {
@@ -405,11 +405,11 @@ impl State {
async fn create_ec2_instance_for_build(
&self,
build: &Build,
) -> anyhow::Result<(Ec2Instance, Option<aws::Client>, Log)> {
) -> anyhow::Result<(Ec2Instance, Option<aws::Client>, Vec<Log>)> {
if build.aws_config.is_none() {
return Err(anyhow!("build has no aws_config attached"));
}
let start_ts = monitor_timestamp();
let start_instance_ts = monitor_timestamp();
let aws_config = build.aws_config.as_ref().unwrap();
let region = aws_config
.region
@@ -464,20 +464,29 @@ impl State {
assign_public_ip,
)
.await?;
let instance_id = &instance.instance_id;
let start_log = Log {
stage: "start build instance".to_string(),
success: true,
stdout: format!("instance id: {instance_id}\nami id: {ami_id}\ninstance type: {instance_type}\nvolume size: {volume_size_gb} GB\nsubnet id: {subnet_id}\nsecurity groups: {readable_sec_group_ids}"),
start_ts: start_instance_ts,
end_ts: monitor_timestamp(),
..Default::default()
};
let start_connect_ts = monitor_timestamp();
let mut res = Ok(String::new());
for _ in 0..BUILDER_POLL_MAX_TRIES {
let status = self.periphery.health_check(&instance.server).await;
if let Ok(_) = status {
let instance_id = &instance.instance_id;
let log = Log {
stage: "start build instance".to_string(),
let connect_log = Log {
stage: "build instance connected".to_string(),
success: true,
stdout: format!("instance id: {instance_id}\nami id: {ami_id}\ninstance type: {instance_type}\nvolume size: {volume_size_gb} GB\nsubnet id: {subnet_id}\nsecurity groups: {readable_sec_group_ids}"),
start_ts,
stdout: "established contact with periphery on builder".to_string(),
start_ts: start_connect_ts,
end_ts: monitor_timestamp(),
..Default::default()
};
return Ok((instance, Some(aws_client), log));
return Ok((instance, Some(aws_client), vec![start_log, connect_log]));
}
res = status;
tokio::time::sleep(Duration::from_secs(BUILDER_POLL_RATE_SECS)).await;

View File

@@ -1,5 +1,5 @@
import { useNavigate } from "@solidjs/router";
import { Component, createSignal } from "solid-js";
import { Component, createSignal, Show } from "solid-js";
import { client, pushNotification } from "..";
import { useAppState } from "../state/StateProvider";
import { Build, Deployment } from "../types";
@@ -42,12 +42,11 @@ const CopyMenu: Component<{
if (p.type === "build") {
promise = client.copy_build(p.id, {
name: newName(),
server_id: selectedId(),
});
} else {
promise = client.copy_deployment(p.id, {
name: newName(),
server_id: selectedId(),
server_id: selectedId()!,
});
}
toggleShow();
@@ -75,18 +74,20 @@ const CopyMenu: Component<{
value={newName()}
onEdit={setNewName}
/>
<Selector
label="target: "
selected={selectedId()}
items={servers.ids()!}
onSelect={setSelected}
itemMap={(id) => servers.get(id)!.server.name}
targetClass="blue"
targetStyle={{ display: "flex", gap: "0.5rem" }}
searchStyle={{ width: "100%" }}
position="bottom right"
useSearch
/>
<Show when={p.type === "deployment"}>
<Selector
label="target: "
selected={selectedId()!}
items={servers.ids()!}
onSelect={setSelected}
itemMap={(id) => servers.get(id)!.server.name}
targetClass="blue"
targetStyle={{ display: "flex", gap: "0.5rem" }}
searchStyle={{ width: "100%" }}
position="bottom right"
useSearch
/>
</Show>
</Flex>
<ConfirmButton
class="green"

View File

@@ -24,7 +24,7 @@ const Actions: Component<{}> = (p) => {
build().permissions![getId(user())] === PermissionLevel.Execute ||
build().permissions![getId(user())] === PermissionLevel.Update;
return (
<Show when={userCanExecute() && server()?.status === ServerStatus.Ok}>
<Show when={userCanExecute() && (server() ? server()?.status === ServerStatus.Ok : true)}>
<Grid class={combineClasses("card shadow")} gridTemplateRows="auto 1fr">
<h1>actions</h1>
<Grid style={{ height: "fit-content" }}>

View File

@@ -2,9 +2,7 @@ import { useNavigate, useParams } from "@solidjs/router";
import { Component, createEffect, onCleanup, Show } from "solid-js";
import { useAppDimensions } from "../../state/DimensionProvider";
import { useAppState } from "../../state/StateProvider";
import { useUser } from "../../state/UserProvider";
import { Operation, PermissionLevel } from "../../types";
import { combineClasses, getId } from "../../util/helpers";
import { Operation } from "../../types";
import NotFound from "../NotFound";
import Grid from "../shared/layout/Grid";
import Actions from "./Actions";

View File

@@ -70,13 +70,15 @@ const Header: Component<{}> = (p) => {
</Flex>
<Flex alignItems="center" justifyContent="space-between">
<Flex alignItems="center">
<A
href={`/server/${build().server_id}`}
class="text-hover"
style={{ opacity: 0.7, padding: 0 }}
>
{server()?.server.name}
</A>
<Show when={server()} fallback={<div style={{ opacity: 0.7 }}>{build().aws_config ? "aws build" : ""}</div>}>
<A
href={`/server/${build().server_id}`}
class="text-hover"
style={{ opacity: 0.7, padding: 0 }}
>
{server()?.server.name}
</A>
</Show>
<div style={{ opacity: 0.7 }}>build</div>
</Flex>
<div style={{ opacity: 0.7 }}>

View File

@@ -2,12 +2,10 @@ import { useParams } from "@solidjs/router";
import { Component, Show } from "solid-js";
import { useAppState } from "../../../state/StateProvider";
import { useUser } from "../../../state/UserProvider";
import { PermissionLevel } from "../../../types";
import { getId } from "../../../util/helpers";
import SimpleTabs from "../../shared/tabs/SimpleTabs";
import { Tab } from "../../shared/tabs/Tabs";
import BuildConfig from "./build-config/BuildConfig";
import GitConfig from "./git-config/GitConfig";
import BuilderConfig from "./builder/BuilderConfig";
import BuildConfig from "./config/BuildConfig";
import Owners from "./Permissions";
import { ConfigProvider } from "./Provider";
@@ -24,12 +22,12 @@ const BuildTabs: Component<{}> = (p) => {
tabs={
[
{
title: "repo",
element: () => <GitConfig />,
title: "config",
element: () => <BuildConfig />,
},
{
title: "build",
element: () => <BuildConfig />,
title: "builder",
element: () => <BuilderConfig />
},
user().admin && {
title: "collaborators",

View File

@@ -0,0 +1,116 @@
import { Component, Show } from "solid-js";
import { useAppState } from "../../../../state/StateProvider";
import Input from "../../../shared/Input";
import Flex from "../../../shared/layout/Flex";
import Selector from "../../../shared/menu/Selector";
import { useConfig } from "../Provider";
const AwsBuilderConfig: Component<{}> = (p) => {
const { build } = useConfig();
return (
<>
<Ami />
<InstanceType />
<VolumeSize />
<Show when={!build.updated}>
<div style={{ height: "4rem" }} />
</Show>
</>
);
};
const Ami: Component = () => {
const { aws_builder_config } = useAppState();
const { build, setBuild, userCanUpdate } = useConfig();
const get_ami_id = () => {
if (build.aws_config?.ami_id) {
return build.aws_config.ami_id;
} else {
return aws_builder_config()?.default_ami_id || "unknown";
}
};
const get_ami_name = (ami_id: string) => {
if (aws_builder_config() === undefined || ami_id === "unknown")
return "unknown";
return (
aws_builder_config()!.available_ami_accounts![ami_id]?.name || "unknown"
);
};
const ami_ids = () => {
if (aws_builder_config() === undefined) return [];
return Object.keys(aws_builder_config()!.available_ami_accounts!);
};
return (
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>ami</h1>
<Selector
targetClass="blue"
selected={get_ami_id()}
items={ami_ids()}
onSelect={(ami_id) => setBuild("aws_config", "ami_id", ami_id)}
itemMap={get_ami_name}
position="bottom right"
disabled={!userCanUpdate()}
useSearch
/>
</Flex>
);
};
const InstanceType: Component = () => {
const { aws_builder_config } = useAppState();
const { build, setBuild, userCanUpdate } = useConfig();
return (
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>instance type</h1>
<Input
placeholder={aws_builder_config()?.default_instance_type}
value={build.aws_config?.instance_type}
onEdit={(instance_type) =>
setBuild("aws_config", "instance_type", instance_type)
}
disabled={!userCanUpdate()}
/>
</Flex>
);
};
const VolumeSize: Component = () => {
const { aws_builder_config } = useAppState();
const { build, setBuild, userCanUpdate } = useConfig();
return (
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>volume size</h1>
<Flex gap="0.25rem" alignItems="center">
<Input
style={{ width: "4rem" }}
placeholder={aws_builder_config()?.default_volume_gb?.toString()}
value={
build.aws_config?.volume_gb
? build.aws_config.volume_gb.toString()
: ""
}
onEdit={(volume_size) =>
setBuild("aws_config", "volume_gb", Number(volume_size))
}
disabled={!userCanUpdate()}
/>
GB
</Flex>
</Flex>
);
};
export default AwsBuilderConfig;

View File

@@ -1,43 +1,27 @@
import { Component, Show } from "solid-js";
import { pushNotification, URL } from "../../../..";
import { combineClasses, copyToClipboard, getId } from "../../../../util/helpers";
import ConfirmButton from "../../../shared/ConfirmButton";
import Icon from "../../../shared/Icon";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import Loading from "../../../shared/loading/Loading";
import { useConfig } from "../Provider";
import Git from "./Git";
// import OnClone from "./OnClone";
import Loading from "../../../shared/loading/Loading";
import BuilderType from "./BuilderType";
import BuilderServer from "./BuilderServer";
import AwsBuilderConfig from "./AwsBuilderConfig";
const GitConfig: Component<{}> = (p) => {
const BuilderConfig: Component<{}> = (p) => {
const { build, reset, save, userCanUpdate } = useConfig();
const listenerUrl = () => `${URL}/api/listener/build/${getId(build)}`;
return (
<Show when={build.loaded}>
<Grid class="config">
<Grid class="config-items scroller">
<Git />
{/* <OnClone /> */}
<Show when={userCanUpdate()}>
<Grid class={combineClasses("config-item shadow")}>
<h1>webhook url</h1>
<Flex justifyContent="space-between" alignItems="center">
<div class="ellipsis" style={{ width: "250px" }}>
{listenerUrl()}
</div>
<ConfirmButton
class="blue"
onFirstClick={() => {
copyToClipboard(listenerUrl());
pushNotification("good", "copied url to clipboard");
}}
confirm={<Icon type="check" />}
>
<Icon type="clipboard" />
</ConfirmButton>
</Flex>
</Grid>
<BuilderType />
<Show when={build.server_id}>
<BuilderServer />
<div style={{ height: "12rem" }} />
</Show>
<Show when={build.aws_config}>
<AwsBuilderConfig />
</Show>
</Grid>
<Show when={userCanUpdate() && build.updated}>
@@ -66,4 +50,4 @@ const GitConfig: Component<{}> = (p) => {
);
};
export default GitConfig;
export default BuilderConfig;

View File

@@ -0,0 +1,46 @@
import { Component } from "solid-js";
import { useAppState } from "../../../../state/StateProvider";
import { PermissionLevel } from "../../../../types";
import { getId } from "../../../../util/helpers";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import Selector from "../../../shared/menu/Selector";
import { useConfig } from "../Provider";
const BuilderServer: Component<{}> = (p) => {
const { servers, getPermissionOnServer } = useAppState();
const { setBuild, server, userCanUpdate } = useConfig();
const availableServers = () => {
if (!servers.loaded()) return [];
return servers
.ids()!
.filter((id) => {
return getPermissionOnServer(id) === PermissionLevel.Update;
});
};
return (
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>builder server</h1>
<Selector
targetClass="blue"
selected={server()?.server ? getId(server()!.server) : "select server"}
items={availableServers()}
onSelect={(server_id) => setBuild("server_id", server_id)}
itemMap={(server_id) =>
server_id === "select server"
? "select server"
: servers.get(server_id)!.server.name
}
disabled={!userCanUpdate()}
position="bottom right"
useSearch
/>
</Flex>
);
};
export default BuilderServer;

View File

@@ -0,0 +1,60 @@
import { Component, Show } from "solid-js";
import { useAppState } from "../../../../state/StateProvider";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import { useConfig } from "../Provider";
const BuilderType: Component<{}> = (p) => {
const { servers } = useAppState();
const { build, setBuild, userCanUpdate } = useConfig();
const builderType = () => {
if (build.server_id) {
return "server";
} else if (build.aws_config) {
return "aws";
} else {
return undefined;
}
};
return (
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>builder type</h1>
<Show when={userCanUpdate()} fallback={<h2>{builderType()}</h2>}>
<Grid gap="0" gridTemplateColumns="1fr 1fr">
<button
class={builderType() === "server" ? "blue" : "grey"}
style={{ width: "100%" }}
onClick={() => {
if (builderType() !== "server") {
const server_id =
servers.ids()?.length || 0 > 0
? servers.ids()![0]
: undefined;
setBuild({ server_id, aws_config: undefined });
}
}}
>
server
</button>
<button
class={builderType() === "aws" ? "blue" : "grey"}
style={{ width: "100%" }}
onClick={() => {
if (builderType() !== "aws") {
setBuild({ server_id: undefined, aws_config: {} });
}
}}
>
aws
</button>
</Grid>
</Show>
</Flex>
);
};
export default BuilderType;

View File

@@ -1,12 +1,10 @@
import { Component, createEffect, createSignal, Show } from "solid-js";
import {
combineClasses,
parseDotEnvToEnvVars,
parseEnvVarseToDotEnv,
} from "../../../../util/helpers";
import { useToggle } from "../../../../util/hooks";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import CenterMenu from "../../../shared/menu/CenterMenu";
import TextArea from "../../../shared/TextArea";
import { useConfig } from "../Provider";
@@ -14,24 +12,26 @@ import { useConfig } from "../Provider";
const BuildArgs: Component<{}> = (p) => {
const { build, userCanUpdate } = useConfig();
return (
<Grid class={combineClasses("config-item shadow")}>
<Flex alignItems="center" justifyContent="space-between">
<h1>build args</h1>
<Flex alignItems="center" gap="0.2rem">
<Show
when={
!build.docker_build_args?.build_args ||
build.docker_build_args.build_args.length === 0
}
>
<div>none</div>
</Show>
<Show when={userCanUpdate()}>
<EditBuildArgs />
</Show>
</Flex>
<Flex
class="config-item shadow"
alignItems="center"
justifyContent="space-between"
>
<h1>build args</h1>
<Flex alignItems="center" gap="0.2rem">
<Show
when={
!build.docker_build_args?.build_args ||
build.docker_build_args.build_args.length === 0
}
>
<div>none</div>
</Show>
<Show when={userCanUpdate()}>
<EditBuildArgs />
</Show>
</Flex>
</Grid>
</Flex>
);
};

View File

@@ -9,6 +9,8 @@ import { useConfig } from "../Provider";
import Loading from "../../../shared/loading/Loading";
import BuildArgs from "./BuildArgs";
import Version from "./Version";
import Repo from "./Repo";
import ListenerUrl from "./ListenerUrl";
const BuildConfig: Component<{}> = (p) => {
const { build, reset, save, userCanUpdate } = useConfig();
@@ -17,9 +19,11 @@ const BuildConfig: Component<{}> = (p) => {
<Grid class="config">
<Grid class="config-items scroller">
<Version />
<Repo />
<Docker />
<BuildArgs />
<CliBuild />
<ListenerUrl />
</Grid>
<Show when={userCanUpdate() && build.updated}>
<Show

View File

@@ -10,15 +10,28 @@ import Selector from "../../../shared/menu/Selector";
import { useConfig } from "../Provider";
const Docker: Component<{}> = (p) => {
const { aws_builder_config } = useAppState();
const { build, setBuild, server, userCanUpdate } = useConfig();
const [dockerAccounts, setDockerAccounts] = createSignal<string[]>();
const [peripheryDockerAccounts, setPeripheryDockerAccounts] =
createSignal<string[]>();
createEffect(() => {
if (server()?.status === ServerStatus.Ok) {
client
.get_server_docker_accounts(build.server_id)
.then(setDockerAccounts);
.get_server_docker_accounts(build.server_id!)
.then(setPeripheryDockerAccounts);
}
});
const dockerAccounts = () => {
if (build.server_id) {
return peripheryDockerAccounts() || [];
} else if (build.aws_config) {
const ami_id =
build.aws_config?.ami_id || aws_builder_config()?.default_ami_id;
return ami_id
? aws_builder_config()?.available_ami_accounts![ami_id].docker || []
: [];
} else return [];
};
return (
<Grid class={combineClasses("config-item shadow")}>
<h1>docker build</h1> {/* checkbox here? */}
@@ -62,7 +75,7 @@ const Docker: Component<{}> = (p) => {
<Selector
targetClass="blue"
selected={build.docker_account || "none"}
items={["none", ...dockerAccounts()!]}
items={["none", ...dockerAccounts()]}
onSelect={(account) => {
setBuild(
"docker_account",

View File

@@ -0,0 +1,37 @@
import { Component, Show } from "solid-js";
import { pushNotification, URL } from "../../../..";
import { copyToClipboard, getId } from "../../../../util/helpers";
import ConfirmButton from "../../../shared/ConfirmButton";
import Icon from "../../../shared/Icon";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import { useConfig } from "../Provider";
const ListenerUrl: Component<{}> = (p) => {
const { build, userCanUpdate } = useConfig();
const listenerUrl = () => `${URL}/api/listener/build/${getId(build)}`;
return (
<Show when={userCanUpdate()}>
<Grid class="config-item shadow">
<h1>webhook url</h1>
<Flex justifyContent="space-between" alignItems="center">
<div class="ellipsis" style={{ width: "250px" }}>
{listenerUrl()}
</div>
<ConfirmButton
class="blue"
onFirstClick={() => {
copyToClipboard(listenerUrl());
pushNotification("good", "copied url to clipboard");
}}
confirm={<Icon type="check" />}
>
<Icon type="clipboard" />
</ConfirmButton>
</Flex>
</Grid>
</Show>
);
}
export default ListenerUrl;

View File

@@ -0,0 +1,90 @@
import { Component, createEffect, createSignal, Show } from "solid-js";
import Grid from "../../../shared/layout/Grid";
import { useConfig } from "../Provider";
import Flex from "../../../shared/layout/Flex";
import Input from "../../../shared/Input";
import { combineClasses } from "../../../../util/helpers";
import { useAppState } from "../../../../state/StateProvider";
import { client } from "../../../..";
import { ServerStatus } from "../../../../types";
import Selector from "../../../shared/menu/Selector";
const Repo: Component<{}> = (p) => {
const { aws_builder_config } = useAppState();
const { build, setBuild, server, userCanUpdate } = useConfig();
const [peripheryGithubAccounts, setPeripheryGithubAccounts] =
createSignal<string[]>();
createEffect(() => {
if (server()?.status === ServerStatus.Ok) {
client
.get_server_github_accounts(build.server_id!)
.then(setPeripheryGithubAccounts);
}
});
const githubAccounts = () => {
if (build.server_id) {
return peripheryGithubAccounts() || [];
} else if (build.aws_config) {
const ami_id =
build.aws_config?.ami_id || aws_builder_config()?.default_ami_id;
return ami_id
? aws_builder_config()?.available_ami_accounts![ami_id].github || []
: [];
} else return [];
};
return (
<Grid class={combineClasses("config-item shadow")}>
<h1>repo config</h1>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>repo: </h2>
<Input
placeholder="ie. solidjs/solid"
value={build.repo || ""}
onEdit={(value) => setBuild("repo", value)}
disabled={!userCanUpdate()}
/>
</Flex>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>branch: </h2>
<Input
placeholder="defaults to main"
value={build.branch || (userCanUpdate() ? "" : "main")}
onEdit={(value) => setBuild("branch", value)}
disabled={!userCanUpdate()}
/>
</Flex>
<Show when={githubAccounts()}>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>github account: </h2>
<Selector
targetClass="blue"
selected={build.github_account || "none"}
items={["none", ...githubAccounts()]}
onSelect={(account) => {
setBuild(
"github_account",
account === "none" ? undefined : account
);
}}
position="bottom right"
disabled={!userCanUpdate()}
/>
</Flex>
</Show>
</Grid>
);
};
export default Repo;

View File

@@ -1,78 +0,0 @@
import { Component, createEffect, createSignal } from "solid-js";
import Grid from "../../../shared/layout/Grid";
import { useConfig } from "../Provider";
import Flex from "../../../shared/layout/Flex";
import Input from "../../../shared/Input";
import Selector from "../../../shared/menu/Selector";
import { combineClasses } from "../../../../util/helpers";
import { client } from "../../../..";
import { ServerStatus } from "../../../../types";
const Git: Component<{}> = (p) => {
const { build, setBuild, server, userCanUpdate } = useConfig();
// const [githubAccounts, setGithubAccounts] = createSignal<string[]>();
// createEffect(() => {
// if (server()?.status === ServerStatus.Ok) {
// client.get_server_github_accounts(build.server_id).then(setGithubAccounts);
// }
// });
return (
<Grid class={combineClasses("config-item shadow")}>
<h1>github config</h1>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>repo: </h2>
<Input
placeholder="ie. solidjs/solid"
value={build.repo || ""}
onEdit={(value) => setBuild("repo", value)}
disabled={!userCanUpdate()}
/>
</Flex>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>branch: </h2>
<Input
placeholder="defaults to main"
value={build.branch || (userCanUpdate() ? "" : "main")}
onEdit={(value) => setBuild("branch", value)}
disabled={!userCanUpdate()}
/>
</Flex>
<Flex
justifyContent={userCanUpdate() ? "space-between" : undefined}
alignItems="center"
style={{ "flex-wrap": "wrap" }}
>
<h2>github account: </h2>
{/* <Selector
targetClass="blue"
selected={build.github_account || "none"}
items={["none", ...githubAccounts()!]}
onSelect={(account) => {
setBuild(
"github_account",
account === "none" ? undefined : account
);
}}
position="bottom right"
disabled={!userCanUpdate()}
/> */}
<Input
placeholder="github username"
value={build.github_account}
onEdit={value => setBuild("github_account", value)}
disabled={!userCanUpdate()}
/>
</Flex>
</Grid>
);
};
export default Git;

View File

@@ -1,63 +0,0 @@
import { Component } from "solid-js";
import { combineClasses } from "../../../../util/helpers";
import Input from "../../../shared/Input";
import Grid from "../../../shared/layout/Grid";
import { useConfig } from "../Provider";
import Flex from "../../../shared/layout/Flex";
const OnClone: Component = () => {
const { build, setBuild, userCanUpdate } = useConfig();
return (
<Grid class={combineClasses("config-item shadow")}>
{/* <h1>on clone</h1>
<Flex
alignItems="center"
justifyContent={userCanUpdate() ? "space-between" : undefined}
style={{ "flex-wrap": "wrap" }}
>
<h2>path:</h2>
<Input
placeholder="relative to repo"
value={build.on_clone?.path || ""}
onEdit={(path) => {
if (
path.length === 0 &&
(!build.on_clone ||
!build.on_clone.command ||
build.on_clone.command.length === 0)
) {
setBuild("on_clone", undefined);
}
setBuild("on_clone", { path });
}}
disabled={!userCanUpdate()}
/>
</Flex>
<Flex
alignItems="center"
justifyContent={userCanUpdate() ? "space-between" : undefined}
style={{ "flex-wrap": "wrap" }}
>
<h2>command:</h2>
<Input
placeholder="command"
value={build.on_clone?.command || ""}
onEdit={(command) => {
if (
command.length === 0 &&
(!build.on_clone ||
!build.on_clone.path ||
build.on_clone.path.length === 0)
) {
setBuild("on_clone", undefined);
}
setBuild("on_clone", { command });
}}
disabled={!userCanUpdate()}
/>
</Flex> */}
</Grid>
);
};
export default OnClone;

View File

@@ -1,5 +1,5 @@
import { useNavigate } from "@solidjs/router";
import { createContext, ParentComponent, useContext } from "solid-js";
import { createContext, createResource, ParentComponent, Resource, useContext } from "solid-js";
import { useWindowKeyDown } from "../util/hooks";
import {
useBuilds,
@@ -14,7 +14,8 @@ import {
} from "./hooks";
import connectToWs from "./ws";
import { useUser } from "./UserProvider";
import { PermissionLevel } from "../types";
import { AwsBuilderConfig, PermissionLevel } from "../types";
import { client } from "..";
export type State = {
usernames: ReturnType<typeof useUsernames>;
@@ -32,6 +33,7 @@ export type State = {
procedures: ReturnType<typeof useProcedures>;
getPermissionOnProcedure: (id: string) => PermissionLevel;
updates: ReturnType<typeof useUpdates>;
aws_builder_config: Resource<AwsBuilderConfig>;
};
const context = createContext<
@@ -51,6 +53,7 @@ export const AppStateProvider: ParentComponent = (p) => {
const procedures = useProcedures();
const deployments = useDeployments();
const usernames = useUsernames();
const [aws_builder_config] = createResource(() => client.get_aws_builder_defaults());
const state: State = {
usernames,
servers,
@@ -129,6 +132,7 @@ export const AppStateProvider: ParentComponent = (p) => {
}
},
updates: useUpdates(),
aws_builder_config,
};
// createEffect(() => {

View File

@@ -2,6 +2,8 @@
Generated by typeshare 1.0.0
*/
export type AvailableAmiAccounts = Record<string, AmiAccounts>;
export type PermissionsMap = Record<string, PermissionLevel>;
export interface Action {
@@ -74,6 +76,7 @@ export interface AwsBuilderConfig {
default_ami_id: string;
default_subnet_id: string;
default_key_pair_name: string;
available_ami_accounts?: AvailableAmiAccounts;
default_region?: string;
default_volume_gb?: number;
default_instance_type?: string;
@@ -81,6 +84,12 @@ export interface AwsBuilderConfig {
default_assign_public_ip?: boolean;
}
export interface AmiAccounts {
name: string;
github?: string[];
docker?: string[];
}
export interface Deployment {
_id?: string;
name: string;

View File

@@ -112,6 +112,9 @@ pub struct AwsBuilderConfig {
pub default_subnet_id: String,
pub default_key_pair_name: String,
#[serde(default)]
pub available_ami_accounts: AvailableAmiAccounts,
#[serde(default = "default_aws_region")]
pub default_region: String,
@@ -140,6 +143,19 @@ fn default_instance_type() -> String {
String::from("m5.2xlarge")
}
#[typeshare]
pub type AvailableAmiAccounts = HashMap<String, AmiAccounts>; // (ami_id, AmiAccounts)
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AmiAccounts {
pub name: String,
#[serde(default)]
pub github: Vec<String>,
#[serde(default)]
pub docker: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PeripheryConfig {
#[serde(default = "default_periphery_port")]