-
Notifications
You must be signed in to change notification settings - Fork 115
Expand file tree
/
Copy pathdeploy.sh
More file actions
executable file
·454 lines (394 loc) · 18.5 KB
/
Copy pathdeploy.sh
File metadata and controls
executable file
·454 lines (394 loc) · 18.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
#!/bin/bash
# OpenShift Deployment Script for vTeam Ambient Agentic Runner
# Usage: ./deploy.sh
# Or with environment variables: NAMESPACE=my-namespace ./deploy.sh
# Note: This script deploys pre-built images. Build and push images first.
set -e
# Always run from the script's directory (manifests root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Load .env file if it exists (optional for local setups)
if [ -f ".env" ]; then
set -a # automatically export all variables
source .env
set +a
fi
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Helper: Run the OAuth setup (Route host, OAuthClient, Secret)
oauth_setup() {
echo -e "${YELLOW}Configuring OpenShift OAuth for the frontend...${NC}"
# Determine Route name (try known names then fallback by label)
ROUTE_NAME_CANDIDATE="${ROUTE_NAME:-}"
if [[ -z "$ROUTE_NAME_CANDIDATE" ]]; then
if oc get route frontend-route -n ${NAMESPACE} >/dev/null 2>&1; then
ROUTE_NAME_CANDIDATE="frontend-route"
elif oc get route frontend -n ${NAMESPACE} >/dev/null 2>&1; then
ROUTE_NAME_CANDIDATE="frontend"
else
ROUTE_NAME_CANDIDATE=$(oc get route -n ${NAMESPACE} -l app=frontend -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
fi
fi
if [[ -z "$ROUTE_NAME_CANDIDATE" ]]; then
echo -e "${RED}❌ Could not find a Route for the frontend in namespace ${NAMESPACE}.${NC}"
echo -e "${YELLOW}Make sure manifests are applied and a Route exists (e.g., name 'frontend-route').${NC}"
return 1
fi
ROUTE_NAME="$ROUTE_NAME_CANDIDATE"
echo -e "${BLUE}Using Route: ${ROUTE_NAME}${NC}"
# Ensure Route host is set to <namespace>.<cluster apps domain>
echo -e "${BLUE}Setting Route host if needed...${NC}"
ROUTE_DOMAIN=$(oc get ingresses.config cluster -o jsonpath='{.spec.domain}')
if [[ -z "$ROUTE_DOMAIN" ]]; then
echo -e "${YELLOW}Could not detect cluster apps domain; skipping Route host patch.${NC}"
else
DESIRED_HOST="${NAMESPACE}.${ROUTE_DOMAIN}"
CURRENT_HOST=$(oc -n ${NAMESPACE} get route ${ROUTE_NAME} -o jsonpath='{.spec.host}' 2>/dev/null || true)
if [[ -z "$CURRENT_HOST" || "$CURRENT_HOST" != "$DESIRED_HOST" ]]; then
echo -e "${BLUE}Patching Route host to ${DESIRED_HOST}...${NC}"
oc -n ${NAMESPACE} patch route ${ROUTE_NAME} --type=merge -p "{\"spec\":{\"host\":\"${DESIRED_HOST}\"}}"
else
echo -e "${GREEN}Route host already set to ${CURRENT_HOST}${NC}"
fi
fi
ROUTE_HOST=$(oc -n ${NAMESPACE} get route ${ROUTE_NAME} -o jsonpath='{.spec.host}' 2>/dev/null || true)
if [[ -z "$ROUTE_HOST" ]]; then
echo -e "${YELLOW}Route host is empty; OAuthClient redirect URI may be incomplete.${NC}"
else
echo -e "${GREEN}Route host: https://${ROUTE_HOST}${NC}"
fi
# Create/Update cluster-scoped OAuthClient (requires cluster-admin)
echo -e "${BLUE}Creating/Updating OAuthClient 'ambient-frontend'...${NC}"
cat > /tmp/ambient-frontend-oauthclient.yaml <<EOF
apiVersion: oauth.openshift.io/v1
kind: OAuthClient
metadata:
name: ambient-frontend
secret: ${CLIENT_SECRET_VALUE}
redirectURIs:
- https://${ROUTE_HOST}/oauth/callback
grantMethod: auto
EOF
set +e
oc apply -f /tmp/ambient-frontend-oauthclient.yaml
OAUTH_APPLY_RC=$?
set -e
rm -f /tmp/ambient-frontend-oauthclient.yaml
if [[ ${OAUTH_APPLY_RC} -ne 0 ]]; then
echo -e "${YELLOW}⚠️ Could not create/update cluster-scoped OAuthClient. You likely need cluster-admin.${NC}"
echo -e "${YELLOW}Ask an admin to run:${NC}"
echo "oc apply -f - <<'EOF'"
echo "apiVersion: oauth.openshift.io/v1"
echo "kind: OAuthClient"
echo "metadata:"
echo " name: ambient-frontend"
echo "secret: ${CLIENT_SECRET_VALUE}"
echo "redirectURIs:"
echo "- https://${ROUTE_HOST}/oauth/callback"
echo "grantMethod: auto"
echo "EOF"
else
echo -e "${GREEN}✅ OAuthClient configured${NC}"
fi
# Create/Update the frontend OAuth secret in the namespace
echo -e "${BLUE}Creating/Updating Secret 'frontend-oauth-config'...${NC}"
oc -n ${NAMESPACE} create secret generic frontend-oauth-config \
--from-literal=client-secret="${CLIENT_SECRET_VALUE}" \
--from-literal=cookie_secret="${COOKIE_SECRET_VALUE}" \
--dry-run=client -o yaml | oc apply -f -
echo -e "${GREEN}✅ Secret configured${NC}"
# Restart frontend to pick up new secret
echo -e "${BLUE}Restarting frontend deployment...${NC}"
oc -n ${NAMESPACE} rollout restart deployment/frontend
}
# Configuration
NAMESPACE="${NAMESPACE:-ambient-code}"
# Allow overriding images via CONTAINER_REGISTRY/IMAGE_TAG or explicit DEFAULT_*_IMAGE
CONTAINER_REGISTRY="${CONTAINER_REGISTRY:-quay.io/ambient_code}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
DEFAULT_BACKEND_IMAGE="${DEFAULT_BACKEND_IMAGE:-${CONTAINER_REGISTRY}/vteam_backend:${IMAGE_TAG}}"
DEFAULT_FRONTEND_IMAGE="${DEFAULT_FRONTEND_IMAGE:-${CONTAINER_REGISTRY}/vteam_frontend:${IMAGE_TAG}}"
DEFAULT_OPERATOR_IMAGE="${DEFAULT_OPERATOR_IMAGE:-${CONTAINER_REGISTRY}/vteam_operator:${IMAGE_TAG}}"
DEFAULT_RUNNER_IMAGE="${DEFAULT_RUNNER_IMAGE:-${CONTAINER_REGISTRY}/vteam_claude_runner:${IMAGE_TAG}}"
DEFAULT_STATE_SYNC_IMAGE="${DEFAULT_STATE_SYNC_IMAGE:-${CONTAINER_REGISTRY}/vteam_state_sync:${IMAGE_TAG}}"
# Content service image (defaults to same as backend, but can be overridden)
CONTENT_SERVICE_IMAGE="${CONTENT_SERVICE_IMAGE:-${DEFAULT_BACKEND_IMAGE}}"
DEFAULT_API_SERVER_IMAGE="${DEFAULT_API_SERVER_IMAGE:-${CONTAINER_REGISTRY}/vteam_api_server:${IMAGE_TAG}}"
# Handle uninstall/clean command early
if [ "${1:-}" = "uninstall" ] || [ "${1:-}" = "clean" ]; then
echo -e "${YELLOW}Uninstalling vTeam from namespace ${NAMESPACE}...${NC}"
# Check prerequisites for uninstall
if ! command_exists oc; then
echo -e "${RED}❌ OpenShift CLI (oc) not found. Please install it first.${NC}"
exit 1
fi
if ! command_exists kustomize; then
echo -e "${RED}❌ Kustomize not found. Please install it first.${NC}"
exit 1
fi
# Check if logged in to OpenShift
if ! oc whoami >/dev/null 2>&1; then
echo -e "${RED}❌ Not logged in to OpenShift. Please run 'oc login' first.${NC}"
exit 1
fi
# Delete using kustomize (from production overlay)
cd overlays/production
if [ "$NAMESPACE" != "ambient-code" ]; then
kustomize edit set namespace "$NAMESPACE"
fi
kustomize build . | oc delete -f - --ignore-not-found=true
# Restore kustomization if we modified it
if [ "$NAMESPACE" != "ambient-code" ]; then
kustomize edit set namespace ambient-code
fi
cd ../..
echo -e "${GREEN}✅ vTeam uninstalled from namespace ${NAMESPACE}${NC}"
echo -e "${YELLOW}Note: Namespace ${NAMESPACE} still exists. Delete manually if needed:${NC}"
echo -e " ${BLUE}oc delete namespace ${NAMESPACE}${NC}"
exit 0
fi
# Handle secrets-only command (OAuth setup only)
if [ "${1:-}" = "secrets" ]; then
echo -e "${YELLOW}Running OAuth secrets setup only...${NC}"
# Check prerequisites for secrets subcommand
if ! command_exists oc; then
echo -e "${RED}❌ OpenShift CLI (oc) not found. Please install it first.${NC}"
exit 1
fi
if ! oc whoami >/dev/null 2>&1; then
echo -e "${RED}❌ Not logged in to OpenShift. Please run 'oc login' first.${NC}"
exit 1
fi
# Generate secrets values like in full deploy
OAUTH_ENV_FILE="oauth-secret.env"
CLIENT_SECRET_VALUE="${OCP_OAUTH_CLIENT_SECRET:-}"
COOKIE_SECRET_VALUE="${OCP_OAUTH_COOKIE_SECRET:-}"
if [[ -z "$CLIENT_SECRET_VALUE" ]]; then
CLIENT_SECRET_VALUE=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)
fi
COOKIE_LEN=${#COOKIE_SECRET_VALUE}
if [[ -z "$COOKIE_SECRET_VALUE" || ( $COOKIE_LEN -ne 16 && $COOKIE_LEN -ne 24 && $COOKIE_LEN -ne 32 ) ]]; then
COOKIE_SECRET_VALUE=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)
fi
cat > "$OAUTH_ENV_FILE" << EOF
client-secret=${CLIENT_SECRET_VALUE}
cookie_secret=${COOKIE_SECRET_VALUE}
EOF
# Ensure namespace exists and switch
if ! oc get namespace ${NAMESPACE} >/dev/null 2>&1; then
echo -e "${RED}❌ Namespace ${NAMESPACE} does not exist. Deploy manifests first.${NC}"
rm -f "$OAUTH_ENV_FILE"
exit 1
fi
oc project ${NAMESPACE}
# Perform OAuth setup
if ! oauth_setup; then
echo -e "${YELLOW}OAuth setup completed with warnings/errors. See messages above.${NC}"
fi
# Cleanup
rm -f "$OAUTH_ENV_FILE"
echo -e "${GREEN}✅ Secrets subcommand completed${NC}"
exit 0
fi
echo -e "${BLUE}🚀 vTeam Ambient Agentic Runner - OpenShift Deployment${NC}"
echo -e "${BLUE}====================================================${NC}"
echo -e "Namespace: ${GREEN}${NAMESPACE}${NC}"
echo -e "Backend Image: ${GREEN}${DEFAULT_BACKEND_IMAGE}${NC}"
echo -e "Frontend Image: ${GREEN}${DEFAULT_FRONTEND_IMAGE}${NC}"
echo -e "Operator Image: ${GREEN}${DEFAULT_OPERATOR_IMAGE}${NC}"
echo -e "Runner Image: ${GREEN}${DEFAULT_RUNNER_IMAGE}${NC}"
echo -e "State Sync Image: ${GREEN}${DEFAULT_STATE_SYNC_IMAGE}${NC}"
echo -e "Content Service Image: ${GREEN}${CONTENT_SERVICE_IMAGE}${NC}"
echo -e "API Server Image: ${GREEN}${DEFAULT_API_SERVER_IMAGE}${NC}"
echo ""
# Check prerequisites
echo -e "${YELLOW}Checking prerequisites...${NC}"
if ! command_exists oc; then
echo -e "${RED}❌ OpenShift CLI (oc) not found. Please install it first.${NC}"
exit 1
fi
if ! command_exists kustomize; then
echo -e "${RED}❌ Kustomize not found. Please install it first.${NC}"
exit 1
fi
echo -e "${GREEN}✅ Prerequisites check passed${NC}"
echo ""
# Check if logged in to OpenShift
echo -e "${YELLOW}Checking OpenShift authentication...${NC}"
if ! oc whoami >/dev/null 2>&1; then
echo -e "${RED}❌ Not logged in to OpenShift. Please run 'oc login' first.${NC}"
exit 1
fi
echo -e "${GREEN}✅ Authenticated as: $(oc whoami)${NC}"
echo ""
# Prepare oauth secret env file for kustomize secretGenerator
echo -e "${YELLOW}Preparing oauth secret env for kustomize...${NC}"
OAUTH_ENV_FILE="oauth-secret.env"
CLIENT_SECRET_VALUE="${OCP_OAUTH_CLIENT_SECRET:-}"
COOKIE_SECRET_VALUE="${OCP_OAUTH_COOKIE_SECRET:-}"
if [[ -z "$CLIENT_SECRET_VALUE" ]]; then
CLIENT_SECRET_VALUE=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)
fi
# cookie_secret must be exactly 16, 24, or 32 bytes. Use 32 ASCII bytes by default.
if [[ -z "$COOKIE_SECRET_VALUE" ]]; then
COOKIE_SECRET_VALUE=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)
fi
# If provided via .env, ensure it meets required length
COOKIE_LEN=${#COOKIE_SECRET_VALUE}
if [[ $COOKIE_LEN -ne 16 && $COOKIE_LEN -ne 24 && $COOKIE_LEN -ne 32 ]]; then
echo -e "${YELLOW}Provided OCP_OAUTH_COOKIE_SECRET length ($COOKIE_LEN) is invalid; regenerating 32-byte value...${NC}"
COOKIE_SECRET_VALUE=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)
fi
cat > "$OAUTH_ENV_FILE" << EOF
client-secret=${CLIENT_SECRET_VALUE}
cookie_secret=${COOKIE_SECRET_VALUE}
EOF
echo -e "${GREEN}✅ Generated ${OAUTH_ENV_FILE}${NC}"
echo ""
# Deploy using kustomize
echo -e "${YELLOW}Deploying to OpenShift using Kustomize...${NC}"
# Use production overlay
cd overlays/production
# Set namespace if different from default
if [ "$NAMESPACE" != "ambient-code" ]; then
echo -e "${BLUE}Setting custom namespace: ${NAMESPACE}${NC}"
kustomize edit set namespace "$NAMESPACE"
fi
# Set custom images if different from defaults
echo -e "${BLUE}Setting custom images...${NC}"
kustomize edit set image quay.io/ambient_code/vteam_backend:latest=${DEFAULT_BACKEND_IMAGE}
kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=${DEFAULT_FRONTEND_IMAGE}
kustomize edit set image quay.io/ambient_code/vteam_operator:latest=${DEFAULT_OPERATOR_IMAGE}
kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=${DEFAULT_RUNNER_IMAGE}
kustomize edit set image quay.io/ambient_code/vteam_state_sync:latest=${DEFAULT_STATE_SYNC_IMAGE}
kustomize edit set image quay.io/ambient_code/vteam_api_server:latest=${DEFAULT_API_SERVER_IMAGE}
# Build and apply manifests
echo -e "${BLUE}Building and applying manifests...${NC}"
kustomize build . | oc apply -f -
# Return to manifests root
cd ../..
# Check if namespace exists and is active
echo -e "${YELLOW}Checking namespace status...${NC}"
if ! oc get namespace ${NAMESPACE} >/dev/null 2>&1; then
echo -e "${RED}❌ Namespace ${NAMESPACE} does not exist${NC}"
exit 1
fi
# Check if namespace is active
NAMESPACE_PHASE=$(oc get namespace ${NAMESPACE} -o jsonpath='{.status.phase}')
if [ "$NAMESPACE_PHASE" != "Active" ]; then
echo -e "${RED}❌ Namespace ${NAMESPACE} is not active (phase: ${NAMESPACE_PHASE})${NC}"
exit 1
fi
echo -e "${GREEN}✅ Namespace ${NAMESPACE} is active${NC}"
# Switch to the target namespace
echo -e "${BLUE}Switching to namespace ${NAMESPACE}...${NC}"
oc project ${NAMESPACE}
###############################################
# OAuth setup: Route host, OAuthClient, Secret
###############################################
if ! oauth_setup; then
echo -e "${YELLOW}OAuth setup completed with warnings/errors. You may need a cluster-admin to apply the OAuthClient.${NC}"
fi
# Apply git configuration if we created a patch
if [[ -f "/tmp/git-config-patch.yaml" ]]; then
echo -e "${BLUE}Applying Git configuration...${NC}"
oc apply -f /tmp/git-config-patch.yaml
rm -f /tmp/git-config-patch.yaml
fi
# Update operator deployment with custom runner image
echo -e "${BLUE}Updating operator with custom runner image...${NC}"
oc patch deployment agentic-operator -n ${NAMESPACE} -p "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"agentic-operator\",\"env\":[{\"name\":\"AMBIENT_CODE_RUNNER_IMAGE\",\"value\":\"${DEFAULT_RUNNER_IMAGE}\"}]}]}}}}" --type=strategic
# Pin OPERATOR_IMAGE in operator-config so scheduled session triggers use the correct image
echo -e "${BLUE}Pinning OPERATOR_IMAGE in operator-config configmap...${NC}"
oc patch configmap operator-config -n ${NAMESPACE} \
--type=merge -p "{\"data\":{\"OPERATOR_IMAGE\":\"${DEFAULT_OPERATOR_IMAGE}\"}}" 2>/dev/null || \
oc create configmap operator-config -n ${NAMESPACE} --from-literal=OPERATOR_IMAGE="${DEFAULT_OPERATOR_IMAGE}" 2>/dev/null || true
# Update agent-registry configmap with custom runner and state-sync images
echo -e "${BLUE}Updating agent-registry configmap with custom images...${NC}"
REGISTRY_JSON=$(oc get configmap ambient-agent-registry -n ${NAMESPACE} -o jsonpath='{.data.agent-registry\.json}')
REGISTRY_JSON=$(echo "$REGISTRY_JSON" | sed \
-e "s|quay\.io/ambient_code/vteam_claude_runner:[^ \"]*|${DEFAULT_RUNNER_IMAGE}|g" \
-e "s|quay\.io/ambient_code/vteam_state_sync:[^ \"]*|${DEFAULT_STATE_SYNC_IMAGE}|g")
oc patch configmap ambient-agent-registry -n ${NAMESPACE} \
--type=merge -p "{\"data\":{\"agent-registry.json\":$(echo "$REGISTRY_JSON" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}}"
echo -e "${GREEN}✅ Agent registry configmap updated${NC}"
echo ""
echo -e "${GREEN}✅ Deployment completed!${NC}"
echo ""
# Wait for deployments to be ready
echo -e "${YELLOW}Waiting for deployments to be ready...${NC}"
oc rollout status deployment/backend-api --namespace=${NAMESPACE} --timeout=300s
oc rollout status deployment/agentic-operator --namespace=${NAMESPACE} --timeout=300s
oc rollout status deployment/frontend --namespace=${NAMESPACE} --timeout=300s
oc rollout status deployment/unleash --namespace=${NAMESPACE} --timeout=300s
# Get service and route information
echo -e "${BLUE}Getting service and route information...${NC}"
echo ""
echo -e "${GREEN}🎉 Deployment successful!${NC}"
echo -e "${GREEN}========================${NC}"
echo -e "Namespace: ${BLUE}${NAMESPACE}${NC}"
echo ""
# Show pod status
echo -e "${BLUE}Pod Status:${NC}"
oc get pods -n ${NAMESPACE}
echo ""
# Show services and route
echo -e "${BLUE}Services:${NC}"
oc get services -n ${NAMESPACE}
echo ""
echo -e "${BLUE}Routes:${NC}"
oc get route -n ${NAMESPACE} || true
if [[ -z "${ROUTE_NAME:-}" ]]; then
if oc get route frontend-route -n ${NAMESPACE} >/dev/null 2>&1; then
ROUTE_NAME="frontend-route"
elif oc get route frontend -n ${NAMESPACE} >/dev/null 2>&1; then
ROUTE_NAME="frontend"
fi
fi
ROUTE_HOST=$(oc get route ${ROUTE_NAME:-frontend-route} -n ${NAMESPACE} -o jsonpath='{.spec.host}' 2>/dev/null || true)
echo ""
# Cleanup generated files
echo -e "${BLUE}Cleaning up generated files...${NC}"
rm -f "$OAUTH_ENV_FILE"
echo -e "${YELLOW}Next steps:${NC}"
if [[ -n "${ROUTE_HOST}" ]]; then
echo -e "1. Access the frontend via Route:"
echo -e " ${BLUE}https://${ROUTE_HOST}${NC}"
else
echo -e "1. Access the frontend (fallback via port-forward):"
echo -e " ${BLUE}oc port-forward svc/frontend-service 3000:3000 -n ${NAMESPACE}${NC}"
echo -e " Then open: http://localhost:3000"
fi
echo -e "2. Configure secrets in the UI (Runner/API keys, project settings)."
echo -e " Open the app and follow Settings → Runner Secrets."
echo -e "3. Monitor the deployment:"
echo -e " ${BLUE}oc get pods -n ${NAMESPACE} -w${NC}"
echo -e "4. View logs:"
echo -e " ${BLUE}oc logs -f deployment/backend-api -n ${NAMESPACE}${NC}"
echo -e " ${BLUE}oc logs -f deployment/agentic-operator -n ${NAMESPACE}${NC}"
echo -e "4. Monitor RFE workflows:"
echo -e " ${BLUE}oc get agenticsessions -n ${NAMESPACE}${NC}"
echo ""
# Restore kustomization if we modified it
echo -e "${BLUE}Restoring kustomization defaults...${NC}"
cd overlays/production
if [ "$NAMESPACE" != "ambient-code" ]; then
kustomize edit set namespace ambient-code
fi
# Restore default images
kustomize edit set image quay.io/ambient_code/vteam_backend:latest=quay.io/ambient_code/vteam_backend:latest
kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=quay.io/ambient_code/vteam_frontend:latest
kustomize edit set image quay.io/ambient_code/vteam_operator:latest=quay.io/ambient_code/vteam_operator:latest
kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=quay.io/ambient_code/vteam_claude_runner:latest
kustomize edit set image quay.io/ambient_code/vteam_state_sync:latest=quay.io/ambient_code/vteam_state_sync:latest
kustomize edit set image quay.io/ambient_code/vteam_api_server:latest=quay.io/ambient_code/vteam_api_server:latest
cd ../..
echo -e "${GREEN}🎯 Ready to create RFE workflows with multi-agent collaboration!${NC}"