Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
go mod verify

- name: Run tests with coverage
shell: bash
run: |
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
go tool cover -func=coverage.out
Expand All @@ -73,6 +74,7 @@ jobs:

- name: Generate coverage badge
if: matrix.go-version == '1.22'
shell: bash
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "COVERAGE=$COVERAGE" >> $GITHUB_ENV
Expand Down
33 changes: 33 additions & 0 deletions cmd/docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: '3.8'

# Development mode - both UI and Core run on host
# Only MongoDB runs in Docker

services:
mongodb:
image: mongo:8.0
container_name: kubeorchestra-mongodb-dev
restart: unless-stopped
environment:
MONGO_INITDB_DATABASE: kubeorchestra
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

# UI runs on host: cd ui && npm install && npm run dev (port 3001)
# Core runs on host: cd core && air (port 3000)
# Both connect to MongoDB at localhost:27017

volumes:
mongodb_data:
name: kubeorchestra_mongodb_data_dev
mongodb_config:
name: kubeorchestra_mongodb_config_dev
76 changes: 76 additions & 0 deletions cmd/docker/docker-compose.hybrid-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
version: '3.8'

# Hybrid Core mode - Core repo cloned, UI from Docker image
# All services run in Docker for simplicity

networks:
kubeorchestra-net:
driver: bridge
name: kubeorchestra-network-hybrid

services:
mongodb:
image: mongo:8.0
container_name: kubeorchestra-mongodb-hybrid
restart: unless-stopped
networks:
- kubeorchestra-net
environment:
MONGO_INITDB_DATABASE: kubeorchestra
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

# Core runs in container with mounted code for hot reload
# This way backend devs don't need Go installed locally
core:
image: cosmtrek/air:latest
container_name: kubeorchestra-core-hybrid
restart: unless-stopped
networks:
- kubeorchestra-net
volumes:
- ../core:/app
- go-modules:/go/pkg/mod # Cache Go modules
working_dir: /app
ports:
- "3000:3000"
environment:
MONGO_URI: mongodb://mongodb:27017/kubeorchestra
MONGO_DB_NAME: kubeorchestra
depends_on:
mongodb:
condition: service_healthy
command: air

ui:
image: ghcr.io/kubeorch/ui:latest
container_name: kubeorchestra-ui-hybrid
restart: unless-stopped
networks:
- kubeorchestra-net
ports:
- "3001:3001"
environment:
# Both use internal Docker network names
NEXT_PUBLIC_API_URL: http://localhost:3000
API_URL_INTERNAL: http://core:3000
PORT: 3001
depends_on:
- core

volumes:
mongodb_data:
name: kubeorchestra_mongodb_data_hybrid
mongodb_config:
name: kubeorchestra_mongodb_config_hybrid
go-modules:
name: kubeorchestra_go_modules
54 changes: 54 additions & 0 deletions cmd/docker/docker-compose.hybrid-ui.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
version: '3.8'

# Hybrid UI mode - UI runs on host, Core from Docker image
# MongoDB and Core run in Docker

networks:
kubeorchestra-net:
driver: bridge
name: kubeorchestra-network-hybrid

services:
mongodb:
image: mongo:8.0
container_name: kubeorchestra-mongodb-hybrid
restart: unless-stopped
networks:
- kubeorchestra-net
environment:
MONGO_INITDB_DATABASE: kubeorchestra
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

core:
image: ghcr.io/kubeorch/core:latest
container_name: kubeorchestra-core-hybrid
restart: unless-stopped
networks:
- kubeorchestra-net
ports:
- "3000:3000"
environment:
MONGO_URI: mongodb://mongodb:27017/kubeorchestra
MONGO_DB_NAME: kubeorchestra
depends_on:
mongodb:
condition: service_healthy

# UI runs on host: cd ui && npm install && npm run dev (port 3001)
# UI connects to Core at localhost:3000

volumes:
mongodb_data:
name: kubeorchestra_mongodb_data_hybrid
mongodb_config:
name: kubeorchestra_mongodb_config_hybrid
68 changes: 68 additions & 0 deletions cmd/docker/docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
version: '3.8'

networks:
kubeorchestra-net:
driver: bridge
name: kubeorchestra-network

services:
mongodb:
image: mongo:8.0
container_name: kubeorchestra-mongodb
restart: unless-stopped
networks:
- kubeorchestra-net
environment:
MONGO_INITDB_DATABASE: kubeorchestra
ports:
- "27017:27017"
expose:
- "27017"
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

