diff --git a/codeagent/codeagent_and_gitlab/codeagent_setup.sh b/codeagent/codeagent_and_gitlab/codeagent_setup.sh new file mode 100644 index 0000000..ecb17fd --- /dev/null +++ b/codeagent/codeagent_and_gitlab/codeagent_setup.sh @@ -0,0 +1,100 @@ +#!/bin/bash +set -e + +# CodeAgent Setup Script +# This script configures CodeAgent with GitLab integration + +LOG_FILE="/var/log/codeagent_setup.log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +# Variables passed from Terraform +MODEL_API_KEY='${model_api_key}' +GITLAB_BASE_URL='${gitlab_base_url}' +GITLAB_WEBHOOK_SECRET='${gitlab_webhook_secret}' +GITLAB_TOKEN='${gitlab_token}' + +echo "==========================================" +echo "Starting CodeAgent configuration..." +echo "Log file: $LOG_FILE" +echo "==========================================" + + +# Step 1: Update API_KEY in supervisor config +echo "----------------------------------------" +echo "Step 1: Updating API_KEY in supervisor config..." +echo "----------------------------------------" + +SUPERVISOR_CONF="/etc/supervisor/conf.d/codeagent.conf" +if [ ! -f "$SUPERVISOR_CONF" ]; then + echo "ERROR: $SUPERVISOR_CONF not found!" + exit 1 +fi + +echo "Found supervisor config at: $SUPERVISOR_CONF" +sed -i.bak "s/\"fake_token\"/\"$MODEL_API_KEY\"/g" "$SUPERVISOR_CONF" +echo "✓ API_KEY updated successfully" + +# Step 2: Update GitLab configuration in codeagent.yaml +echo "----------------------------------------" +echo "Step 2: Updating GitLab configuration..." +echo "----------------------------------------" + +CODEAGENT_CONF="/home/codeagent/codeagent/_package/conf/codeagent.yaml" +if [ ! -f "$CODEAGENT_CONF" ]; then + echo "ERROR: $CODEAGENT_CONF not found!" + exit 1 +fi + +echo "Found CodeAgent config at: $CODEAGENT_CONF" +cp "$CODEAGENT_CONF" "$CODEAGENT_CONF.bak" + +# Replace base_url +sed -i "s|base_url: https://gitlab.com|base_url: $GITLAB_BASE_URL|g" "$CODEAGENT_CONF" +echo "✓ Updated base_url to: $GITLAB_BASE_URL" + +# Replace webhook_secret +sed -i "s|webhook_secret: \".*\"|webhook_secret: \"$GITLAB_WEBHOOK_SECRET\"|g" "$CODEAGENT_CONF" +echo "✓ Updated webhook_secret" + +# Replace token +sed -i "s|token: \"glpat-.*\"|token: \"$GITLAB_TOKEN\"|g" "$CODEAGENT_CONF" +echo "✓ Updated GitLab token" + +echo "✓ GitLab configuration updated successfully" + +# Step 3: Restart CodeAgent service +echo "----------------------------------------" +echo "Step 3: Restarting CodeAgent service..." +echo "----------------------------------------" + +if ! command -v supervisorctl &> /dev/null; then + echo "ERROR: supervisorctl command not found!" + exit 1 +fi + +supervisorctl reread +supervisorctl update +echo "✓ CodeAgent service restarted successfully" + +# Step 4: Verify services +echo "----------------------------------------" +echo "Step 4: Verifying services..." +echo "----------------------------------------" + +echo "Supervisor status:" +supervisorctl status codeagent + +echo "" +echo "==========================================" +echo "CodeAgent configuration completed!" +echo "==========================================" +echo "" +echo "Configuration:" +echo " - GitLab URL: $GITLAB_BASE_URL" +echo " - CodeAgent service is running" +echo "" +echo "Next Steps:" +echo " 1. Check service status: supervisorctl status codeagent" +echo " 2. View service logs: supervisorctl tail -f codeagent" +echo " 3. View setup log: cat $LOG_FILE" +echo "==========================================" diff --git a/codeagent/codeagent_and_gitlab/configure_webhook.sh b/codeagent/codeagent_and_gitlab/configure_webhook.sh new file mode 100644 index 0000000..47efe90 --- /dev/null +++ b/codeagent/codeagent_and_gitlab/configure_webhook.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +# GitLab Webhook Configuration Script +# This script waits for GitLab to be ready and creates a webhook for CodeAgent + +GITLAB_URL="${gitlab_url}" +CODEAGENT_IP="${codeagent_ip}" +TOKEN="${gitlab_token}" +WEBHOOK_SECRET="${webhook_secret}" +PROJECT_ID="${project_id}" + +echo "============================================" +echo "Configuring GitLab Webhook" +echo "GitLab URL: $GITLAB_URL" +echo "CodeAgent IP: $CODEAGENT_IP" +echo "Project ID: $PROJECT_ID" +echo "============================================" + +# Create webhook with retry (GitLab will be checked as part of the API call) +echo "Creating webhook for project ID $PROJECT_ID..." + +max_retry=30 +retry=0 + +while [ $retry -lt $max_retry ]; do + echo "Attempt $((retry + 1))/$max_retry..." + + response=$(curl -s -w "\n%%{http_code}" --request POST \ + --header "PRIVATE-TOKEN: $TOKEN" \ + --data "url=http://$CODEAGENT_IP:8889/hook" \ + --data "push_events=true" \ + --data "merge_requests_events=true" \ + --data "issues_events=true" \ + --data "confidential_issues_events=true" \ + --data "note_events=true" \ + --data "confidential_note_events=true" \ + --data "enable_ssl_verification=false" \ + --data "token=$WEBHOOK_SECRET" \ + "$GITLAB_URL/api/v4/projects/$PROJECT_ID/hooks" 2>/dev/null) + + http_code=$(echo "$response" | tail -1) + body=$(echo "$response" | sed '$d') + + if [ "$http_code" = "201" ]; then + echo "✓ Webhook created successfully!" + echo "Response: $body" + exit 0 + elif echo "$body" | grep -q "already exists"; then + echo "✓ Webhook already exists" + exit 0 + else + echo "Got response code: $http_code" + retry=$((retry + 1)) + if [ $retry -lt $max_retry ]; then + echo "Retrying in 10 seconds..." + sleep 10 + fi + fi +done + +echo "" +echo "WARNING: Failed to create webhook after $max_retry attempts" +echo "You can manually create it later with:" +echo " curl --request POST --header \"PRIVATE-TOKEN: $TOKEN\" \\" +echo " --data \"url=http://$CODEAGENT_IP:8889/hook\" --data \"token=$WEBHOOK_SECRET\" \\" +echo " \"$GITLAB_URL/api/v4/projects/$PROJECT_ID/hooks\"" +exit 0 diff --git a/codeagent/codeagent_and_gitlab/gitlab_setup.sh b/codeagent/codeagent_and_gitlab/gitlab_setup.sh new file mode 100644 index 0000000..9961e5b --- /dev/null +++ b/codeagent/codeagent_and_gitlab/gitlab_setup.sh @@ -0,0 +1,74 @@ +#!/bin/bash +set -e + +# GitLab Setup Script +# This script configures GitLab with the public IP + +LOG_FILE="/var/log/gitlab_setup.log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +# Variables passed from Terraform +PUBLIC_IP='${public_ip}' + +echo "==========================================" +echo "Starting GitLab configuration..." +echo "Log file: $LOG_FILE" +echo "Public IP: $PUBLIC_IP" +echo "==========================================" + +# Wait for cloud-init to complete +echo "Waiting for cloud-init to complete..." +cloud-init status --wait || true +echo "Cloud-init completed." + +# Update GitLab external_url +echo "----------------------------------------" +echo "Step 1: Updating GitLab external_url..." +echo "----------------------------------------" + +GITLAB_CONF="/etc/gitlab/gitlab.rb" +if [ ! -f "$GITLAB_CONF" ]; then + echo "ERROR: $GITLAB_CONF not found!" + exit 1 +fi + +echo "Found GitLab config at: $GITLAB_CONF" +cp "$GITLAB_CONF" "$GITLAB_CONF.bak" + +# Replace external_url +sed -i "s|external_url '.*'|external_url 'http://$PUBLIC_IP'|g" "$GITLAB_CONF" +echo "✓ Updated external_url to http://$PUBLIC_IP" + +# Reconfigure GitLab +echo "----------------------------------------" +echo "Step 2: Reconfiguring GitLab..." +echo "----------------------------------------" + +if ! command -v gitlab-ctl &> /dev/null; then + echo "ERROR: gitlab-ctl command not found!" + exit 1 +fi + +gitlab-ctl reconfigure +echo "✓ GitLab reconfigured successfully" + +# Verify GitLab status +echo "----------------------------------------" +echo "Step 3: Verifying GitLab status..." +echo "----------------------------------------" + +gitlab-ctl status | head -n 5 + +echo "" +echo "==========================================" +echo "GitLab configuration completed!" +echo "==========================================" +echo "" +echo "Access Information:" +echo " - GitLab URL: http://$PUBLIC_IP" +echo "" +echo "Next Steps:" +echo " 1. Wait 5-10 minutes for GitLab to fully start" +echo " 2. Access GitLab at http://$PUBLIC_IP" +echo " 3. Get root password: cat /etc/gitlab/initial_root_password" +echo "==========================================" diff --git a/codeagent/codeagent_and_gitlab/main.tf b/codeagent/codeagent_and_gitlab/main.tf new file mode 100644 index 0000000..470183a --- /dev/null +++ b/codeagent/codeagent_and_gitlab/main.tf @@ -0,0 +1,122 @@ +# Generate random passwords +resource "random_password" "gitlab_instance_password" { + length = 16 + special = true + lower = true + upper = true + numeric = true +} + +resource "random_password" "codeagent_instance_password" { + length = 16 + special = true + lower = true + upper = true + numeric = true +} + +# Step 1: Create GitLab instance first +resource "qiniu_compute_instance" "gitlab_instance" { + instance_type = var.gitlab_instance_type + name = format("gitlab-%s", local.instance_suffix) + description = format("GitLab instance %s", local.instance_suffix) + image_id = var.gitlab_image_id + system_disk_size = var.gitlab_system_disk_size + internet_max_bandwidth = var.gitlab_internet_max_bandwidth + password = random_password.gitlab_instance_password.result + + timeouts { + create = "30m" + update = "20m" + delete = "10m" + } +} + +# Use null_resource to configure GitLab with actual public IP via SSH +resource "null_resource" "configure_gitlab" { + depends_on = [qiniu_compute_instance.gitlab_instance] + + connection { + type = "ssh" + user = "root" + password = random_password.gitlab_instance_password.result + host = qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4 + timeout = "10m" + agent = false + host_key = null + } + + # Upload the setup script + provisioner "file" { + content = templatefile("${path.module}/gitlab_setup.sh", { + public_ip = qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4 + }) + destination = "/tmp/gitlab_setup.sh" + } + + # Execute the script + provisioner "remote-exec" { + inline = [ + "chmod +x /tmp/gitlab_setup.sh", + "/tmp/gitlab_setup.sh" + ] + } +} + +# Step 2: Create CodeAgent instance after GitLab is configured +resource "qiniu_compute_instance" "codeagent_instance" { + depends_on = [null_resource.configure_gitlab] + + instance_type = var.codeagent_instance_type + name = format("codeagent-%s", local.instance_suffix) + description = format("CodeAgent instance %s", local.instance_suffix) + image_id = var.codeagent_image_id + system_disk_size = var.codeagent_system_disk_size + internet_max_bandwidth = var.codeagent_internet_max_bandwidth + password = random_password.codeagent_instance_password.result + + # Configure CodeAgent with GitLab URL + user_data = base64encode(templatefile("${path.module}/codeagent_setup.sh", { + model_api_key = var.model_api_key + gitlab_base_url = format("http://%s", qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4) + gitlab_webhook_secret = local.gitlab_webhook_secret + gitlab_token = local.gitlab_token + })) + + timeouts { + create = "30m" + update = "20m" + delete = "10m" + } +} + +# Step 3: Configure GitLab webhook after CodeAgent is ready +resource "null_resource" "configure_gitlab_webhook" { + depends_on = [qiniu_compute_instance.codeagent_instance] + + provisioner "local-exec" { + command = templatefile("${path.module}/configure_webhook.sh", { + gitlab_url = format("http://%s", qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4) + codeagent_ip = qiniu_compute_instance.codeagent_instance.public_ip_addresses[0].ipv4 + gitlab_token = local.gitlab_token + webhook_secret = local.gitlab_webhook_secret + project_id = "1" + }) + interpreter = ["/bin/bash", "-c"] + } +} + +resource "random_string" "resource_suffix" { + length = 6 + upper = false + lower = true + special = false +} + +locals { + instance_suffix = random_string.resource_suffix.result + + # Hardcoded GitLab configuration for CodeAgent + gitlab_webhook_secret = "7Xk9pL2qNvR" #gitlab 内置测试项目配置的webhook_secret密钥,仅做测试用,请勿用于真实环境 + gitlab_token = "glpat-vkEFt2B0j-bFbEJaUmfWcm86MQp1OjIH.01.0w1yp1q9m" #gitlab 内置配置的codeagent的token ,仅做测试用,请勿用于真实环境 +} \ No newline at end of file diff --git a/codeagent/codeagent_and_gitlab/outputs.tf b/codeagent/codeagent_and_gitlab/outputs.tf new file mode 100644 index 0000000..bb1500e --- /dev/null +++ b/codeagent/codeagent_and_gitlab/outputs.tf @@ -0,0 +1,64 @@ +# GitLab instance outputs +output "gitlab_instance_id" { + value = qiniu_compute_instance.gitlab_instance.id + description = "GitLab instance ID" +} + +output "gitlab_public_ip" { + value = qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4 + description = "GitLab instance public IP address" +} + +output "gitlab_private_ip" { + value = qiniu_compute_instance.gitlab_instance.private_ip_addresses[0].ipv4 + description = "GitLab instance private IP address" +} + +output "gitlab_instance_password" { + value = random_password.gitlab_instance_password.result + description = "Root password for SSH access to GitLab instance" + sensitive = true +} + +output "gitlab_url" { + value = format("http://%s", qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4) + description = "GitLab access URL" +} + +# CodeAgent instance outputs +output "codeagent_instance_id" { + value = qiniu_compute_instance.codeagent_instance.id + description = "CodeAgent instance ID" +} + +output "codeagent_public_ip" { + value = qiniu_compute_instance.codeagent_instance.public_ip_addresses[0].ipv4 + description = "CodeAgent instance public IP address" +} + +output "codeagent_private_ip" { + value = qiniu_compute_instance.codeagent_instance.private_ip_addresses[0].ipv4 + description = "CodeAgent instance private IP address" +} + +output "codeagent_instance_password" { + value = random_password.codeagent_instance_password.result + description = "Root password for SSH access to CodeAgent instance" + sensitive = true +} + +# Combined information +output "deployment_summary" { + value = { + gitlab = { + instance_id = qiniu_compute_instance.gitlab_instance.id + public_ip = qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4 + url = format("http://%s", qiniu_compute_instance.gitlab_instance.public_ip_addresses[0].ipv4) + } + codeagent = { + instance_id = qiniu_compute_instance.codeagent_instance.id + public_ip = qiniu_compute_instance.codeagent_instance.public_ip_addresses[0].ipv4 + } + } + description = "Complete deployment summary" +} diff --git a/codeagent/codeagent_and_gitlab/terraform.tfvars.example b/codeagent/codeagent_and_gitlab/terraform.tfvars.example new file mode 100644 index 0000000..ee09be0 --- /dev/null +++ b/codeagent/codeagent_and_gitlab/terraform.tfvars.example @@ -0,0 +1,24 @@ +# CodeAgent & GitLab Deployment Configuration Example +# Copy this file to terraform.tfvars and update with your values + +# ===== Required Parameters ===== + +# AI Model API Key (Required) +model_api_key = "your-ai-model-api-key-here" + +# ===== Optional: Instance Configuration ===== + +# GitLab Instance Configuration +# gitlab_instance_type = "ecs.c1.c16m32" # 16 cores, 32GB RAM +# gitlab_system_disk_size = 100 # 100GB system disk +# gitlab_internet_max_bandwidth = 100 # 100Mbps bandwidth +# gitlab_image_id = "image-693bdc845d7ae428f33348af" + +# CodeAgent Instance Configuration +# codeagent_instance_type = "ecs.c1.c16m32" # 16 cores, 32GB RAM +# codeagent_system_disk_size = 100 # 100GB system disk +# codeagent_internet_max_bandwidth = 100 # 100Mbps bandwidth +# codeagent_image_id = "image-693b7d014fc9d0719531c21f" + +# ===== Note ===== +# GitLab configuration (webhook_secret and token) is hardcoded in the module diff --git a/codeagent/codeagent_and_gitlab/variables.tf b/codeagent/codeagent_and_gitlab/variables.tf new file mode 100644 index 0000000..31b1fba --- /dev/null +++ b/codeagent/codeagent_and_gitlab/variables.tf @@ -0,0 +1,114 @@ +# GitLab instance configuration +variable "gitlab_instance_type" { + type = string + description = "GitLab instance type (ECS specification)" + default = "ecs.c1.c16m32" + + validation { + condition = var.gitlab_instance_type != "" && contains([ + "ecs.t1.c1m2", "ecs.t1.c2m4", "ecs.t1.c4m8", "ecs.t1.c12m24", + "ecs.t1.c32m64", "ecs.t1.c24m48", "ecs.t1.c8m16", "ecs.t1.c16m32", + "ecs.g1.c16m120", "ecs.g1.c32m240", "ecs.c1.c1m2", "ecs.c1.c2m4", + "ecs.c1.c4m8", "ecs.c1.c8m16", "ecs.c1.c16m32", "ecs.c1.c24m48", + "ecs.c1.c12m24", "ecs.c1.c32m64" + ], var.gitlab_instance_type) + error_message = "gitlab_instance_type must be one of the allowed ECS instance types" + } +} + +variable "gitlab_system_disk_size" { + type = number + description = "GitLab system disk size in GiB" + default = 100 + + validation { + condition = var.gitlab_system_disk_size >= 100 + error_message = "gitlab_system_disk_size must be greater than or equal to 100 GiB" + } +} + +variable "gitlab_internet_max_bandwidth" { + type = number + description = "GitLab maximum internet bandwidth in Mbps (0-200)" + default = 100 + + validation { + condition = var.gitlab_internet_max_bandwidth >= 0 && var.gitlab_internet_max_bandwidth <= 200 + error_message = "gitlab_internet_max_bandwidth must be between 0 and 200 Mbps" + } +} + +variable "gitlab_image_id" { + type = string + description = "GitLab pre-configured image ID" + default = "image-693bdc845d7ae428f33348af" + + validation { + condition = can(regex("^image-[a-z0-9]+$", var.gitlab_image_id)) + error_message = "gitlab_image_id must be in the format 'image-xxxxx'" + } +} + +# CodeAgent instance configuration +variable "codeagent_instance_type" { + type = string + description = "CodeAgent instance type (ECS specification)" + default = "ecs.c1.c16m32" + + validation { + condition = var.codeagent_instance_type != "" && contains([ + "ecs.t1.c1m2", "ecs.t1.c2m4", "ecs.t1.c4m8", "ecs.t1.c12m24", + "ecs.t1.c32m64", "ecs.t1.c24m48", "ecs.t1.c8m16", "ecs.t1.c16m32", + "ecs.g1.c16m120", "ecs.g1.c32m240", "ecs.c1.c1m2", "ecs.c1.c2m4", + "ecs.c1.c4m8", "ecs.c1.c8m16", "ecs.c1.c16m32", "ecs.c1.c24m48", + "ecs.c1.c12m24", "ecs.c1.c32m64" + ], var.codeagent_instance_type) + error_message = "codeagent_instance_type must be one of the allowed ECS instance types" + } +} + +variable "codeagent_system_disk_size" { + type = number + description = "CodeAgent system disk size in GiB" + default = 100 + + validation { + condition = var.codeagent_system_disk_size >= 20 && var.codeagent_system_disk_size <= 500 + error_message = "codeagent_system_disk_size must be between 20 and 500 GiB" + } +} + +variable "codeagent_internet_max_bandwidth" { + type = number + description = "CodeAgent maximum internet bandwidth in Mbps (0-200)" + default = 100 + + validation { + condition = var.codeagent_internet_max_bandwidth >= 0 && var.codeagent_internet_max_bandwidth <= 200 + error_message = "codeagent_internet_max_bandwidth must be between 0 and 200 Mbps" + } +} + +variable "codeagent_image_id" { + type = string + description = "CodeAgent pre-configured image ID" + default = "image-693b7d014fc9d0719531c21f" + + validation { + condition = can(regex("^image-[a-z0-9]+$", var.codeagent_image_id)) + error_message = "codeagent_image_id must be in the format 'image-xxxxx'" + } +} + +# CodeAgent configuration +variable "model_api_key" { + type = string + description = "AI Model API Key for CodeAgent" + sensitive = true + + validation { + condition = length(var.model_api_key) >= 10 + error_message = "model_api_key must be at least 10 characters long" + } +} + diff --git a/codeagent/codeagent_and_gitlab/versions.tf b/codeagent/codeagent_and_gitlab/versions.tf new file mode 100644 index 0000000..1e5e3ae --- /dev/null +++ b/codeagent/codeagent_and_gitlab/versions.tf @@ -0,0 +1,18 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + qiniu = { + source = "hashicorp/qiniu" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } +} + +provider "qiniu" {} + +provider "random" {}