Skip to content

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added registry/AJ0070/.images/avtar.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions registry/AJ0070/README.md
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
---
23 changes: 23 additions & 0 deletions registry/AJ0070/modules/pgadmin/README.md
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/postgres.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
}
```
10 changes: 10 additions & 0 deletions registry/AJ0070/modules/pgadmin/main.test.ts
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",
});
});
108 changes: 108 additions & 0 deletions registry/AJ0070/modules/pgadmin/main.tf
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 = "admin@coder.com"
DEFAULT_PASSWORD = "coderPASSWORD"
SERVER_MODE = false
MASTER_PASSWORD_REQUIRED = false
LISTEN_ADDRESS = "127.0.0.1"
}
}

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/postgres.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/postgres.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))
)
])
}
76 changes: 76 additions & 0 deletions registry/AJ0070/modules/pgadmin/run.sh
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
fi

printf "Installing pgAdmin 4 in virtual environment...\n"
if ! "$PGADMIN_VENV_DIR/bin/pip" install pgadmin4; then
echo "⚠️ Warning: Failed to install pgAdmin4"
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
3 changes: 3 additions & 0 deletions registry/coder/modules/filebrowser/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ describe("filebrowser", async () => {
"apk add bash",
);

const expectedUrl = "http://localhost:13339/@default/default/apps/filebrowser";
const expectedLogLine = `📂 Serving /root at ${expectedUrl} `;

testBaseLine(output);
}, 15000);
});
2 changes: 1 addition & 1 deletion registry/coder/modules/filebrowser/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ filebrowser config set --baseurl=${SERVER_BASE_PATH} --port=${PORT} --auth.metho

printf "👷 Starting filebrowser in background... \n\n"

printf "📂 Serving $${ROOT_DIR} at http://localhost:${PORT} \n\n"
printf "📂 Serving $${ROOT_DIR} at http://localhost:${PORT}${SERVER_BASE_PATH} \n\n"

filebrowser >>${LOG_PATH} 2>&1 &

Expand Down