Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
671 changes: 671 additions & 0 deletions .github/workflows/nightly.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions .github/workflows/release-upgrade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ jobs:
# part of the shippable release tarball. release.yaml DOES build and
# push the Orca image (<registry>/orca:<tag>), but its manifests plus
# the test-only Garage cachestore are deployed here from hack/orca via
# hack/orca/deploy-stable.sh.
# hack/orca/deploy-integration.sh.
#
# Origin is real Azure Blob storage; cachestore is an in-cluster
# single-node Garage backed by a PVC. Confidential values (Azure
Expand Down Expand Up @@ -552,7 +552,7 @@ jobs:
set -euo pipefail
IMAGE="${REGISTRY,,}/orca:${TAG}"
echo "Deploying Orca image: ${IMAGE}"
./hack/orca/deploy-stable.sh \
./hack/orca/deploy-integration.sh \
--image "${IMAGE}" \
--azure-account "${ORCA_AZURE_ACCOUNT}" \
--azure-container "${ORCA_AZURE_CONTAINER}" \
Expand Down
10 changes: 8 additions & 2 deletions hack/orca/bootstrap-garage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,17 @@ secret_key="$(secret_value ORCA_CACHESTORE_S3_SECRET_KEY)"
if ! gexec key list 2>/dev/null | grep -q "${access_key}"; then
gexec key import "${access_key}" "${secret_key}" -n "${KEY_NAME}" --yes
fi
gexec key allow --create-bucket "${KEY_NAME}" >/dev/null 2>&1 || true
# Grant by the unique access key id, not the human-readable name: if the
# Secret's keys were ever regenerated, Garage ends up with multiple keys
# sharing the name "${KEY_NAME}", and a name-based grant is ambiguous (it can
# land on a stale key, leaving the key Orca actually uses unauthorized and
# Orca failing with a 403 on its first cachestore call). The access key id is
# unique, so granting on it always targets the key currently in the Secret.
gexec key allow --create-bucket "${access_key}" >/dev/null 2>&1 || true

# Ensure the cachestore bucket exists and is owned by the key.
gexec bucket info "${BUCKET}" >/dev/null 2>&1 || gexec bucket create "${BUCKET}"
gexec bucket allow --read --write --owner --key "${KEY_NAME}" "${BUCKET}" >/dev/null 2>&1 || true
gexec bucket allow --read --write --owner --key "${access_key}" "${BUCKET}" >/dev/null 2>&1 || true

# Verify the bucket is queryable before declaring success.
gexec bucket info "${BUCKET}" >/dev/null 2>&1 \
Expand Down
4 changes: 2 additions & 2 deletions hack/orca/create-credentials-secret.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# - ORCA_CACHESTORE_S3_ACCESS_KEY Garage S3 access key id (generated here)
# - ORCA_CACHESTORE_S3_SECRET_KEY Garage S3 secret key (generated here)
#
# The Garage S3 keys are the single source of truth: hack/orca/deploy-stable.sh
# The Garage S3 keys are the single source of truth: hack/orca/deploy-integration.sh
# imports them into Garage (via bootstrap-garage.sh) and injects them into
# Orca via envFrom. This script generates fresh ones in the format Garage
# requires (access id = "GK" + 12 hex bytes; secret = 32 hex bytes) unless
Expand Down Expand Up @@ -100,5 +100,5 @@ cat >&2 <<EOF
Secret ${SECRET_NAME} applied to namespace ${NAMESPACE}.

Garage S3 credentials are recorded only in the Secret and are imported
into Garage automatically by hack/orca/deploy-stable.sh.
into Garage automatically by hack/orca/deploy-integration.sh.
EOF
23 changes: 13 additions & 10 deletions hack/orca/deploy-stable.sh → hack/orca/deploy-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# deploy-stable.sh - Deploy Orca onto an integration cluster
# (unbounded-stable) with a real Azure Blob origin and an in-cluster
# single-node Garage cachestore (PVC-backed).
# deploy-integration.sh - Deploy Orca onto an integration cluster with a
# real Azure Blob origin and an in-cluster single-node Garage cachestore
# (PVC-backed).
#
# This is the integration-test deploy path. It is intentionally NOT
# coupled to Azurite (the dev emulator): the origin is a real Azure
# storage account. It renders the shippable Orca manifests from
# deploy/orca and the test-only Garage manifest from hack/orca/stable,
# applies them, bootstraps Garage, and waits for the rollout.
# This is the integration-test deploy path, used by both the
# unbounded-stable (release-upgrade) and unbounded-nightly workflows. It
# is deployment-neutral: it targets whatever cluster the current kube
# context / KUBECONFIG points at. It is intentionally NOT coupled to
# Azurite (the dev emulator): the origin is a real Azure storage account.
# It renders the shippable Orca manifests from deploy/orca and the
# test-only Garage manifest from hack/orca/integration, applies them,
# bootstraps Garage, and waits for the rollout.
#
# Confidential values (Azure account key, Garage S3 keys) come from a
# pre-created Secret named orca-credentials and are injected into Orca
Expand All @@ -22,7 +25,7 @@
# endpoint, origin id) are rendered into the orca-config ConfigMap from
# the flags below.
#
# Usage: deploy-stable.sh [flags]
# Usage: deploy-integration.sh [flags]
#
# --context CTX kubectl context to target (default: current)
# --namespace NS namespace to install into (default: unbounded-kube)
Expand Down Expand Up @@ -168,7 +171,7 @@ log "Rendering orca manifests (image ${ORCA_IMAGE}, origin azureblob account ${A

