Skip to content
87 changes: 76 additions & 11 deletions applications/wg-easy/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ tasks:
vars:
CHANNEL: '{{.CHANNEL | default "Unstable"}}'
SKIP_INSTALL: '{{.SKIP_INSTALL | default "false"}}'
AIRGAP: '{{.AIRGAP | default "false"}}'
ADMIN_CONSOLE_PASSWORD:
sh: uuidgen | cut -c1-13
deps:
Expand All @@ -610,34 +611,98 @@ tasks:
exit 1
fi

# Check if airgap build is available when airgap mode is enabled
if [ "{{.AIRGAP}}" = "true" ]; then
echo "Checking if airgap build is available for lastest release in channel {{.CHANNEL}}..."

# Get release list and extract app ID and channel ID
RELEASE_DATA=$(replicated release ls -o json)
APP_ID=$(echo "$RELEASE_DATA" | jq -r '.[0].appId')
CHANNEL_ID=$(echo "$RELEASE_DATA" | jq -r '.[0].activeChannels[] | select(.name == "{{.CHANNEL}}") | .id')

if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then
echo "Error: Could not retrieve app ID from releases"
exit 1
fi

if [ -z "$CHANNEL_ID" ] || [ "$CHANNEL_ID" = "null" ]; then
echo "Error: Could not find channel ID for channel {{.CHANNEL}}"
exit 1
fi

echo "Found app ID: $APP_ID, channel ID: $CHANNEL_ID"

# Get channel releases and check airgap build status
CHANNEL_RELEASES=$(replicated api get "v3/app/$APP_ID/channel/$CHANNEL_ID/releases")
AIRGAP_BUILD_STATUS=$(echo "$CHANNEL_RELEASES" | jq -r '.releases[0].airgapBuildStatus // "none"')
AIRGAP_BUILD_ERROR=$(echo "$CHANNEL_RELEASES" | jq -r '.releases[0].airgapBuildError // "none"')
AIRGAP_BUNDLE_IMAGES=$(echo "$CHANNEL_RELEASES" | jq -r '.releases[0].airgapBundleImages // "none"')
AIRGAP_LATEST_SEQUENCE=$(echo "$CHANNEL_RELEASES" | jq -r '.releases[0].sequence')

echo "Airgap build status: $AIRGAP_BUILD_STATUS"

if [ "$AIRGAP_BUILD_STATUS" = "metadata" ]; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking the status of the airgap build is nice. I think we should wait for the build to complete. As a user, it would be nice to just run task cmx-vm-install..., get some coffee and come back to find the deployment done.

We can add a new wait-airgap-build task or something like that, or we can just wait within cmx-vm-install task

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great idea, I've added new task airgap-build with polling and can be called separately or from cmx-vm-install.

e.g.

Check if user is set...
Check if license ID is set...
Airgap mode enabled, ensuring airgap build is ready...
Checking if airgap build is available for latest release in channel Unstable...
Found app ID: 2xzKY8D0vi6qlCGajpFLEumdsi6, channel ID: 2xzKY7R5vVrmM1CaE13yKqRKFXH
Airgap build status: metadata
Airgap has not been built yet. Triggering build...
{}Airgap build triggered. Polling every 10 seconds for up to 5 minutes...
Checking airgap build status... (attempt 1/30)
Airgap build current status: building
Checking airgap build status... (attempt 2/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 3/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 4/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 5/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 6/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 7/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 8/30)
Airgap build current status: building_bundle
Checking airgap build status... (attempt 9/30)
Airgap build current status: built
Airgap build completed successfully!
Airgap bundle images: [
  "debian:buster-slim",
  "docker.io/traefik:v3.0.0",
  "ghcr.io/wg-easy/wg-easy:14",
  "quay.io/jetstack/cert-manager-cainjector:v1.14.5",
  "quay.io/jetstack/cert-manager-controller:v1.14.5",
  "quay.io/jetstack/cert-manager-startupapicheck:v1.14.5",
  "quay.io/jetstack/cert-manager-webhook:v1.14.5",
  "registry.replicated.com/library/replicated-sdk-image:1.5.3"
]
SSH into the VM and download the app binary...

echo "Airgap has not been built yet. Triggering build..."
replicated api post "v3/app/$APP_ID/channel/$CHANNEL_ID/release/$AIRGAP_LATEST_SEQUENCE/airgap/build"
echo "Airgap build triggered. Run the task again later to check if it's ready."
exit 1
fi

