generated from kyegomez/Python-Package-Template
-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Your Name
committed
Oct 9, 2024
1 parent
5eb6bb7
commit 854e7ba
Showing
5 changed files
with
147 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import os | ||
from typing import Any, Dict | ||
|
||
import click | ||
import pulumi | ||
import yaml | ||
from loguru import logger | ||
from pulumi_gcp import cloudrun, storage | ||
|
||
# Configure logging | ||
logger.add("deploy_agent.log", rotation="10 MB", retention="10 days", level="INFO") | ||
|
||
|
||
# Function to load and validate agent.yaml | ||
def load_yaml(file_path: str) -> Dict[str, Any]: | ||
try: | ||
logger.info(f"Loading YAML configuration from {file_path}") | ||
with open(file_path, "r") as file: | ||
config = yaml.safe_load(file) | ||
logger.info("YAML configuration loaded successfully") | ||
return config | ||
except FileNotFoundError as e: | ||
logger.error(f"YAML file not found: {e}") | ||
raise | ||
except yaml.YAMLError as e: | ||
logger.error(f"Error parsing YAML: {e}") | ||
raise | ||
|
||
|
||
# Function to check file existence | ||
def check_file_exists(file_path: str) -> bool: | ||
if os.path.exists(file_path): | ||
return True | ||
else: | ||
logger.error(f"File not found: {file_path}") | ||
return False | ||
|
||
|
||
# Function to build and push Docker image | ||
def build_and_push_docker_image( | ||
agent_name: str, project_id: str, dockerfile_path: str | ||
) -> str: | ||
image_name = f"gcr.io/{project_id}/{agent_name}" | ||
try: | ||
logger.info(f"Building Docker image: {image_name}") | ||
build_command = f"docker build -t {image_name} -f {dockerfile_path} ." | ||
if os.system(build_command) != 0: | ||
raise RuntimeError(f"Failed to build Docker image: {image_name}") | ||
|
||
logger.info(f"Pushing Docker image: {image_name}") | ||
push_command = f"docker push {image_name}" | ||
if os.system(push_command) != 0: | ||
raise RuntimeError(f"Failed to push Docker image: {image_name}") | ||
|
||
logger.info(f"Docker image built and pushed successfully: {image_name}") | ||
return image_name | ||
except Exception as e: | ||
logger.error(f"Error building or pushing Docker image: {e}") | ||
raise | ||
|
||
|
||
@click.command() | ||
@click.option("--project-id", envvar="GCP_PROJECT_ID", help="Google Cloud Project ID") | ||
@click.option( | ||
"--region", | ||
default="us-central1", | ||
envvar="GCP_REGION", | ||
help="Region where the agent will be deployed", | ||
) | ||
@click.option( | ||
"--dockerfile-path", default="./Dockerfile", help="Path to the Dockerfile" | ||
) | ||
@click.option("--yaml-path", default="./agent.yaml", help="Path to the agent YAML file") | ||
def deploy_agent( | ||
project_id: str, region: str, dockerfile_path: str, yaml_path: str | ||
) -> None: | ||
try: | ||
# Step 1: Validate existence of Dockerfile and agent.yaml | ||
if not check_file_exists(dockerfile_path): | ||
logger.error("Dockerfile is missing, exiting.") | ||
return | ||
|
||
if not check_file_exists(yaml_path): | ||
logger.error("YAML file is missing, exiting.") | ||
return | ||
|
||
# Step 2: Load the YAML configuration | ||
config = load_yaml(yaml_path) | ||
agent_name = config.get("agent_name", "default-agent") | ||
description = config.get("description", "No description provided") | ||
resources = config.get("cloud_run", {}).get("resources", {}) | ||
environment_variables = config.get("cloud_run", {}).get( | ||
"environment_variables", {} | ||
) | ||
|
||
# Step 3: Initialize Pulumi programmatically | ||
logger.info(f"Setting up Pulumi with project {project_id} and region {region}") | ||
pulumi.runtime.set_config("gcp:project", project_id) | ||
pulumi.runtime.set_config("gcp:region", region) | ||
|
||
# Step 4: Build and push Docker image | ||
docker_image = build_and_push_docker_image( | ||
agent_name, project_id, dockerfile_path | ||
) | ||
|
||
# Step 5: Deploy to Google Cloud Run | ||
logger.info(f"Deploying {agent_name} to Google Cloud Run...") | ||
cloud_run_service = cloudrun.Service( | ||
agent_name, | ||
location=region, | ||
template={ | ||
"spec": { | ||
"containers": [ | ||
{ | ||
"image": docker_image, | ||
"resources": { | ||
"limits": { | ||
"cpu": resources.get("cpu", "1"), | ||
"memory": resources.get("memory", "512Mi"), | ||
} | ||
}, | ||
"env": [ | ||
{"name": k, "value": v} | ||
for k, v in environment_variables.items() | ||
], | ||
} | ||
] | ||
} | ||
}, | ||
autogenerate_name=True, | ||
) | ||
|
||
logger.info( | ||
f"Agent {agent_name} deployed successfully at: {cloud_run_service.status.url}" | ||
) | ||
print(f"Agent deployed at: {cloud_run_service.status.url}") | ||
|
||
except Exception as e: | ||
logger.error(f"An error occurred during deployment: {e}") | ||
raise | ||
|
||
|
||
if __name__ == "__main__": | ||
deploy_agent() |