core:
image: ghcr.io/kubeorch/core:latest
container_name: kubeorchestra-core
restart: unless-stopped
networks:
- kubeorchestra-net
ports:
- "3000:3000"
expose:
- "3000"
environment:
MONGO_URI: mongodb://mongodb:27017/kubeorchestra
MONGO_DB_NAME: kubeorchestra
depends_on:
mongodb:
condition: service_healthy

ui:
image: ghcr.io/kubeorch/ui:latest
container_name: kubeorchestra-ui
restart: unless-stopped
networks:
- kubeorchestra-net
ports:
- "3001:3001"
expose:
- "3001"
environment:
NEXT_PUBLIC_API_URL: http://localhost:3000
API_URL_INTERNAL: http://core:3000
depends_on:
- core

volumes:
mongodb_data:
name: kubeorchestra_mongodb_data
mongodb_config:
name: kubeorchestra_mongodb_config
12 changes: 12 additions & 0 deletions cmd/embedded.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cmd

import "embed"

//go:embed docker/*
var embeddedComposeFiles embed.FS

//go:embed templates/config.yaml
var configTemplate string

//go:embed templates/env.local
var envLocalTemplate string
51 changes: 29 additions & 22 deletions cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ var execCmd = &cobra.Command{
Use: "exec <service> [command]",
Short: "Execute a command in a running service container",
Long: `Execute a command in a running service container.
Services: postgres, core, ui

Services: mongodb, core, ui

Examples:
# Open PostgreSQL shell
orchcli exec postgres psql -U kubeorchestra -d kubeorchestra
# Open MongoDB shell
orchcli exec mongodb mongosh kubeorchestra

# Run migrations in Core
orchcli exec core go run . migrate

# Open bash shell in UI container
orchcli exec ui bash

# Check Node version in UI container
orchcli exec ui node --version`,
Args: cobra.MinimumNArgs(1),
Expand All @@ -43,35 +43,42 @@ func runExec(cmd *cobra.Command, args []string) error {

service := args[0]
validServices := map[string]string{
"postgres": "kubeorchestra-postgres",
"core": "kubeorchestra-core",
"ui": "kubeorchestra-ui",
"mongodb": "kubeorchestra-mongodb",
"core": "kubeorchestra-core",
"ui": "kubeorchestra-ui",
}

containerName, valid := validServices[service]
if !valid {
return fmt.Errorf("invalid service: %s. Valid services: postgres, core, ui", service)
return fmt.Errorf("invalid service: %s. Valid services: mongodb, core, ui", service)
Comment thread
mohit-nagaraj marked this conversation as resolved.
}

// Check if container is running
// Find the actual running container — name may have a -dev or -hybrid suffix
// depending on which orchcli init mode was used.
// #nosec G204 -- containerName is validated from a fixed allowlist above
checkCmd := exec.Command("docker", "ps", "--filter", fmt.Sprintf("name=%s", containerName), "--format", "{{.Names}}")
output, err := checkCmd.Output()
if err != nil || strings.TrimSpace(string(output)) == "" {
// Take the first line only — docker ps may return multiple matches.
trimmed := strings.TrimSpace(string(output))
if idx := strings.IndexByte(trimmed, '\n'); idx != -1 {
trimmed = trimmed[:idx]
}
actualName := trimmed
if err != nil || actualName == "" {
return fmt.Errorf("service %s is not running. Start it with: orchcli start", service)
}

// Build docker exec command
dockerArgs := []string{"exec", "-it", containerName}
// Build docker exec command using the actual running container name
dockerArgs := []string{"exec", "-it", actualName}

if len(args) > 1 {
// Specific command provided
dockerArgs = append(dockerArgs, args[1:]...)
} else {
// Default shells for each service
switch service {
case "postgres":
dockerArgs = append(dockerArgs, "psql", "-U", "kubeorchestra", "-d", "kubeorchestra")
case "mongodb":
dockerArgs = append(dockerArgs, "mongosh", "kubeorchestra")
case "core":
dockerArgs = append(dockerArgs, "sh")
case "ui":
Expand All @@ -80,10 +87,10 @@ func runExec(cmd *cobra.Command, args []string) error {
}

// #nosec G204 -- dockerArgs are constructed from validated inputs
execCmd := exec.Command("docker", dockerArgs...)
execCmd.Stdout = os.Stdout
execCmd.Stderr = os.Stderr
execCmd.Stdin = os.Stdin
execCommand := exec.Command("docker", dockerArgs...)
execCommand.Stdout = os.Stdout
execCommand.Stderr = os.Stderr
execCommand.Stdin = os.Stdin

return execCmd.Run()
return execCommand.Run()
}
Loading
Loading