if [ "$AIRGAP_BUILD_STATUS" != "built" ]; then
echo "Error: Airgap build is not ready. Status: $AIRGAP_BUILD_STATUS"
echo "Airgap build error (if any): $AIRGAP_BUILD_ERROR"
echo "Please wait for the airgap build to complete before installing in airgap mode."
exit 1
fi

echo "Airgap build is ready. Proceeding with installation..."
echo "Contents of airgap bundle images: $AIRGAP_BUNDLE_IMAGES"
fi

echo "SSH into the VM and download the app binary..."
SSH_BASE_CMD="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
if [ -n "{{.CMX_VM_PUBLIC_KEY}}" ]; then
SSH_BASE_CMD="$SSH_BASE_CMD -i {{.CMX_VM_PUBLIC_KEY}}"
fi
VM_SSH_CMD=$(replicated vm ls --output=json | jq -r ".[] | select(.name == \"{{.CMX_VM_NAME}}\") | \"$SSH_BASE_CMD -p \(.direct_ssh_port) {{.CMX_VM_USER}}@\(.direct_ssh_endpoint)\"")

# Determine download URL based on airgap setting
DOWNLOAD_URL="https://replicated.app/embedded/{{.APP_SLUG}}/{{.CHANNEL}}"
if [ "{{.AIRGAP}}" = "true" ]; then
DOWNLOAD_URL="${DOWNLOAD_URL}?airgap=true"
fi

echo "SSH base command: $SSH_BASE_CMD"
$VM_SSH_CMD << 'EOF'
$VM_SSH_CMD << EOF
set -e
echo 'Downloading {{.APP_NAME}} installer...'
curl -f 'https://replicated.app/embedded/{{.APP_NAME}}/{{.CHANNEL}}' -H 'Authorization: {{.REPLICATED_LICENSE_ID}}' -o {{.APP_NAME}}-{{.CHANNEL}}.tgz
echo 'Downloading {{.APP_SLUG}} installer...'
curl -f '$DOWNLOAD_URL' -H 'Authorization: {{.REPLICATED_LICENSE_ID}}' -o {{.APP_SLUG}}-{{.CHANNEL}}.tgz

echo 'Extracting installer...'
tar -xvzf {{.APP_NAME}}-{{.CHANNEL}}.tgz
tar -xvzf {{.APP_SLUG}}-{{.CHANNEL}}.tgz

echo "Binary is available at ./{{.APP_SLUG}}"
EOF

if [ "{{.SKIP_INSTALL}}" = "false" ]; then
echo "Installing {{.APP_NAME}}..."
sudo ./{{.APP_NAME}} install --license license.yaml --admin-console-password {{.ADMIN_CONSOLE_PASSWORD}} --yes
else
echo "Skipping installation as requested. Binary is available at ./{{.APP_NAME}}"
if [ "{{.AIRGAP}}" = "true" ]; then
echo "Updating network policy for airgap installation..."
NETWORK_ID=$(replicated vm ls --output=json | jq -r ".[] | select(.name == \"{{.CMX_VM_NAME}}\") | .network_id")
replicated network update policy $NETWORK_ID --policy airgap
fi
EOF

if [ "{{.SKIP_INSTALL}}" = "false" ]; then
INSTALL_CMD="sudo ./{{.APP_SLUG}} install --license license.yaml --admin-console-password {{.ADMIN_CONSOLE_PASSWORD}} --yes"
if [ "{{.AIRGAP}}" = "true" ]; then
INSTALL_CMD="${INSTALL_CMD} --airgap-bundle {{.APP_SLUG}}.airgap"
fi

echo "Running installation command: $INSTALL_CMD"
$VM_SSH_CMD << EOF
$INSTALL_CMD
EOF

echo "Exposing port 30000 on the VM..."
replicated vm port expose --port 30000 {{.CMX_VM_NAME}}

echo "Visit above URL to access the Admin Console, password: {{.ADMIN_CONSOLE_PASSWORD}}"
fi

Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,30 @@ spec:
weight: 0
helmUpgradeFlags:
- --wait
values:
cert-manager:
global:
imagePullSecrets:
- name: '{{repl ImagePullSecretName }}'
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "jetstack" }}/cert-manager-controller'
webhook:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "jetstack" }}/cert-manager-webhook'
cainjector:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "jetstack" }}/cert-manager-cainjector'
acmesolver:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "jetstack" }}/cert-manager-acmesolver'
startupapicheck:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "jetstack" }}/cert-manager-startupapicheck'

