1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 13:55:21 +02:00

refactor(edge): move edge deploy script to react [EE-2689] (#6747)

This commit is contained in:
Chaim Lev-Ari 2022-04-14 13:14:23 +03:00 committed by GitHub
parent 328ce2f995
commit 85a7b7e0fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1079 additions and 342 deletions

View file

@ -0,0 +1,75 @@
import { FormControl } from '@/portainer/components/form-components/FormControl';
import { Input } from '@/portainer/components/form-components/Input';
import { FormSectionTitle } from '@/portainer/components/form-components/FormSectionTitle';
import { SwitchField } from '@/portainer/components/form-components/SwitchField';
import { OsSelector } from './OsSelector';
import { EdgeProperties } from './types';
interface Props {
setFieldValue<T>(key: string, value: T): void;
values: EdgeProperties;
hideIdGetter: boolean;
}
export function EdgePropertiesForm({
setFieldValue,
values,
hideIdGetter,
}: Props) {
return (
<form className="form-horizontal">
<FormSectionTitle>Edge script settings</FormSectionTitle>
<OsSelector
value={values.os}
onChange={(os) => setFieldValue('os', os)}
/>
{!hideIdGetter && (
<FormControl
label="Edge ID Generator"
tooltip="A bash script one liner that will generate the edge id"
inputId="edge-id-generator-input"
>
<Input
type="text"
name="edgeIdGenerator"
value={values.edgeIdGenerator}
id="edge-id-generator-input"
onChange={(e) => setFieldValue(e.target.name, e.target.value)}
/>
</FormControl>
)}
<div className="form-group">
<div className="col-sm-12">
<SwitchField
checked={values.allowSelfSignedCertificates}
label="Allow self-signed certificates"
tooltip="When allowing self-signed certificates the edge agent will ignore the domain validation when connecting to Portainer via HTTPS"
onChange={(checked) =>
setFieldValue('allowSelfSignedCertificates', checked)
}
/>
</div>
</div>
{values.platform !== 'k8s' && (
<FormControl
label="Environment variables"
tooltip="Comma separated list of environment variables that will be sourced from the host where the agent is deployed."
inputId="env-vars-input"
>
<Input
type="text"
name="envVars"
value={values.envVars}
id="env-vars-input"
onChange={(e) => setFieldValue(e.target.name, e.target.value)}
/>
</FormControl>
)}
</form>
);
}

View file

@ -0,0 +1,60 @@
import { useState } from 'react';
import { useStatus } from '@/portainer/services/api/status.service';
import { r2a } from '@/react-tools/react2angular';
import { useSettings } from '@/portainer/settings/settings.service';
import { EdgePropertiesForm } from './EdgePropertiesForm';
import { Scripts } from './Scripts';
import { EdgeProperties } from './types';
interface Props {
edgeKey: string;
edgeId?: string;
}
export function EdgeScriptForm({ edgeKey, edgeId }: Props) {
const [edgeProperties, setEdgeProperties] = useState<EdgeProperties>({
allowSelfSignedCertificates: true,
envVars: '',
edgeIdGenerator: '',
os: 'linux',
platform: 'swarm',
});
const settingsQuery = useSettings((settings) => settings.AgentSecret);
const versionQuery = useStatus((status) => status.Version);
if (!versionQuery.data) {
return null;
}
const agentVersion = versionQuery.data;
const agentSecret = settingsQuery.data;
return (
<>
<EdgePropertiesForm
setFieldValue={(key, value) =>
setEdgeProperties({ ...edgeProperties, [key]: value })
}
values={edgeProperties}
hideIdGetter={edgeId !== undefined}
/>
<Scripts
values={edgeProperties}
agentVersion={agentVersion}
edgeKey={edgeKey}
onPlatformChange={(platform) =>
setEdgeProperties({ ...edgeProperties, platform })
}
edgeId={edgeId}
agentSecret={agentSecret}
/>
</>
);
}
export const EdgeScriptFormAngular = r2a(EdgeScriptForm, ['edgeKey', 'edgeId']);

View file

@ -0,0 +1,45 @@
import { ButtonSelector } from '@/portainer/components/form-components/ButtonSelector/ButtonSelector';
import { OS } from './types';
interface Props {
value: OS;
onChange(value: OS): void;
}
export function OsSelector({ onChange, value }: Props) {
return (
<div className="form-group">
<div className="col-sm-12">
<ButtonSelector
size="small"
value={value}
onChange={(os: OS) => onChange(os)}
options={[
{
value: 'linux',
label: (
<>
<i className="fab fa-linux space-right" aria-hidden="true" />
Linux
</>
),
},
{
value: 'win',
label: (
<>
<i
className="fab fa-windows space-right"
aria-hidden="true"
/>
Windows
</>
),
},
]}
/>
</div>
</div>
);
}

View file

@ -0,0 +1,293 @@
import { useEffect } from 'react';
import _ from 'lodash';
import { Code } from '@/portainer/components/Code';
import { CopyButton } from '@/portainer/components/Button/CopyButton';
import { NavTabs } from '@/portainer/components/NavTabs/NavTabs';
import { getAgentShortVersion } from '@/portainer/views/endpoints/helpers';
import { EdgeProperties, Platform } from './types';
const commandsByOs = {
linux: [
{
id: 'swarm',
label: 'Docker Swarm',
command: buildLinuxSwarmCommand,
},
{
id: 'standalone',
label: 'Docker Standalone',
command: buildLinuxStandaloneCommand,
},
{
id: 'k8s',
label: 'Kubernetes',
command: buildKubernetesCommand,
},
],
win: [
{
id: 'swarm',
label: 'Docker Swarm',
command: buildWindowsSwarmCommand,
},
{
id: 'standalone',
label: 'Docker Standalone',
command: buildWindowsStandaloneCommand,
},
],
};
interface Props {
values: EdgeProperties;
edgeKey: string;
agentVersion: string;
edgeId?: string;
agentSecret?: string;
onPlatformChange(platform: Platform): void;
}
export function Scripts({
agentVersion,
values,
edgeKey,
edgeId,
agentSecret,
onPlatformChange,
}: Props) {
const {
os,
allowSelfSignedCertificates,
edgeIdGenerator,
envVars,
platform,
} = values;
useEffect(() => {
if (!commandsByOs[os].find((p) => p.id === platform)) {
onPlatformChange('standalone');
}
}, [os, platform, onPlatformChange]);
const options = commandsByOs[os].map((c) => {
const cmd = c.command(
agentVersion,
edgeIdGenerator,
edgeKey,
allowSelfSignedCertificates,
envVars,
edgeId,
agentSecret
);
return {
id: c.id,
label: c.label,
children: (
<>
<Code>{cmd}</Code>
<CopyButton copyText={cmd}>Copy</CopyButton>
</>
),
};
});
return (
<div className="row">
<div className="col-sm-12">
<NavTabs
selectedId={platform}
options={options}
onSelect={(id: Platform) => onPlatformChange(id)}
/>
</div>
</div>
);
}
function buildDockerEnvVars(envVars: string, defaultVars: string[]) {
const vars = defaultVars.concat(
envVars.split(',').filter((s) => s.length > 0)
);
return vars.map((s) => `-e ${s}`).join(' \\\n ');
}
function buildLinuxStandaloneCommand(
agentVersion: string,
edgeIdScript: string,
edgeKey: string,
allowSelfSignedCerts: boolean,
envVars: string,
edgeId?: string,
agentSecret?: string
) {
const env = buildDockerEnvVars(
envVars,
buildDefaultEnvVars(
edgeKey,
allowSelfSignedCerts,
!edgeIdScript ? edgeId : undefined,
agentSecret
)
);
return `${edgeIdScript ? `PORTAINER_EDGE_ID=$(${edgeIdScript}) \n\n` : ''}
docker run -d \\
-v /var/run/docker.sock:/var/run/docker.sock \\
-v /var/lib/docker/volumes:/var/lib/docker/volumes \\
-v /:/host \\
-v portainer_agent_data:/data \\
--restart always \\
${env} \\
--name portainer_edge_agent \\
portainer/agent:${agentVersion}
`;
}
function buildWindowsStandaloneCommand(
agentVersion: string,
edgeIdScript: string,
edgeKey: string,
allowSelfSignedCerts: boolean,
envVars: string,
edgeId?: string,
agentSecret?: string
) {
const env = buildDockerEnvVars(
envVars,
buildDefaultEnvVars(
edgeKey,
allowSelfSignedCerts,
edgeIdScript ? '$Env:PORTAINER_EDGE_ID' : edgeId,
agentSecret
)
);
return `${
edgeIdScript ? `$Env:PORTAINER_EDGE_ID = "@(${edgeIdScript})" \n\n` : ''
}
docker run -d \\
--mount type=npipe,src=\\\\.\\pipe\\docker_engine,dst=\\\\.\\pipe\\docker_engine \\
--mount type=bind,src=C:\\ProgramData\\docker\\volumes,dst=C:\\ProgramData\\docker\\volumes \\
--mount type=volume,src=portainer_agent_data,dst=C:\\data \\
--restart always \\
${env} \\
--name portainer_edge_agent \\
portainer/agent:${agentVersion}
`;
}
function buildLinuxSwarmCommand(
agentVersion: string,
edgeIdScript: string,
edgeKey: string,
allowSelfSignedCerts: boolean,
envVars: string,
edgeId?: string,
agentSecret?: string
) {
const env = buildDockerEnvVars(envVars, [
...buildDefaultEnvVars(
edgeKey,
allowSelfSignedCerts,
!edgeIdScript ? edgeId : undefined,
agentSecret
),
'AGENT_CLUSTER_ADDR=tasks.portainer_edge_agent',
]);
return `${edgeIdScript ? `PORTAINER_EDGE_ID=$(${edgeIdScript}) \n\n` : ''}
docker network create \\
--driver overlay \\
portainer_agent_network;
docker service create \\
--name portainer_edge_agent \\
--network portainer_agent_network \\
${env} \\
--mode global \\
--constraint 'node.platform.os == linux' \\
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \\
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \\
--mount type=bind,src=//,dst=/host \\
--mount type=volume,src=portainer_agent_data,dst=/data \\
portainer/agent:${agentVersion}
`;
}
function buildWindowsSwarmCommand(
agentVersion: string,
edgeIdScript: string,
edgeKey: string,
allowSelfSignedCerts: boolean,
envVars: string,
edgeId?: string,
agentSecret?: string
) {
const env = buildDockerEnvVars(envVars, [
...buildDefaultEnvVars(
edgeKey,
allowSelfSignedCerts,
edgeIdScript ? '$Env:PORTAINER_EDGE_ID' : edgeId,
agentSecret
),
'AGENT_CLUSTER_ADDR=tasks.portainer_edge_agent',
]);
return `${
edgeIdScript ? `$Env:PORTAINER_EDGE_ID = "@(${edgeIdScript})" \n\n` : ''
}
docker network create \\
--driver overlay \\
portainer_agent_network;
docker service create \\
--name portainer_edge_agent \\
--network portainer_agent_network \\
${env} \\
--mode global \\
--constraint 'node.platform.os == windows' \\
--mount type=npipe,src=\\\\.\\pipe\\docker_engine,dst=\\\\.\\pipe\\docker_engine \\
--mount type=bind,src=C:\\ProgramData\\docker\\volumes,dst=C:\\ProgramData\\docker\\volumes \\
--mount type=volume,src=portainer_agent_data,dst=C:\\data \\
portainer/agent:${agentVersion}
`;
}
function buildKubernetesCommand(
agentVersion: string,
edgeIdScript: string,
edgeKey: string,
allowSelfSignedCerts: boolean,
_envVars: string,
edgeId?: string,
agentSecret = ''
) {
const agentShortVersion = getAgentShortVersion(agentVersion);
const idEnvVar = edgeIdScript
? `PORTAINER_EDGE_ID=$(${edgeIdScript}) \n\n`
: '';
return `${idEnvVar}curl https://downloads.portainer.io/portainer-ee${agentShortVersion}-edge-agent-setup.sh |
bash -s -- "${
!edgeIdScript && edgeId ? edgeId : '$PORTAINER_EDGE_ID'
}" "${edgeKey}" "${allowSelfSignedCerts ? '1' : '0'}" "${agentSecret}"`;
}
function buildDefaultEnvVars(
edgeKey: string,
allowSelfSignedCerts: boolean,
edgeId = '$PORTAINER_EDGE_ID',
agentSecret = ''
) {
return _.compact([
'EDGE=1',
`EDGE_ID=${edgeId}`,
`EDGE_KEY=${edgeKey}`,
`EDGE_INSECURE_POLL=${allowSelfSignedCerts ? 1 : 0}`,
agentSecret ? `AGENT_SECRET=${agentSecret}` : ``,
]);
}

View file

@ -0,0 +1 @@
export { EdgeScriptForm, EdgeScriptFormAngular } from './EdgeScriptForm';

View file

@ -0,0 +1,10 @@
export type Platform = 'standalone' | 'swarm' | 'k8s';
export type OS = 'win' | 'linux';
export interface EdgeProperties {
os: OS;
allowSelfSignedCertificates: boolean;
envVars: string;
edgeIdGenerator: string;
platform: Platform;
}

View file

@ -0,0 +1,7 @@
import angular from 'angular';
import { EdgeScriptFormAngular } from './EdgeScriptForm';
export const componentsModule = angular
.module('app.edge.components', [])
.component('edgeScriptForm', EdgeScriptFormAngular).name;