Skip to content

Commit 57e6bba

Browse files
authored
Merge pull request #35 from ksuderman/feature/github-workflow
Add workflow to test deployments
2 parents c18cc9b + 0f3921d commit 57e6bba

File tree

2 files changed

+310
-0
lines changed

2 files changed

+310
-0
lines changed

.github/workflows/README.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# GitHub Workflows
2+
3+
## Test Galaxy Deployment on GCE
4+
5+
The `test-galaxy-gce.yml` workflow deploys Galaxy to a GCE VM and tests that the API is responsive.
6+
7+
### Setup Requirements
8+
9+
This workflow uses GCP Workload Identity Federation for authentication. You need to configure the following:
10+
11+
#### 1. Create a Workload Identity Pool and Provider
12+
13+
```bash
14+
# Set your project ID
15+
PROJECT_ID="your-project-id"
16+
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
17+
18+
# Create Workload Identity Pool
19+
gcloud iam workload-identity-pools create "github-actions" \
20+
--project="${PROJECT_ID}" \
21+
--location="global" \
22+
--display-name="GitHub Actions Pool"
23+
24+
# Create Workload Identity Provider
25+
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
26+
--project="${PROJECT_ID}" \
27+
--location="global" \
28+
--workload-identity-pool="github-actions" \
29+
--display-name="GitHub Provider" \
30+
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
31+
--issuer-uri="https://token.actions.githubusercontent.com"
32+
```
33+
34+
#### 2. Create a Service Account
35+
36+
```bash
37+
# Create service account
38+
gcloud iam service-accounts create github-actions-galaxy \
39+
--project="${PROJECT_ID}" \
40+
--display-name="GitHub Actions for Galaxy Testing"
41+
42+
# Grant necessary permissions
43+
gcloud projects add-iam-policy-binding $PROJECT_ID \
44+
--member="serviceAccount:github-actions-galaxy@${PROJECT_ID}.iam.gserviceaccount.com" \
45+
--role="roles/compute.instanceAdmin.v1"
46+
47+
gcloud projects add-iam-policy-binding $PROJECT_ID \
48+
--member="serviceAccount:github-actions-galaxy@${PROJECT_ID}.iam.gserviceaccount.com" \
49+
--role="roles/iam.serviceAccountUser"
50+
```
51+
52+
#### 3. Configure Workload Identity Binding
53+
54+
```bash
55+
# Replace with your GitHub repository
56+
REPO="your-github-org/galaxy-k8s-boot"
57+
58+
# Allow GitHub Actions from your repository to impersonate the service account
59+
gcloud iam service-accounts add-iam-policy-binding \
60+
"github-actions-galaxy@${PROJECT_ID}.iam.gserviceaccount.com" \
61+
--project="${PROJECT_ID}" \
62+
--role="roles/iam.workloadIdentityUser" \
63+
--member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-actions/attribute.repository/${REPO}"
64+
```
65+
66+
#### 4. Get the Workload Identity Provider Name
67+
68+
```bash
69+
gcloud iam workload-identity-pools providers describe "github-provider" \
70+
--project="${PROJECT_ID}" \
71+
--location="global" \
72+
--workload-identity-pool="github-actions" \
73+
--format="value(name)"
74+
```
75+
76+
This will output something like:
77+
```
78+
projects/123456789/locations/global/workloadIdentityPools/github-actions/providers/github-provider
79+
```
80+
81+
#### 5. Configure GitHub Secrets
82+
83+
Add the following secrets to your GitHub repository:
84+
85+
- `GCP_WORKLOAD_IDENTITY_PROVIDER`: The full provider name from step 4
86+
- `GCP_SERVICE_ACCOUNT`: The service account email (e.g., `github-actions-galaxy@PROJECT_ID.iam.gserviceaccount.com`)
87+
88+
### Running the Workflow
89+
90+
1. Go to Actions tab in your GitHub repository
91+
2. Select "Test Galaxy Deployment on GCE" workflow
92+
3. Click "Run workflow"
93+
4. Customize parameters as needed:
94+
- **galaxy-chart-version**: Galaxy Helm chart version (default: 6.6.0)
95+
- **git-repo**: Repository URL for galaxy-k8s-boot
96+
- **git-branch**: Branch to deploy
97+
- **instance-name**: Name for the test VM
98+
- **gcp-project**: GCP project ID
99+
- **gcp-zone**: GCP zone
100+
101+
### What the Workflow Does
102+
103+
1. Authenticates to GCP using Workload Identity
104+
2. Generates an SSH key pair for the VM
105+
3. Launches a GCE VM using `bin/launch_vm.sh`
106+
4. Waits for cloud-init to complete
107+
5. Copies the kubeconfig from the VM
108+
6. Waits for all Galaxy deployments to rollout (15 minute timeout)
109+
7. Tests the `/api/version` endpoint
110+
8. Validates the response is valid JSON
111+
9. Deletes the VM (always runs, even on failure)
112+
113+
### Troubleshooting
114+
115+
If the workflow fails:
116+
- Check the workflow logs for detailed error messages
117+
- Verify Workload Identity is configured correctly
118+
- Ensure the service account has necessary permissions
119+
- Check GCP quotas for compute instances
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
name: Test Galaxy Deployment on GCE
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
galaxy-chart-version:
7+
description: 'Galaxy Helm chart version'
8+
default: '6.6.0'
9+
required: true
10+
git-repo:
11+
description: 'Git repository URL for galaxy-k8s-boot'
12+
default: 'https://github.com/galaxyproject/galaxy-k8s-boot.git'
13+
required: true
14+
git-branch:
15+
description: 'Git branch to deploy'
16+
default: 'master'
17+
required: true
18+
instance-name:
19+
description: 'Name for the test VM instance'
20+
default: 'galaxy-test-ci'
21+
required: true
22+
gcp-project:
23+
description: 'GCP project ID'
24+
default: 'anvil-and-terra-development'
25+
required: true
26+
gcp-zone:
27+
description: 'GCP zone'
28+
default: 'us-east4-c'
29+
required: true
30+
31+
env:
32+
INSTANCE_NAME: ${{ inputs.instance-name }}
33+
GCP_PROJECT: ${{ inputs.gcp-project }}
34+
GCP_ZONE: ${{ inputs.gcp-zone }}
35+
36+
jobs:
37+
test-galaxy:
38+
name: Deploy and Test Galaxy
39+
runs-on: ubuntu-latest
40+
41+
permissions:
42+
contents: read
43+
id-token: write # Required for Workload Identity
44+
45+
steps:
46+
- name: Checkout repository
47+
uses: actions/checkout@v4
48+
49+
- name: Authenticate to Google Cloud
50+
uses: google-github-actions/auth@v2
51+
with:
52+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
53+
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
54+
55+
- name: Set up Cloud SDK
56+
uses: google-github-actions/setup-gcloud@v2
57+
58+
- name: Generate SSH key for VM
59+
id: ssh-key
60+
run: |
61+
ssh-keygen -t rsa -b 4096 -f ~/.ssh/galaxy-ci-key -N "" -C "github-actions"
62+
echo "public-key=$(cat ~/.ssh/galaxy-ci-key.pub)" >> $GITHUB_OUTPUT
63+
echo "private-key-path=$HOME/.ssh/galaxy-ci-key" >> $GITHUB_OUTPUT
64+
65+
- name: Launch Galaxy VM
66+
id: launch-vm
67+
run: |
68+
bin/launch_vm.sh \
69+
--project "${{ env.GCP_PROJECT }}" \
70+
--zone "${{ env.GCP_ZONE }}" \
71+
--ephemeral-only \
72+
--galaxy-chart-version "${{ inputs.galaxy-chart-version }}" \
73+
--git-repo "${{ inputs.git-repo }}" \
74+
--git-branch "${{ inputs.git-branch }}" \
75+
-k "${{ steps.ssh-key.outputs.public-key }}" \
76+
-f values/values.yml \
77+
"${{ env.INSTANCE_NAME }}"
78+
79+
- name: Get VM IP address
80+
id: vm-ip
81+
run: |
82+
sleep 10 # Give VM time to fully initialize
83+
VM_IP=$(gcloud compute instances describe "${{ env.INSTANCE_NAME }}" \
84+
--project="${{ env.GCP_PROJECT }}" \
85+
--zone="${{ env.GCP_ZONE }}" \
86+
--format='get(networkInterfaces[0].accessConfigs[0].natIP)')
87+
echo "ip=${VM_IP}" >> $GITHUB_OUTPUT
88+
echo "Galaxy VM IP: ${VM_IP}"
89+
90+
- name: Wait for cloud-init to complete
91+
run: |
92+
echo "Waiting for cloud-init to complete on ${{ steps.vm-ip.outputs.ip }}..."
93+
for i in {1..60}; do
94+
if gcloud compute ssh "${{ env.INSTANCE_NAME }}" \
95+
--project="${{ env.GCP_PROJECT }}" \
96+
--zone="${{ env.GCP_ZONE }}" \
97+
--ssh-key-file="${{ steps.ssh-key.outputs.private-key-path }}" \
98+
--command="cloud-init status --wait" 2>/dev/null; then
99+
echo "Cloud-init completed successfully"
100+
break
101+
fi
102+
echo "Attempt $i/60: Cloud-init still running or SSH not ready..."
103+
sleep 30
104+
done
105+
106+
- name: Copy kubeconfig from VM
107+
run: |
108+
mkdir -p ~/.kube
109+
gcloud compute scp \
110+
--project="${{ env.GCP_PROJECT }}" \
111+
--zone="${{ env.GCP_ZONE }}" \
112+
--ssh-key-file="${{ steps.ssh-key.outputs.private-key-path }}" \
113+
"ubuntu@${{ env.INSTANCE_NAME }}:/home/ubuntu/.kube/config" \
114+
~/.kube/config
115+
116+
# Update kubeconfig to use external IP
117+
sed -i "s|https://0.0.0.0:6443|https://${{ steps.vm-ip.outputs.ip }}:6443|" ~/.kube/config
118+
119+
- name: Wait for Galaxy deployments to rollout
120+
run: |
121+
echo "Waiting for Galaxy deployments to complete (timeout: 15 minutes)..."
122+
123+
# Get all deployments in the galaxy namespace
124+
DEPLOYMENTS=$(kubectl get deployments -n galaxy -o jsonpath='{.items[*].metadata.name}')
125+
126+
if [ -z "$DEPLOYMENTS" ]; then
127+
echo "No deployments found in galaxy namespace"
128+
exit 1
129+
fi
130+
131+
echo "Found deployments: $DEPLOYMENTS"
132+
133+
# Wait for each deployment to rollout
134+
for deployment in $DEPLOYMENTS; do
135+
echo "Waiting for deployment: $deployment"
136+
kubectl rollout status deployment/$deployment -n galaxy --timeout=15m
137+
done
138+
139+
echo "All deployments rolled out successfully"
140+
141+
- name: Test Galaxy API endpoint
142+
id: test-api
143+
run: |
144+
GALAXY_URL="http://${{ steps.vm-ip.outputs.ip }}/api/version"
145+
echo "Testing Galaxy API at: $GALAXY_URL"
146+
147+
# Wait for Galaxy to be responsive (max 5 minutes)
148+
for i in {1..30}; do
149+
if response=$(curl -s -f "$GALAXY_URL"); then
150+
echo "Galaxy API is responsive"
151+
echo "$response" | jq .
152+
153+
# Validate that response is valid JSON
154+
if echo "$response" | jq -e . >/dev/null 2>&1; then
155+
echo "Response is valid JSON ✓"
156+
echo "version-info=$response" >> $GITHUB_OUTPUT
157+
exit 0
158+
else
159+
echo "Response is not valid JSON"
160+
exit 1
161+
fi
162+
fi
163+
echo "Attempt $i/30: Galaxy not ready yet..."
164+
sleep 10
165+
done
166+
167+
echo "Galaxy API did not become responsive in time"
168+
exit 1
169+
170+
- name: Cleanup - Delete VM
171+
if: always()
172+
run: |
173+
echo "Cleaning up: Deleting VM ${{ env.INSTANCE_NAME }}"
174+
gcloud compute instances delete "${{ env.INSTANCE_NAME }}" \
175+
--project="${{ env.GCP_PROJECT }}" \
176+
--zone="${{ env.GCP_ZONE }}" \
177+
--quiet || echo "Failed to delete VM (may not exist)"
178+
179+
- name: Display test results
180+
if: always()
181+
run: |
182+
echo "=== Test Results ==="
183+
echo "Instance: ${{ env.INSTANCE_NAME }}"
184+
echo "IP: ${{ steps.vm-ip.outputs.ip }}"
185+
echo "Galaxy Chart Version: ${{ inputs.galaxy-chart-version }}"
186+
echo "Git Repo: ${{ inputs.git-repo }}"
187+
echo "Git Branch: ${{ inputs.git-branch }}"
188+
if [ -n "${{ steps.test-api.outputs.version-info }}" ]; then
189+
echo "Galaxy Version Info:"
190+
echo "${{ steps.test-api.outputs.version-info }}" | jq .
191+
fi

0 commit comments

Comments
 (0)