cp
This commit is contained in:
parent
ae219c8111
commit
f1c41a074d
4
.gitignore
vendored
4
.gitignore
vendored
@ -49,3 +49,7 @@ htmlcov/
|
|||||||
.coverage.*
|
.coverage.*
|
||||||
coverage.xml
|
coverage.xml
|
||||||
*.cover
|
*.cover
|
||||||
|
|
||||||
|
# Terraform
|
||||||
|
*.tfvars
|
||||||
|
.terraform
|
||||||
|
|||||||
64
deployment/README.md
Normal file
64
deployment/README.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Deployment Options for Sereact
|
||||||
|
|
||||||
|
This directory contains multiple options for deploying the Sereact application:
|
||||||
|
|
||||||
|
## Terraform Infrastructure (`/terraform`)
|
||||||
|
|
||||||
|
The Terraform configuration automates the provisioning of all required Google Cloud resources:
|
||||||
|
|
||||||
|
- Google Cloud Run service
|
||||||
|
- Google Container Registry (GCR)
|
||||||
|
- Cloud Firestore
|
||||||
|
- Cloud Storage buckets
|
||||||
|
|
||||||
|
See [terraform/README.md](terraform/README.md) for detailed instructions.
|
||||||
|
|
||||||
|
## Cloud Run Deployment (`/cloud-run`)
|
||||||
|
|
||||||
|
The `service.yaml` file defines the Cloud Run service configuration which can be deployed using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gcloud run services replace deployment/cloud-run/service.yaml --region=us-central1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Script (`deploy.sh`)
|
||||||
|
|
||||||
|
For convenience, a deployment script is provided to handle the entire deployment workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Provision infrastructure with Terraform
|
||||||
|
./deployment/deploy.sh --provision
|
||||||
|
|
||||||
|
# Build and push Docker image
|
||||||
|
./deployment/deploy.sh --build
|
||||||
|
|
||||||
|
# Deploy to Cloud Run
|
||||||
|
./deployment/deploy.sh --deploy
|
||||||
|
|
||||||
|
# Do everything (provision, build, deploy)
|
||||||
|
./deployment/deploy.sh --all
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD Pipelines
|
||||||
|
|
||||||
|
For CI/CD integration, consider using:
|
||||||
|
|
||||||
|
1. **GitHub Actions**: Sample workflow included in terraform/README.md
|
||||||
|
2. **Cloud Build**: Configure a `cloudbuild.yaml` in your repository
|
||||||
|
3. **Jenkins**: Use the `deploy.sh` script in your pipeline
|
||||||
|
|
||||||
|
## Managing Secrets
|
||||||
|
|
||||||
|
Sensitive data should be managed using Google Secret Manager:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a secret
|
||||||
|
gcloud secrets create sereact-db-uri --replication-policy="automatic"
|
||||||
|
|
||||||
|
# Add a secret version
|
||||||
|
echo -n "your-mongodb-uri" | gcloud secrets versions add sereact-db-uri --data-file=-
|
||||||
|
|
||||||
|
# Update Cloud Run service to use the secret
|
||||||
|
gcloud run services update sereact \
|
||||||
|
--update-secrets=DATABASE_URI=sereact-db-uri:latest
|
||||||
|
```
|
||||||
54
deployment/cloudbuild.yaml
Normal file
54
deployment/cloudbuild.yaml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
steps:
|
||||||
|
# Build the container image
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['build', '-t', 'gcr.io/$PROJECT_ID/sereact:$COMMIT_SHA', '.']
|
||||||
|
|
||||||
|
# Push the container image to Container Registry
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['push', 'gcr.io/$PROJECT_ID/sereact:$COMMIT_SHA']
|
||||||
|
|
||||||
|
# Tag the image as latest
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['tag', 'gcr.io/$PROJECT_ID/sereact:$COMMIT_SHA', 'gcr.io/$PROJECT_ID/sereact:latest']
|
||||||
|
|
||||||
|
# Push the latest tag
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['push', 'gcr.io/$PROJECT_ID/sereact:latest']
|
||||||
|
|
||||||
|
# Deploy to Cloud Run
|
||||||
|
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
||||||
|
entrypoint: gcloud
|
||||||
|
args:
|
||||||
|
- 'run'
|
||||||
|
- 'deploy'
|
||||||
|
- 'sereact'
|
||||||
|
- '--image=gcr.io/$PROJECT_ID/sereact:$COMMIT_SHA'
|
||||||
|
- '--region=us-central1'
|
||||||
|
- '--platform=managed'
|
||||||
|
- '--allow-unauthenticated'
|
||||||
|
- '--set-env-vars=GCS_BUCKET_NAME=${_GCS_BUCKET_NAME},DATABASE_NAME=${_DATABASE_NAME},VECTOR_DB_ENVIRONMENT=${_VECTOR_DB_ENVIRONMENT},VECTOR_DB_INDEX_NAME=${_VECTOR_DB_INDEX_NAME},LOG_LEVEL=INFO'
|
||||||
|
- '--set-secrets=DATABASE_URI=sereact-db-uri:latest,API_KEY_SECRET=sereact-api-key-secret:latest,VECTOR_DB_API_KEY=sereact-vector-db-key:latest'
|
||||||
|
|
||||||
|
# Optional: Run tests after deployment
|
||||||
|
# - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
||||||
|
# entrypoint: /bin/bash
|
||||||
|
# args:
|
||||||
|
# - '-c'
|
||||||
|
# - |
|
||||||
|
# SERVICE_URL=$(gcloud run services describe sereact --region=us-central1 --format='value(status.url)')
|
||||||
|
# curl -s -o /dev/null -w "%{http_code}" $${SERVICE_URL}/health | grep 200
|
||||||
|
|
||||||
|
# Store images in Container Registry
|
||||||
|
images:
|
||||||
|
- 'gcr.io/$PROJECT_ID/sereact:$COMMIT_SHA'
|
||||||
|
- 'gcr.io/$PROJECT_ID/sereact:latest'
|
||||||
|
|
||||||
|
# Substitution variables to be set in the Cloud Build trigger
|
||||||
|
substitutions:
|
||||||
|
_GCS_BUCKET_NAME: 'your-app-storage-bucket'
|
||||||
|
_DATABASE_NAME: 'imagedb'
|
||||||
|
_VECTOR_DB_ENVIRONMENT: 'your-pinecone-env'
|
||||||
|
_VECTOR_DB_INDEX_NAME: 'image-embeddings'
|
||||||
|
|
||||||
|
# Increase timeout to 30 minutes
|
||||||
|
timeout: '1800s'
|
||||||
142
deployment/deploy.sh
Normal file
142
deployment/deploy.sh
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PROJECT_ID=$(gcloud config get-value project)
|
||||||
|
IMAGE_NAME="sereact"
|
||||||
|
REGION="us-central1"
|
||||||
|
SERVICE_NAME="sereact"
|
||||||
|
|
||||||
|
# Help function
|
||||||
|
function show_help {
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo "Options:"
|
||||||
|
echo " --provision Run Terraform to provision cloud resources"
|
||||||
|
echo " --build Build and push Docker image"
|
||||||
|
echo " --deploy Deploy to Cloud Run"
|
||||||
|
echo " --all Do all of the above"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if any arguments were provided
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
show_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process arguments
|
||||||
|
PROVISION=false
|
||||||
|
BUILD=false
|
||||||
|
DEPLOY=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--provision)
|
||||||
|
PROVISION=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--build)
|
||||||
|
BUILD=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--deploy)
|
||||||
|
DEPLOY=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--all)
|
||||||
|
PROVISION=true
|
||||||
|
BUILD=true
|
||||||
|
DEPLOY=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ensure gcloud is configured
|
||||||
|
if [ -z "$PROJECT_ID" ]; then
|
||||||
|
echo "ERROR: No Google Cloud project is set. Run 'gcloud config set project YOUR_PROJECT_ID'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Using Google Cloud project: $PROJECT_ID"
|
||||||
|
echo "==================================="
|
||||||
|
|
||||||
|
# Provision resources with Terraform
|
||||||
|
if [ "$PROVISION" = true ]; then
|
||||||
|
echo "Provisioning cloud resources with Terraform..."
|
||||||
|
cd "$(dirname "$0")/terraform"
|
||||||
|
|
||||||
|
# Check if terraform.tfvars exists, if not copy from example
|
||||||
|
if [ ! -f terraform.tfvars ]; then
|
||||||
|
echo "Creating terraform.tfvars from example..."
|
||||||
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
|
# Replace project ID in tfvars file
|
||||||
|
sed -i "s/your-gcp-project-id/$PROJECT_ID/g" terraform.tfvars
|
||||||
|
echo "Please review and edit terraform.tfvars with your desired values"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
terraform init
|
||||||
|
terraform apply
|
||||||
|
|
||||||
|
cd - > /dev/null
|
||||||
|
echo "Provisioning completed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build and push Docker image
|
||||||
|
if [ "$BUILD" = true ]; then
|
||||||
|
echo "Building and pushing Docker image..."
|
||||||
|
|
||||||
|
# Enable Docker to authenticate to GCR
|
||||||
|
gcloud auth configure-docker gcr.io
|
||||||
|
|
||||||
|
# Build the image with timestamp tag
|
||||||
|
TAG=$(date +%Y%m%d-%H%M%S)
|
||||||
|
FULL_IMAGE_NAME="gcr.io/$PROJECT_ID/$IMAGE_NAME:$TAG"
|
||||||
|
LATEST_IMAGE_NAME="gcr.io/$PROJECT_ID/$IMAGE_NAME:latest"
|
||||||
|
|
||||||
|
echo "Building image: $FULL_IMAGE_NAME"
|
||||||
|
docker build -t "$FULL_IMAGE_NAME" -t "$LATEST_IMAGE_NAME" .
|
||||||
|
|
||||||
|
echo "Pushing images to Container Registry..."
|
||||||
|
docker push "$FULL_IMAGE_NAME"
|
||||||
|
docker push "$LATEST_IMAGE_NAME"
|
||||||
|
|
||||||
|
echo "Image built and pushed successfully."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deploy to Cloud Run
|
||||||
|
if [ "$DEPLOY" = true ]; then
|
||||||
|
echo "Deploying to Cloud Run..."
|
||||||
|
|
||||||
|
# Deploy using the latest image
|
||||||
|
LATEST_IMAGE_NAME="gcr.io/$PROJECT_ID/$IMAGE_NAME:latest"
|
||||||
|
|
||||||
|
# Check if we have an existing service.yaml to use
|
||||||
|
if [ -f "$(dirname "$0")/cloud-run/service.yaml" ]; then
|
||||||
|
echo "Deploying using service.yaml configuration..."
|
||||||
|
gcloud run services replace "$(dirname "$0")/cloud-run/service.yaml" --region="$REGION"
|
||||||
|
else
|
||||||
|
echo "Deploying directly..."
|
||||||
|
gcloud run deploy "$SERVICE_NAME" \
|
||||||
|
--image="$LATEST_IMAGE_NAME" \
|
||||||
|
--platform="managed" \
|
||||||
|
--region="$REGION" \
|
||||||
|
--allow-unauthenticated
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get service URL
|
||||||
|
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region="$REGION" --format='value(status.url)')
|
||||||
|
|
||||||
|
echo "Deployment completed successfully."
|
||||||
|
echo "Service URL: $SERVICE_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "All operations completed."
|
||||||
21
deployment/terraform/.terraform.lock.hcl
generated
Normal file
21
deployment/terraform/.terraform.lock.hcl
generated
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/hashicorp/google" {
|
||||||
|
version = "6.36.1"
|
||||||
|
hashes = [
|
||||||
|
"h1:rj3g00i0dH4VxXYO5xXJg188i6OXWbFUT6WmLbO5orY=",
|
||||||
|
"zh:161d054bda352a286a997f80f3d59366d072377abc6777bfe8abacc2e10ac2bf",
|
||||||
|
"zh:314c38d8050036176031f691b533184c3578036085483fed877b3b139f887047",
|
||||||
|
"zh:503c9807312feb9766f0da207d5ac149aa6f5a669144c60da38a33d072ebe2c2",
|
||||||
|
"zh:897abe484c44c625b301e828a4967c9f781fbf33b5bb50afe226410ebbfd0137",
|
||||||
|
"zh:97bcdc879b48f5f8bee98316234a1eed3c2e440e356631066d07b5d85ccfe288",
|
||||||
|
"zh:b273e940da85c5d673cbb3cafe36fb70dd8536e2d8812e617191196c312dac3b",
|
||||||
|
"zh:ba294699ca7082d394498ce62ecb55501c6a141fd1c43db00a6abdaebc92fa2e",
|
||||||
|
"zh:c50be96b5c8df5124f18ccdef473eed0bc3a2452e674c19f58fbf7ee14195af4",
|
||||||
|
"zh:d5a8fda3abda57d912be020e22bab3568facc729756e5339af9a3e56ca277cbc",
|
||||||
|
"zh:dddbfed09dff01fe538830714a13e71d7581cf2ccfba15acc0a6bb7266147bed",
|
||||||
|
"zh:e65e8c2e97d1e23c9380516b1d37e111cc700b538d8fca6b9e28ebb89e305ee0",
|
||||||
|
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||||
|
]
|
||||||
|
}
|
||||||
95
deployment/terraform/README.md
Normal file
95
deployment/terraform/README.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Terraform Configuration for Sereact
|
||||||
|
|
||||||
|
This directory contains Terraform configurations to provision the required Google Cloud resources for Sereact:
|
||||||
|
|
||||||
|
- Google Cloud Run service
|
||||||
|
- Google Container Registry (GCR)
|
||||||
|
- Firestore database
|
||||||
|
- Cloud Storage bucket
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. Install [Terraform](https://www.terraform.io/downloads) (v1.0.0+)
|
||||||
|
2. Install [Google Cloud SDK](https://cloud.google.com/sdk/docs/install)
|
||||||
|
3. Authenticate with Google Cloud:
|
||||||
|
```bash
|
||||||
|
gcloud auth login
|
||||||
|
gcloud auth application-default login
|
||||||
|
```
|
||||||
|
4. Create or select a Google Cloud project:
|
||||||
|
```bash
|
||||||
|
gcloud projects create PROJECT_ID --name="Sereact Project" # optional
|
||||||
|
gcloud config set project PROJECT_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup and Usage
|
||||||
|
|
||||||
|
1. Copy the example variables file and edit it with your values:
|
||||||
|
```bash
|
||||||
|
cp terraform.tfvars.example terraform.tfvars
|
||||||
|
# Edit terraform.tfvars with your project-specific values
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Initialize Terraform:
|
||||||
|
```bash
|
||||||
|
terraform init
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Preview the changes:
|
||||||
|
```bash
|
||||||
|
terraform plan
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Apply the configuration:
|
||||||
|
```bash
|
||||||
|
terraform apply
|
||||||
|
```
|
||||||
|
|
||||||
|
5. After provisioning, you'll see outputs including:
|
||||||
|
- Cloud Run service URL
|
||||||
|
- Storage bucket name
|
||||||
|
- Firestore database ID
|
||||||
|
- Container Registry URL
|
||||||
|
|
||||||
|
## Managing Secrets
|
||||||
|
|
||||||
|
Secrets for environment variables (DATABASE_URI, API_KEY_SECRET, etc.) should be managed separately using Google Secret Manager:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create secrets
|
||||||
|
gcloud secrets create sereact-db-uri --replication-policy="automatic"
|
||||||
|
gcloud secrets create sereact-api-key-secret --replication-policy="automatic"
|
||||||
|
gcloud secrets create sereact-vector-db-key --replication-policy="automatic"
|
||||||
|
|
||||||
|
# Add secret versions
|
||||||
|
echo -n "your-secret-value" | gcloud secrets versions add sereact-db-uri --data-file=-
|
||||||
|
echo -n "your-secret-value" | gcloud secrets versions add sereact-api-key-secret --data-file=-
|
||||||
|
echo -n "your-secret-value" | gcloud secrets versions add sereact-vector-db-key --data-file=-
|
||||||
|
|
||||||
|
# Update Cloud Run service to use secrets
|
||||||
|
gcloud run services update sereact \
|
||||||
|
--update-secrets=DATABASE_URI=sereact-db-uri:latest,API_KEY_SECRET=sereact-api-key-secret:latest,VECTOR_DB_API_KEY=sereact-vector-db-key:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD Integration
|
||||||
|
|
||||||
|
To integrate this with CI/CD, store the `terraform.tfvars` securely in your CI/CD system and run Terraform as part of your deployment pipeline:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Example GitHub Actions step
|
||||||
|
- name: Terraform Apply
|
||||||
|
run: |
|
||||||
|
cd deployment/terraform
|
||||||
|
terraform init
|
||||||
|
terraform apply -auto-approve
|
||||||
|
env:
|
||||||
|
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GCP_SA_KEY }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Destroying Resources
|
||||||
|
|
||||||
|
To destroy all provisioned resources:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
terraform destroy
|
||||||
|
```
|
||||||
94
deployment/terraform/main.tf
Normal file
94
deployment/terraform/main.tf
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
provider "google" {
|
||||||
|
project = var.project_id
|
||||||
|
region = var.region
|
||||||
|
zone = var.zone
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable required APIs
|
||||||
|
resource "google_project_service" "services" {
|
||||||
|
for_each = toset([
|
||||||
|
"cloudresourcemanager.googleapis.com",
|
||||||
|
"containerregistry.googleapis.com",
|
||||||
|
"run.googleapis.com",
|
||||||
|
"firestore.googleapis.com",
|
||||||
|
"storage.googleapis.com"
|
||||||
|
])
|
||||||
|
|
||||||
|
project = var.project_id
|
||||||
|
service = each.key
|
||||||
|
|
||||||
|
disable_on_destroy = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cloud Storage bucket
|
||||||
|
resource "google_storage_bucket" "app_bucket" {
|
||||||
|
name = var.storage_bucket_name
|
||||||
|
location = var.region
|
||||||
|
uniform_bucket_level_access = true
|
||||||
|
|
||||||
|
depends_on = [google_project_service.services]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Firestore Database
|
||||||
|
resource "google_firestore_database" "database" {
|
||||||
|
name = var.firestore_db_name
|
||||||
|
location_id = var.region
|
||||||
|
type = "FIRESTORE_NATIVE"
|
||||||
|
|
||||||
|
depends_on = [google_project_service.services]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Container Registry - no explicit resource needed, just enable the API
|
||||||
|
# You'll push images to gcr.io/${var.project_id}/sereact
|
||||||
|
|
||||||
|
# Cloud Run service
|
||||||
|
resource "google_cloud_run_service" "sereact" {
|
||||||
|
name = "sereact"
|
||||||
|
location = var.region
|
||||||
|
|
||||||
|
template {
|
||||||
|
spec {
|
||||||
|
containers {
|
||||||
|
# Using a public placeholder image that exists to avoid deployment failure
|
||||||
|
# You'll need to update this later with your actual image
|
||||||
|
image = "gcr.io/google-samples/hello-app:1.0"
|
||||||
|
|
||||||
|
ports {
|
||||||
|
container_port = 8080
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
limits = {
|
||||||
|
cpu = "1"
|
||||||
|
memory = "512Mi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "DATABASE_NAME"
|
||||||
|
value = var.firestore_db_name
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "GCS_BUCKET_NAME"
|
||||||
|
value = var.storage_bucket_name
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "LOG_LEVEL"
|
||||||
|
value = "INFO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [google_project_service.services]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make the Cloud Run service publicly accessible
|
||||||
|
resource "google_cloud_run_service_iam_member" "public_access" {
|
||||||
|
service = google_cloud_run_service.sereact.name
|
||||||
|
location = google_cloud_run_service.sereact.location
|
||||||
|
role = "roles/run.invoker"
|
||||||
|
member = "allUsers"
|
||||||
|
}
|
||||||
19
deployment/terraform/outputs.tf
Normal file
19
deployment/terraform/outputs.tf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
output "cloud_run_url" {
|
||||||
|
value = google_cloud_run_service.sereact.status[0].url
|
||||||
|
description = "The URL of the deployed Cloud Run service"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "storage_bucket_name" {
|
||||||
|
value = google_storage_bucket.app_bucket.name
|
||||||
|
description = "The name of the provisioned Cloud Storage bucket"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "firestore_database_id" {
|
||||||
|
value = google_firestore_database.database.id
|
||||||
|
description = "The ID of the provisioned Firestore database"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "container_registry_url" {
|
||||||
|
value = "gcr.io/${var.project_id}/sereact"
|
||||||
|
description = "The URL of the Container Registry repository"
|
||||||
|
}
|
||||||
9
deployment/terraform/terraform.tfstate
Normal file
9
deployment/terraform/terraform.tfstate
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": 4,
|
||||||
|
"terraform_version": "1.10.1",
|
||||||
|
"serial": 28,
|
||||||
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
|
"outputs": {},
|
||||||
|
"resources": [],
|
||||||
|
"check_results": null
|
||||||
|
}
|
||||||
416
deployment/terraform/terraform.tfstate.backup
Normal file
416
deployment/terraform/terraform.tfstate.backup
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
{
|
||||||
|
"version": 4,
|
||||||
|
"terraform_version": "1.10.1",
|
||||||
|
"serial": 18,
|
||||||
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
|
"outputs": {
|
||||||
|
"cloud_run_url": {
|
||||||
|
"value": "https://sereact-p64zpdtkta-uc.a.run.app",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"container_registry_url": {
|
||||||
|
"value": "gcr.io/gen-lang-client-0424120530/sereact",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"firestore_database_id": {
|
||||||
|
"value": "projects/gen-lang-client-0424120530/databases/imagedb",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"storage_bucket_name": {
|
||||||
|
"value": "sereact-storage-bucket",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_cloud_run_service",
|
||||||
|
"name": "sereact",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 2,
|
||||||
|
"attributes": {
|
||||||
|
"autogenerate_revision_name": false,
|
||||||
|
"id": "locations/us-central1/namespaces/gen-lang-client-0424120530/services/sereact",
|
||||||
|
"location": "us-central1",
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"annotations": {},
|
||||||
|
"effective_annotations": {
|
||||||
|
"run.googleapis.com/ingress": "all",
|
||||||
|
"run.googleapis.com/ingress-status": "all",
|
||||||
|
"run.googleapis.com/operation-id": "0982194f-b3e8-45b8-a33f-7ed5fd529307",
|
||||||
|
"run.googleapis.com/urls": "[\"https://sereact-761163285547.us-central1.run.app\",\"https://sereact-p64zpdtkta-uc.a.run.app\"]",
|
||||||
|
"serving.knative.dev/creator": "johnpccd3@gmail.com",
|
||||||
|
"serving.knative.dev/lastModifier": "johnpccd3@gmail.com"
|
||||||
|
},
|
||||||
|
"effective_labels": {
|
||||||
|
"cloud.googleapis.com/location": "us-central1"
|
||||||
|
},
|
||||||
|
"generation": 1,
|
||||||
|
"labels": {},
|
||||||
|
"namespace": "gen-lang-client-0424120530",
|
||||||
|
"resource_version": "AAY108GXDwM",
|
||||||
|
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
||||||
|
"terraform_labels": {},
|
||||||
|
"uid": "5b695749-5095-4fb5-86bd-4d86f77dc7da"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "sereact",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"status": [
|
||||||
|
{
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"message": "",
|
||||||
|
"reason": "",
|
||||||
|
"status": "True",
|
||||||
|
"type": "Ready"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"message": "",
|
||||||
|
"reason": "",
|
||||||
|
"status": "True",
|
||||||
|
"type": "ConfigurationsReady"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"message": "",
|
||||||
|
"reason": "",
|
||||||
|
"status": "True",
|
||||||
|
"type": "RoutesReady"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"latest_created_revision_name": "sereact-00001-bt2",
|
||||||
|
"latest_ready_revision_name": "sereact-00001-bt2",
|
||||||
|
"observed_generation": 1,
|
||||||
|
"traffic": [
|
||||||
|
{
|
||||||
|
"latest_revision": true,
|
||||||
|
"percent": 100,
|
||||||
|
"revision_name": "sereact-00001-bt2",
|
||||||
|
"tag": "",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": "https://sereact-p64zpdtkta-uc.a.run.app"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"template": [
|
||||||
|
{
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"autoscaling.knative.dev/maxScale": "3"
|
||||||
|
},
|
||||||
|
"generation": 0,
|
||||||
|
"labels": {
|
||||||
|
"run.googleapis.com/startupProbeType": "Default"
|
||||||
|
},
|
||||||
|
"name": "",
|
||||||
|
"namespace": "",
|
||||||
|
"resource_version": "",
|
||||||
|
"self_link": "",
|
||||||
|
"uid": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spec": [
|
||||||
|
{
|
||||||
|
"container_concurrency": 80,
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"args": null,
|
||||||
|
"command": null,
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"name": "DATABASE_NAME",
|
||||||
|
"value": "imagedb",
|
||||||
|
"value_from": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GCS_BUCKET_NAME",
|
||||||
|
"value": "sereact-storage-bucket",
|
||||||
|
"value_from": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LOG_LEVEL",
|
||||||
|
"value": "INFO",
|
||||||
|
"value_from": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"env_from": [],
|
||||||
|
"image": "gcr.io/google-samples/hello-app:1.0",
|
||||||
|
"liveness_probe": [],
|
||||||
|
"name": "",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"container_port": 8080,
|
||||||
|
"name": "http1",
|
||||||
|
"protocol": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"limits": {
|
||||||
|
"cpu": "1",
|
||||||
|
"memory": "512Mi"
|
||||||
|
},
|
||||||
|
"requests": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"startup_probe": [
|
||||||
|
{
|
||||||
|
"failure_threshold": 1,
|
||||||
|
"grpc": [],
|
||||||
|
"http_get": [],
|
||||||
|
"initial_delay_seconds": 0,
|
||||||
|
"period_seconds": 240,
|
||||||
|
"tcp_socket": [
|
||||||
|
{
|
||||||
|
"port": 8080
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeout_seconds": 240
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volume_mounts": [],
|
||||||
|
"working_dir": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"node_selector": null,
|
||||||
|
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
||||||
|
"serving_state": "",
|
||||||
|
"timeout_seconds": 300,
|
||||||
|
"volumes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeouts": null,
|
||||||
|
"traffic": [
|
||||||
|
{
|
||||||
|
"latest_revision": true,
|
||||||
|
"percent": 100,
|
||||||
|
"revision_name": "",
|
||||||
|
"tag": "",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMiJ9",
|
||||||
|
"dependencies": [
|
||||||
|
"google_project_service.services"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_cloud_run_service_iam_member",
|
||||||
|
"name": "public_access",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"condition": [],
|
||||||
|
"etag": "BwY108GyUf0=",
|
||||||
|
"id": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact/roles/run.invoker/allUsers",
|
||||||
|
"location": "us-central1",
|
||||||
|
"member": "allUsers",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"role": "roles/run.invoker",
|
||||||
|
"service": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact"
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "bnVsbA==",
|
||||||
|
"dependencies": [
|
||||||
|
"google_cloud_run_service.sereact",
|
||||||
|
"google_project_service.services"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_firestore_database",
|
||||||
|
"name": "database",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"app_engine_integration_mode": "DISABLED",
|
||||||
|
"cmek_config": [],
|
||||||
|
"concurrency_mode": "PESSIMISTIC",
|
||||||
|
"create_time": "",
|
||||||
|
"database_edition": "STANDARD",
|
||||||
|
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
||||||
|
"deletion_policy": "ABANDON",
|
||||||
|
"earliest_version_time": "2025-05-23T20:47:31.801717Z",
|
||||||
|
"etag": "IIelp4e8uo0DMPX0nai7uo0D",
|
||||||
|
"id": "projects/gen-lang-client-0424120530/databases/imagedb",
|
||||||
|
"key_prefix": "",
|
||||||
|
"location_id": "us-central1",
|
||||||
|
"name": "imagedb",
|
||||||
|
"point_in_time_recovery_enablement": "POINT_IN_TIME_RECOVERY_DISABLED",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"timeouts": null,
|
||||||
|
"type": "FIRESTORE_NATIVE",
|
||||||
|
"uid": "177e30f2-9b67-428c-9979-22e625b929c4",
|
||||||
|
"update_time": "",
|
||||||
|
"version_retention_period": "3600s"
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19",
|
||||||
|
"dependencies": [
|
||||||
|
"google_project_service.services"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_project_service",
|
||||||
|
"name": "services",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"index_key": "cloudresourcemanager.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/cloudresourcemanager.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "cloudresourcemanager.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "containerregistry.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/containerregistry.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "containerregistry.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "firestore.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/firestore.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "firestore.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "run.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/run.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "run.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "storage.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/storage.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "storage.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_storage_bucket",
|
||||||
|
"name": "app_bucket",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 3,
|
||||||
|
"attributes": {
|
||||||
|
"autoclass": [],
|
||||||
|
"cors": [],
|
||||||
|
"custom_placement_config": [],
|
||||||
|
"default_event_based_hold": false,
|
||||||
|
"effective_labels": {
|
||||||
|
"goog-terraform-provisioned": "true"
|
||||||
|
},
|
||||||
|
"enable_object_retention": false,
|
||||||
|
"encryption": [],
|
||||||
|
"force_destroy": false,
|
||||||
|
"hierarchical_namespace": [
|
||||||
|
{
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "sereact-storage-bucket",
|
||||||
|
"labels": {},
|
||||||
|
"lifecycle_rule": [],
|
||||||
|
"location": "US-CENTRAL1",
|
||||||
|
"logging": [],
|
||||||
|
"name": "sereact-storage-bucket",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"project_number": 761163285547,
|
||||||
|
"public_access_prevention": "inherited",
|
||||||
|
"requester_pays": false,
|
||||||
|
"retention_policy": [],
|
||||||
|
"rpo": null,
|
||||||
|
"self_link": "https://www.googleapis.com/storage/v1/b/sereact-storage-bucket",
|
||||||
|
"soft_delete_policy": [
|
||||||
|
{
|
||||||
|
"effective_time": "2025-05-23T20:47:26.788Z",
|
||||||
|
"retention_duration_seconds": 604800
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storage_class": "STANDARD",
|
||||||
|
"terraform_labels": {
|
||||||
|
"goog-terraform-provisioned": "true"
|
||||||
|
},
|
||||||
|
"time_created": "2025-05-23T20:47:26.788Z",
|
||||||
|
"timeouts": null,
|
||||||
|
"uniform_bucket_level_access": true,
|
||||||
|
"updated": "2025-05-23T20:47:26.788Z",
|
||||||
|
"url": "gs://sereact-storage-bucket",
|
||||||
|
"versioning": [],
|
||||||
|
"website": []
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsInJlYWQiOjI0MDAwMDAwMDAwMCwidXBkYXRlIjoyNDAwMDAwMDAwMDB9LCJzY2hlbWFfdmVyc2lvbiI6IjMifQ==",
|
||||||
|
"dependencies": [
|
||||||
|
"google_project_service.services"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"check_results": null
|
||||||
|
}
|
||||||
5
deployment/terraform/terraform.tfvars.example
Normal file
5
deployment/terraform/terraform.tfvars.example
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
project_id = "your-gcp-project-id"
|
||||||
|
region = "us-central1"
|
||||||
|
zone = "us-central1-a"
|
||||||
|
storage_bucket_name = "your-app-storage-bucket"
|
||||||
|
firestore_db_name = "imagedb"
|
||||||
27
deployment/terraform/variables.tf
Normal file
27
deployment/terraform/variables.tf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
variable "project_id" {
|
||||||
|
description = "The Google Cloud project ID"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "region" {
|
||||||
|
description = "The Google Cloud region"
|
||||||
|
type = string
|
||||||
|
default = "us-central1"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "zone" {
|
||||||
|
description = "The Google Cloud zone"
|
||||||
|
type = string
|
||||||
|
default = "us-central1-a"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "storage_bucket_name" {
|
||||||
|
description = "The name of the Cloud Storage bucket"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "firestore_db_name" {
|
||||||
|
description = "The name of the Firestore database"
|
||||||
|
type = string
|
||||||
|
default = "imagedb"
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user