File size: 6,005 Bytes
1f2d50a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env bash
# KGraph-MCP Deployment Script
# Usage: ./deploy.sh <environment> <version>

set -euo pipefail

# Configuration
ENVIRONMENT="${1:-}"
VERSION="${2:-}"
DOCKER_REGISTRY="${DOCKER_REGISTRY:-ghcr.io/basalganglia}"
IMAGE_NAME="kgraph-mcp"

# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Functions
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

validate_environment() {
    case "$ENVIRONMENT" in
        dev|development)
            ENVIRONMENT="dev"
            DEPLOY_HOST="${DEV_HOST:-dev.kgraph-mcp.example.com}"
            DEPLOY_USER="${DEV_USER:-deploy}"
            COMPOSE_FILE="docker-compose.dev.yml"
            ;;
        staging)
            DEPLOY_HOST="${STAGING_HOST:-staging.kgraph-mcp.example.com}"
            DEPLOY_USER="${STAGING_USER:-deploy}"
            COMPOSE_FILE="docker-compose.staging.yml"
            ;;
        prod|production)
            ENVIRONMENT="prod"
            DEPLOY_HOST="${PROD_HOST:-api.kgraph-mcp.example.com}"
            DEPLOY_USER="${PROD_USER:-deploy}"
            COMPOSE_FILE="docker-compose.prod.yml"
            ;;
        *)
            log_error "Invalid environment: $ENVIRONMENT"
            echo "Usage: $0 <dev|staging|prod> <version>"
            exit 1
            ;;
    esac
}

check_prerequisites() {
    log_info "Checking prerequisites..."
    
    # Check if docker is installed
    if ! command -v docker &> /dev/null; then
        log_error "Docker is not installed"
        exit 1
    fi
    
    # Check if we have SSH access
    if ! ssh -o ConnectTimeout=5 "${DEPLOY_USER}@${DEPLOY_HOST}" "echo 'SSH connection successful'" &> /dev/null; then
        log_error "Cannot connect to ${DEPLOY_USER}@${DEPLOY_HOST}"
        exit 1
    fi
    
    log_info "Prerequisites check passed"
}

build_and_push_image() {
    local tag="${DOCKER_REGISTRY}/${IMAGE_NAME}:${ENVIRONMENT}-${VERSION}"
    
    log_info "Building Docker image: $tag"
    docker build \
        --build-arg ENVIRONMENT="${ENVIRONMENT}" \
        --tag "$tag" \
        --file Dockerfile \
        .
    
    log_info "Pushing image to registry..."
    docker push "$tag"
    
    # Also tag as latest for the environment
    docker tag "$tag" "${DOCKER_REGISTRY}/${IMAGE_NAME}:${ENVIRONMENT}-latest"
    docker push "${DOCKER_REGISTRY}/${IMAGE_NAME}:${ENVIRONMENT}-latest"
}

deploy_to_server() {
    local tag="${DOCKER_REGISTRY}/${IMAGE_NAME}:${ENVIRONMENT}-${VERSION}"
    
    log_info "Deploying to ${DEPLOY_HOST}..."
    
    # Copy compose file to server
    scp "deployments/${COMPOSE_FILE}" "${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/"
    
    # Deploy using docker-compose
    ssh "${DEPLOY_USER}@${DEPLOY_HOST}" << EOF
        set -e
        
        # Create deployment directory
        mkdir -p ~/kgraph-mcp
        cd ~/kgraph-mcp
        
        # Move compose file
        mv /tmp/${COMPOSE_FILE} docker-compose.yml
        
        # Set environment variables
        export KGRAPH_VERSION="${VERSION}"
        export KGRAPH_IMAGE="${tag}"
        export ENVIRONMENT="${ENVIRONMENT}"
        
        # Pull new image
        docker pull "${tag}"
        
        # Stop old containers
        docker-compose down --remove-orphans || true
        
        # Start new containers
        docker-compose up -d
        
        # Wait for health check
        sleep 10
        
        # Check if service is healthy
        if docker-compose ps | grep -q "unhealthy"; then
            echo "Service is unhealthy, rolling back..."
            docker-compose down
            exit 1
        fi
        
        # Clean up old images
        docker image prune -f
        
        echo "Deployment successful!"
EOF
}

run_post_deployment_checks() {
    log_info "Running post-deployment checks..."
    
    # Wait for service to be ready
    sleep 5
    
    # Check health endpoint
    local health_url="https://${DEPLOY_HOST}/health"
    local response=$(curl -s -o /dev/null -w "%{http_code}" "$health_url" || echo "000")
    
    if [ "$response" = "200" ]; then
        log_info "Health check passed"
    else
        log_error "Health check failed (HTTP $response)"
        return 1
    fi
    
    # Run smoke tests
    if [ -f "tests/smoke/smoke_test.sh" ]; then
        log_info "Running smoke tests..."
        DEPLOY_URL="https://${DEPLOY_HOST}" bash tests/smoke/smoke_test.sh
    fi
}

rollback() {
    log_warn "Rolling back deployment..."
    
    ssh "${DEPLOY_USER}@${DEPLOY_HOST}" << EOF
        cd ~/kgraph-mcp
        
        # Restore previous version
        docker-compose down
        export KGRAPH_IMAGE="${DOCKER_REGISTRY}/${IMAGE_NAME}:${ENVIRONMENT}-previous"
        docker-compose up -d
        
        echo "Rollback completed"
EOF
}

# Main execution
main() {
    log_info "Starting deployment process..."
    log_info "Environment: $ENVIRONMENT"
    log_info "Version: $VERSION"
    
    validate_environment
    check_prerequisites
    
    # Build and push image (skip for local dev)
    if [ "$ENVIRONMENT" != "dev" ] || [ "${BUILD_IMAGE:-true}" = "true" ]; then
        build_and_push_image
    fi
    
    # Deploy to server
    if ! deploy_to_server; then
        log_error "Deployment failed"
        rollback
        exit 1
    fi
    
    # Run post-deployment checks
    if ! run_post_deployment_checks; then
        log_error "Post-deployment checks failed"
        rollback
        exit 1
    fi
    
    log_info "Deployment completed successfully! πŸš€"
    log_info "Application URL: https://${DEPLOY_HOST}"
}

# Validate arguments
if [ -z "$ENVIRONMENT" ] || [ -z "$VERSION" ]; then
    log_error "Missing required arguments"
    echo "Usage: $0 <environment> <version>"
    echo "Example: $0 dev abc123"
    echo "         $0 staging v1.2.0"
    echo "         $0 prod v1.2.0"
    exit 1
fi

# Run main function
main