-
Notifications
You must be signed in to change notification settings - Fork 46
feat(pgadmin): add new module for pgAdmin #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
93059b8
af16096
6319e67
0338bd7
8f19fd9
db8df71
9947034
f9b3359
542f8ec
c8f4ba2
d8ed39f
ce103bd
dc1872b
7ea3735
5535a3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
display_name: Jash | ||
bio: Coder user and contributor. | ||
github: AJ0070 | ||
avatar: ./.images/avatar.png | ||
status: community | ||
--- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--- | ||
display_name: "pgAdmin" | ||
description: "A web-based interface for managing PostgreSQL databases in your Coder workspace." | ||
icon: "../../../../.icons/pgadmin.svg" | ||
maintainer_github: "AJ0070" | ||
verified: false | ||
tags: ["database", "postgres", "pgadmin", "web-ide"] | ||
--- | ||
|
||
# pgAdmin | ||
|
||
This module adds a pgAdmin app to your Coder workspace, providing a powerful web-based interface for managing PostgreSQL databases. | ||
|
||
It can be served on a Coder subdomain for easy access, or on `localhost` if you prefer to use port-forwarding. | ||
|
||
```tf | ||
module "pgadmin" { | ||
count = data.coder_workspace.me.start_count | ||
source = "registry.coder.com/AJ0070/pgadmin/coder" | ||
version = "1.0.0" | ||
agent_id = coder_agent.example.id | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { describe } from "bun:test"; | ||
import { runTerraformInit, testRequiredVariables } from "~test"; | ||
|
||
describe("pgadmin", async () => { | ||
await runTerraformInit(import.meta.dir); | ||
|
||
testRequiredVariables(import.meta.dir, { | ||
agent_id: "foo", | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,108 @@ | ||||||||||||||||||||||||||
terraform { | ||||||||||||||||||||||||||
required_providers { | ||||||||||||||||||||||||||
coder = { | ||||||||||||||||||||||||||
source = "coder/coder" | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
variable "agent_id" { | ||||||||||||||||||||||||||
type = string | ||||||||||||||||||||||||||
description = "The agent to install pgAdmin on." | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
variable "port" { | ||||||||||||||||||||||||||
type = number | ||||||||||||||||||||||||||
description = "The port to run pgAdmin on." | ||||||||||||||||||||||||||
default = 5050 | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
variable "subdomain" { | ||||||||||||||||||||||||||
type = bool | ||||||||||||||||||||||||||
description = "If true, the app will be served on a subdomain." | ||||||||||||||||||||||||||
default = true | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
variable "config" { | ||||||||||||||||||||||||||
type = any | ||||||||||||||||||||||||||
description = "A map of pgAdmin configuration settings." | ||||||||||||||||||||||||||
default = { | ||||||||||||||||||||||||||
DEFAULT_EMAIL = "[email protected]" | ||||||||||||||||||||||||||
DEFAULT_PASSWORD = "coderPASSWORD" | ||||||||||||||||||||||||||
SERVER_MODE = false | ||||||||||||||||||||||||||
MASTER_PASSWORD_REQUIRED = false | ||||||||||||||||||||||||||
LISTEN_ADDRESS = "127.0.0.1" | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using 'any' type for the config variable is too permissive and provides no type safety. Consider defining a more specific object type with optional attributes to better validate the configuration structure.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
data "coder_workspace" "me" {} | ||||||||||||||||||||||||||
data "coder_workspace_owner" "me" {} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
resource "coder_app" "pgadmin" { | ||||||||||||||||||||||||||
count = data.coder_workspace.me.start_count | ||||||||||||||||||||||||||
agent_id = var.agent_id | ||||||||||||||||||||||||||
display_name = "pgAdmin" | ||||||||||||||||||||||||||
slug = "pgadmin" | ||||||||||||||||||||||||||
icon = "/icon/pgadmin.svg" | ||||||||||||||||||||||||||
url = local.url | ||||||||||||||||||||||||||
subdomain = var.subdomain | ||||||||||||||||||||||||||
share = "owner" | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
healthcheck { | ||||||||||||||||||||||||||
url = local.healthcheck_url | ||||||||||||||||||||||||||
interval = 5 | ||||||||||||||||||||||||||
threshold = 6 | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
resource "coder_script" "pgadmin" { | ||||||||||||||||||||||||||
agent_id = var.agent_id | ||||||||||||||||||||||||||
display_name = "Install and run pgAdmin" | ||||||||||||||||||||||||||
icon = "/icon/pgadmin.svg" | ||||||||||||||||||||||||||
run_on_start = true | ||||||||||||||||||||||||||
script = templatefile("${path.module}/run.sh", { | ||||||||||||||||||||||||||
PORT = var.port, | ||||||||||||||||||||||||||
LOG_PATH = "/tmp/pgadmin.log", | ||||||||||||||||||||||||||
SERVER_BASE_PATH = local.server_base_path, | ||||||||||||||||||||||||||
CONFIG = local.config_content, | ||||||||||||||||||||||||||
PGADMIN_DATA_DIR = local.pgadmin_data_dir, | ||||||||||||||||||||||||||
PGADMIN_LOG_DIR = local.pgadmin_log_dir, | ||||||||||||||||||||||||||
PGADMIN_VENV_DIR = local.pgadmin_venv_dir | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
locals { | ||||||||||||||||||||||||||
server_base_path = var.subdomain ? "" : format("/@%s/%s/apps/%s", data.coder_workspace_owner.me.name, data.coder_workspace.me.name, "pgadmin") | ||||||||||||||||||||||||||
url = "http://localhost:${var.port}${local.server_base_path}" | ||||||||||||||||||||||||||
healthcheck_url = "http://localhost:${var.port}${local.server_base_path}/" | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# pgAdmin data directories (user-local paths) | ||||||||||||||||||||||||||
pgadmin_data_dir = "$HOME/.pgadmin" | ||||||||||||||||||||||||||
pgadmin_log_dir = "$HOME/.pgadmin/logs" | ||||||||||||||||||||||||||
pgadmin_venv_dir = "$HOME/.pgadmin/venv" | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
base_config = merge(var.config, { | ||||||||||||||||||||||||||
LISTEN_PORT = var.port | ||||||||||||||||||||||||||
# Override paths for user installation | ||||||||||||||||||||||||||
DATA_DIR = local.pgadmin_data_dir | ||||||||||||||||||||||||||
LOG_FILE = "${local.pgadmin_log_dir}/pgadmin4.log" | ||||||||||||||||||||||||||
SQLITE_PATH = "${local.pgadmin_data_dir}/pgadmin4.db" | ||||||||||||||||||||||||||
SESSION_DB_PATH = "${local.pgadmin_data_dir}/sessions" | ||||||||||||||||||||||||||
STORAGE_DIR = "${local.pgadmin_data_dir}/storage" | ||||||||||||||||||||||||||
# Disable initial setup prompts for automated deployment | ||||||||||||||||||||||||||
SETUP_AUTH = false | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
config_with_path = var.subdomain ? local.base_config : merge(local.base_config, { | ||||||||||||||||||||||||||
APPLICATION_ROOT = local.server_base_path | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
config_content = join("\n", [ | ||||||||||||||||||||||||||
for key, value in local.config_with_path : | ||||||||||||||||||||||||||
format("%s = %s", key, | ||||||||||||||||||||||||||
can(regex("^(true|false)$", tostring(value))) ? (value ? "True" : "False") : | ||||||||||||||||||||||||||
can(tonumber(value)) ? tostring(value) : | ||||||||||||||||||||||||||
format("'%s'", tostring(value)) | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
]) | ||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,76 @@ | ||||||||||||||||||||||||||||
#!/usr/bin/env bash | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
set -euo pipefail | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
PORT=${PORT} | ||||||||||||||||||||||||||||
LOG_PATH=${LOG_PATH} | ||||||||||||||||||||||||||||
SERVER_BASE_PATH=${SERVER_BASE_PATH} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
BOLD='\033[0;1m' | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "$${BOLD}Installing pgAdmin!\n" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Check if Python 3 is available | ||||||||||||||||||||||||||||
if ! command -v python3 > /dev/null 2>&1; then | ||||||||||||||||||||||||||||
echo "⚠️ Warning: Python 3 is not installed. Please install Python 3 before using this module." | ||||||||||||||||||||||||||||
exit 0 | ||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Setup pgAdmin directories (from Terraform configuration) | ||||||||||||||||||||||||||||
PGADMIN_DATA_DIR="${PGADMIN_DATA_DIR}" | ||||||||||||||||||||||||||||
PGADMIN_LOG_DIR="${PGADMIN_LOG_DIR}" | ||||||||||||||||||||||||||||
PGADMIN_VENV_DIR="${PGADMIN_VENV_DIR}" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "Setting up pgAdmin directories...\n" | ||||||||||||||||||||||||||||
mkdir -p "$PGADMIN_DATA_DIR" | ||||||||||||||||||||||||||||
mkdir -p "$PGADMIN_LOG_DIR" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Check if pgAdmin virtual environment already exists and is working | ||||||||||||||||||||||||||||
if [ -f "$PGADMIN_VENV_DIR/bin/pgadmin4" ] && [ -f "$PGADMIN_VENV_DIR/bin/activate" ]; then | ||||||||||||||||||||||||||||
printf "🥳 pgAdmin virtual environment already exists\n\n" | ||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||
printf "Creating Python virtual environment for pgAdmin...\n" | ||||||||||||||||||||||||||||
if ! python3 -m venv "$PGADMIN_VENV_DIR"; then | ||||||||||||||||||||||||||||
echo "⚠️ Warning: Failed to create virtual environment" | ||||||||||||||||||||||||||||
exit 0 | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message should be more descriptive and actionable. Consider including the specific error or suggesting potential solutions like checking Python installation or permissions.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "Installing pgAdmin 4 in virtual environment...\n" | ||||||||||||||||||||||||||||
if ! "$PGADMIN_VENV_DIR/bin/pip" install pgadmin4; then | ||||||||||||||||||||||||||||
echo "⚠️ Warning: Failed to install pgAdmin4" | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message should be more descriptive and actionable. Consider including information about potential causes like network issues, Python version compatibility, or suggesting to check pip installation.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||
exit 0 | ||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "🥳 pgAdmin has been installed successfully\n\n" | ||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "$${BOLD}Configuring pgAdmin...\n" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if [ -f "$PGADMIN_VENV_DIR/bin/pgadmin4" ]; then | ||||||||||||||||||||||||||||
# pgAdmin installs to a predictable location in the virtual environment | ||||||||||||||||||||||||||||
PYTHON_VERSION=$("$PGADMIN_VENV_DIR/bin/python" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") | ||||||||||||||||||||||||||||
PGADMIN_INSTALL_DIR="$PGADMIN_VENV_DIR/lib/python$PYTHON_VERSION/site-packages/pgadmin4" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Create pgAdmin config file in the correct location (next to config.py) | ||||||||||||||||||||||||||||
cat > "$PGADMIN_INSTALL_DIR/config_local.py" << EOF | ||||||||||||||||||||||||||||
# pgAdmin configuration for Coder workspace | ||||||||||||||||||||||||||||
${CONFIG} | ||||||||||||||||||||||||||||
EOF | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "📄 Config written to $PGADMIN_INSTALL_DIR/config_local.py\n" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
printf "$${BOLD}Starting pgAdmin in background...\n" | ||||||||||||||||||||||||||||
printf "📝 Check logs at $${LOG_PATH}\n" | ||||||||||||||||||||||||||||
printf "🌐 Serving at http://localhost:${PORT}${SERVER_BASE_PATH}\n" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Create required directories | ||||||||||||||||||||||||||||
mkdir -p "$PGADMIN_DATA_DIR/sessions" | ||||||||||||||||||||||||||||
mkdir -p "$PGADMIN_DATA_DIR/storage" | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
# Start pgadmin4 from the virtual environment with proper environment | ||||||||||||||||||||||||||||
cd "$PGADMIN_DATA_DIR" | ||||||||||||||||||||||||||||
PYTHONPATH="$PGADMIN_INSTALL_DIR:$${PYTHONPATH:-}" "$PGADMIN_VENV_DIR/bin/pgadmin4" > "$${LOG_PATH}" 2>&1 & | ||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||
printf "⚠️ Warning: pgAdmin4 virtual environment not found\n" | ||||||||||||||||||||||||||||
printf "📝 Installation may have failed - check logs above\n" | ||||||||||||||||||||||||||||
fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a hardcoded default password poses a security risk. Consider using a randomly generated password or requiring users to set their own password through a variable.
Copilot uses AI. Check for mistakes.