log "Rendering Garage manifest (PVC ${PVC_SIZE} on ${STORAGE_CLASS})"
( cd "${REPO_ROOT}" && go run ./hack/cmd/render-manifests \
--templates-dir "${REPO_ROOT}/hack/orca/stable" \
--templates-dir "${REPO_ROOT}/hack/orca/integration" \
--output-dir "${rendered_garage}" \
--set "Namespace=${NAMESPACE}" \
--set "CachestoreRegion=us-east-1" \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
---
# Integration-cluster Garage: a single-node Garage cluster used ONLY as
# Orca's cachestore (s3 driver) on the unbounded-stable integration
# cluster. Unlike the dev manifest (deploy/orca/dev/01-garage.yaml.tmpl)
# this does NOT double as an origin emulator: on unbounded-stable the
# origin is real Azure Blob storage, so the only bucket created here is
# the cachestore bucket (orca-cache).
# Orca's cachestore (s3 driver) on an integration cluster (e.g.
# unbounded-stable or unbounded-nightly). Unlike the dev manifest
# (deploy/orca/dev/01-garage.yaml.tmpl) this does NOT double as an origin
# emulator: on an integration cluster the origin is real Azure Blob
# storage, so the only bucket created here is the cachestore bucket
# (orca-cache).
#
# This lives under hack/ on purpose: Garage is a test/integration
# dependency, not a component we ship to customers, so it must not live
Expand All @@ -29,7 +30,7 @@ metadata:
namespace: {{ default "unbounded-kube" .Namespace }}
labels:
app.kubernetes.io/name: garage
app.kubernetes.io/part-of: orca-stable
app.kubernetes.io/part-of: orca
data:
garage.toml: |
metadata_dir = "/var/lib/garage/meta"
Expand All @@ -51,7 +52,7 @@ data:

[admin]
api_bind_addr = "[::]:3903"
admin_token = "{{ default "orca-stable-admin-token" .GarageAdminToken }}"
admin_token = "{{ default "orca-admin-token" .GarageAdminToken }}"

---
apiVersion: v1
Expand All @@ -61,7 +62,7 @@ metadata:
namespace: {{ default "unbounded-kube" .Namespace }}
labels:
app.kubernetes.io/name: garage
app.kubernetes.io/part-of: orca-stable
app.kubernetes.io/part-of: orca
spec:
accessModes:
- ReadWriteOnce
Expand All @@ -78,7 +79,7 @@ metadata:
namespace: {{ default "unbounded-kube" .Namespace }}
labels:
app.kubernetes.io/name: garage
app.kubernetes.io/part-of: orca-stable
app.kubernetes.io/part-of: orca
spec:
type: ClusterIP
selector:
Expand All @@ -97,7 +98,7 @@ metadata:
namespace: {{ default "unbounded-kube" .Namespace }}
labels:
app.kubernetes.io/name: garage
app.kubernetes.io/part-of: orca-stable
app.kubernetes.io/part-of: orca
spec:
replicas: 1
# Recreate: the data PVC is ReadWriteOnce, so the old pod must release
Expand All @@ -112,7 +113,7 @@ spec:
metadata:
labels:
app.kubernetes.io/name: garage
app.kubernetes.io/part-of: orca-stable
app.kubernetes.io/part-of: orca
spec:
containers:
- name: garage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# smoke-stable.sh - Functional end-to-end smoke test for an Orca deploy
# on an integration cluster (real Azure Blob origin + Garage cachestore).
# smoke-integration.sh - Functional end-to-end smoke test for an Orca
# deploy on an integration cluster (real Azure Blob origin + Garage
# cachestore).
#
# It generates a large random object, uploads it to the Azure origin
# container, then fetches it through Orca's edge twice:
Expand All @@ -23,7 +24,7 @@
# Requires: kubectl, az (Azure CLI), curl, dd, and a SHA-256 tool
# (sha256sum, shasum, or openssl).
#
# Usage: smoke-stable.sh [flags]
# Usage: smoke-integration.sh [flags]
#
# --context CTX kubectl context to target (default: current)
# --namespace NS namespace Orca is deployed in (default: unbounded-kube)
Expand Down
49 changes: 44 additions & 5 deletions hack/scripts/setup-deploy-environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@
set -euo pipefail
IFS=$'\n\t'

# This script is meant to run non-interactively (it is also invoked by
# setup-nightly-cluster.sh). Disable gh's pager so the secret/variable list
# summaries below never drop the caller into an interactive pager.
export GH_PAGER=cat

REPO="Azure/unbounded"
MANAGE_CNI_PLUGIN="true"
ASSUME_YES="false"
DEPLOY_CHANNEL="stable"

ENV_NAME=""
KUBECONFIG_PATH=""
Expand Down Expand Up @@ -59,6 +65,7 @@ Required:

Optional:
--manage-cni-plugin BOOL Whether unbounded manages the CNI (true|false). Default: true
--channel CHANNEL Deploy channel for the "next steps" hint: stable|nightly. Default: stable
--orca-azure-account NAME Azure storage account for the Orca origin (enables Orca deploy)
--orca-azure-container NAME Azure blob container for the Orca origin
--orca-azure-endpoint URL Azure blob endpoint (optional; blank => *.blob.core.windows.net)
Expand Down Expand Up @@ -96,6 +103,7 @@ while [[ $# -gt 0 ]]; do
--site-node-cidr) require_value "$1" "${2:-}"; SITE_NODE_CIDR="$2"; shift 2 ;;
--site-pod-cidr) require_value "$1" "${2:-}"; SITE_POD_CIDR="$2"; shift 2 ;;
--manage-cni-plugin) require_value "$1" "${2:-}"; MANAGE_CNI_PLUGIN="$2"; shift 2 ;;
--channel) require_value "$1" "${2:-}"; DEPLOY_CHANNEL="$2"; shift 2 ;;
--orca-azure-account) require_value "$1" "${2:-}"; ORCA_AZURE_ACCOUNT="$2"; shift 2 ;;
--orca-azure-container) require_value "$1" "${2:-}"; ORCA_AZURE_CONTAINER="$2"; shift 2 ;;
--orca-azure-endpoint) require_value "$1" "${2:-}"; ORCA_AZURE_ENDPOINT="$2"; shift 2 ;;
Expand Down Expand Up @@ -135,6 +143,12 @@ case "$MANAGE_CNI_PLUGIN" in
*) die "--manage-cni-plugin must be 'true' or 'false', got '$MANAGE_CNI_PLUGIN'" ;;
esac