namespace: cert-manager
builder: {}
22 changes: 22 additions & 0 deletions applications/wg-easy/charts/cert-manager/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,45 @@ cert-manager:
# Override the namespace used to store the ConfigMap for leader election
namespace: "cert-manager"
installCRDs: true
# Controller image configuration
image:
registry: quay.io
repository: jetstack/cert-manager-controller
extraArgs:
- --cluster-resource-namespace=cert-manager
- --enable-certificate-owner-ref=true
resources:
requests:
cpu: 5m
memory: 45Mi
# Webhook image configuration
webhook:
image:
registry: quay.io
repository: jetstack/cert-manager-webhook
resources:
requests:
cpu: 5m
memory: 22Mi
# CA Injector image configuration
cainjector:
image:
registry: quay.io
repository: jetstack/cert-manager-cainjector
resources:
requests:
cpu: 5m
memory: 101Mi
# ACME Solver image configuration
acmesolver:
image:
registry: quay.io
repository: jetstack/cert-manager-acmesolver
# Startup API Check image configuration
startupapicheck:
image:
registry: quay.io
repository: jetstack/cert-manager-startupapicheck
local:
letsencrypt:
production: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ spec:
- --history-max=15
- --wait

values: {}
values:
replicated:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "registry.replicated.com" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "library" }}/replicated-sdk-image'
imagePullSecrets:
- name: '{{repl ImagePullSecretName }}'
namespace: replicated
builder: {}
3 changes: 3 additions & 0 deletions applications/wg-easy/charts/replicated/values.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Values for replicated-sdk chart
replicated:
enabled: true
image:
registry: registry.replicated.com
repository: "library/replicated-sdk-image"
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,13 @@ spec:
weight: 2
helmUpgradeFlags:
- --wait
values:
traefik:
image:
registry: '{{repl HasLocalRegistry | ternary LocalRegistryHost "docker.io" }}'
repository: '{{repl HasLocalRegistry | ternary LocalRegistryNamespace "library" }}/traefik'
deployment:
imagePullSecrets:
- name: '{{repl ImagePullSecretName }}'
namespace: traefik
builder: {}
3 changes: 3 additions & 0 deletions applications/wg-easy/charts/traefik/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ certs:
installStaging: false
dnsNames: []
traefik:
image:
registry: docker.io
repository: traefik
service:
type: NodePort
ports:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,31 @@ spec:
- --wait

values:
wg-easy:
services:
vpn:
# TODO: Template for stand alone KOTS install?
#type: NodePort
ports:
udp:
nodePort: repl{{ ConfigOption `vpn-port` | ParseInt }}
wireguard:
password: repl{{ ConfigOption `password` }}
host: repl{{ ConfigOption `domain` }}
port: repl{{ ConfigOption `vpn-port` | ParseInt }}
service:
vpn:
ports:
udp:
port: repl{{ ConfigOption `vpn-port` | ParseInt }}
wireguard:
password: repl{{ ConfigOption `password` }}
host: repl{{ ConfigOption `domain` }}
port: repl{{ ConfigOption `vpn-port` | ParseInt }}
templates:
traefikRoutes:
web-tls:
hostName: repl{{ ConfigOption `domain` }}
controllers:
wg-easy:
containers:
wg-container:
image:
repository: '{{repl HasLocalRegistry | ternary LocalRegistryHost "ghcr.io" }}/{{repl HasLocalRegistry | ternary LocalRegistryNamespace "wg-easy" }}/wg-easy'
defaultPodOptions:
imagePullSecrets:
- name: '{{repl ImagePullSecretName }}'
preflight:
image:
repository: '{{repl HasLocalRegistry | ternary LocalRegistryHost "docker.io" }}/{{repl HasLocalRegistry | ternary LocalRegistryNamespace "library" }}/debian:bookworm-slim'

namespace: wg-easy
builder: {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
spec:
collectors:
- sysctl:
image: debian:buster-slim
image: {{ .Values.preflight.image.repository }}
analyzers:
- sysctl:
checkName: IP forwarding enabled
Expand Down
7 changes: 7 additions & 0 deletions applications/wg-easy/charts/wg-easy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,10 @@ persistence:
retain: false
globalMounts:
- path: /etc/wireguard

preflight:
image:
repository: "docker.io/library/debian:bookworm-slim"

defaultPodOptions:
imagePullSecrets: []
4 changes: 2 additions & 2 deletions applications/wg-easy/replicated/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ spec:
icon: https://www.logo.wine/a/logo/WireGuard/WireGuard-Icon-Logo.wine.svg
#releaseNotes: These are our release notes
allowRollback: true
#additionalImages:
# - jenkins/jenkins:lts
additionalImages:
- debian:buster-slim
#additionalNamespaces should be populated by the Task file
#ports:
# - serviceName: wg-easy/web
Expand Down
Loading