# Validate deploy channel (only affects the "next steps" hint printed below).
case "$DEPLOY_CHANNEL" in
stable|nightly) ;;
*) die "--channel must be 'stable' or 'nightly', got '$DEPLOY_CHANNEL'" ;;
esac

# Validate Orca config: account and container go together (endpoint is
# optional). If neither is set, the Orca deploy job is left unconfigured.
if [[ -n "$ORCA_AZURE_ACCOUNT" && -z "$ORCA_AZURE_CONTAINER" ]]; then
Expand Down Expand Up @@ -227,6 +241,14 @@ fi
set_var() {
local name="$1"
local value="$2"
# GitHub Actions variables cannot be empty (the API returns HTTP 422 on a
# missing value). An unset variable already resolves to "" in the workflow,
# which is the intended behavior (e.g. a blank ORCA_AZURE_ENDPOINT => the
# Orca driver uses the default *.blob.core.windows.net). So skip empties.
if [[ -z "$value" ]]; then
echo "==> Skipping empty variable $name"
return 0
fi
echo "==> Setting variable $name"
if ! gh variable set "$name" \
--repo "$REPO" \
Expand Down Expand Up @@ -264,17 +286,34 @@ cat <<EOF

Environment $ENV_NAME configured.

EOF

# Gateway nodes are labeled by forge's gateway pool, so no manual labeling
# step is needed (both stable and nightly run on forge-built clusters). The
# trigger differs per channel: stable deploys release tags via
# release-upgrade.yaml; nightly deploys a snapshot of main via nightly.yaml.
if [[ "$DEPLOY_CHANNEL" == "nightly" ]]; then
cat <<EOF
Next steps:

1. Label at least one node as a gateway:
kubectl label node <node-name> \\
unbounded-cloud.io/unbounded-net-gateway=true --overwrite
1. Trigger the first install (run once per cluster):
gh workflow run nightly.yaml \\
--repo $REPO \\
-f force_init=true

2. Subsequent nightly snapshots of main deploy automatically to $ENV_NAME
at 06:00 UTC.
EOF
else
cat <<EOF
Next steps:

2. Trigger the first install (run once per cluster):
1. Trigger the first install (run once per cluster):
gh workflow run release-upgrade.yaml \\
--repo $REPO \\
-f tag=vX.Y.Z \\
-f force_init=true

3. Subsequent published releases will deploy automatically to $ENV_NAME.
2. Subsequent published releases will deploy automatically to $ENV_NAME.
EOF
fi
Loading
Loading