From f2432b0e4b316af0809f77bd141a8882b62ee943 Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 13:35:24 -0500 Subject: [PATCH 1/7] init - PGAdmin Bounty --- .DS_Store | Bin 0 -> 8196 bytes registry/.DS_Store | Bin 0 -> 6148 bytes registry/phoenix/.DS_Store | Bin 0 -> 6148 bytes registry/phoenix/pgadmin/README.md | 23 ++++++ registry/phoenix/pgadmin/main.test.ts | 10 +++ registry/phoenix/pgadmin/main.tf | 108 ++++++++++++++++++++++++++ registry/phoenix/pgadmin/run.sh | 76 ++++++++++++++++++ 7 files changed, 217 insertions(+) create mode 100644 .DS_Store create mode 100644 registry/.DS_Store create mode 100644 registry/phoenix/.DS_Store create mode 100644 registry/phoenix/pgadmin/README.md create mode 100644 registry/phoenix/pgadmin/main.test.ts create mode 100644 registry/phoenix/pgadmin/main.tf create mode 100644 registry/phoenix/pgadmin/run.sh diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ed261b7abe79f9d40ef7600bc09aef28da51c5b7 GIT binary patch literal 8196 zcmeHM&2G~`5S~p!<0up=M5SJkEOD(uQ&EJ(CFBQG35wLDAOtAbOkXvWJAlD zk_t{j!AWS(LRTn4dI!#y>LeOUn$a*|7|1igwYxvRvVM2{(8U}-P7l#*zh%P_ zQB~_7kVl6=#i;s6ayduJGd= z-3WY-(sqljoUVs8IIx~ugN(@6L`2H;1b5g1Ydh4XPTDeYB$C?8^b{7Dk)Dc3#Z-Ki6>Fh8NcGQUKslB{Md1y zd&6medI?H~E0ApDGbMiY8Vqh)n|HZqGj9zJx(fgc8(g^VkMpMCJ- zAu@3;S2_QZELAx>kSBZc$>`C`MX`{Xm_%9dF@*IAeDKqrc_KI)#kE8>mY{>2r8pfk z&cl@6GTXxHkv}wlmn_aFcP3q> zm`3DNw)V}7n76f<1iTy`QG#A%elvz$ti-e^r3v0CL_|a{H`$HHU|(5#s|wpMvQ+Ou z@BB25vb@*($QoPC?VXm@vi7WJ-h>xkKFa4=e>8g{N)I@X{Z)SCKa9d+*y-NkNj{2_ za3%wyAOz*3gy;;L|y@aO;k%mUi<`z7+a&Ou~djBFs4F* zDwOFf228hzSSnQE#PsEZ>7JRsp)lDy+P5X0n5)pFMggP1rUF~4*b(Rd-Jjq8 zH-k*cC}0%$uM}X-fj8)5NcwE84Njc3HvBnUnBbKPWe5^|9LtP2iud8t@XQt&psTS| Sh#Hvr5s)&N#3=Ab75D~Fn7ar7 literal 0 HcmV?d00001 diff --git a/registry/phoenix/.DS_Store b/registry/phoenix/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..02ef6f90a653906e34878e84a3dbe8346bb80bbd GIT binary patch literal 6148 zcmeHK%}T>S5T0$TO({YS3OxqA7Hx|a!Ap$w;MIs8RBB>M4W`-BAA2Z;ob`o#5?@DW zcDJHdZz5J^VD_8LPm=vM>}CK!c;l!JU;}`KN|-C*@P$yEbU|{)lSdTl9zBR5Jx=6J zm@H(o<1aEmYgdFmbRmEU-mRYuF+!ik0qWL^60{bw!^yB8CMx?W>?iSXRI5FUT)wcf zTC|E**}C#?<-{Kaqw&xS1{ZX7DrFMR?I1jhJCnA(ekjvX5T~7iDu|;Frd*!KX(T6} z9H-Gx)%rSMm8??Ru1u%(ovKrBG-g$2TCeTm#a^>Ho0Y7M&F%e@_Fd9T<%4=}5crKM zSu;3?M>IZhaPJS&M5bMg%&X?vjLZNtzzi%u17>Hl%F90$o&ht!4E!(yv_Ckggs#C% zquM%fP%Qvr0o_W_rk_TtaSXZ!GmRKQ5xNvnmkQHj2wjeT$K<&NGmW|&glRs6d9pAa zicn9-`#UNfgsYK9W`G&^$N=?zC^nt{N8k7VDv1YXfEoCo42VL@Z+SR3bG9zblFnKO s^%|9g@-mHYC1|Ll7<1_;uAnMGze5J1YcSJ@9u)o&P&Dws4E!nsuja2<%m4rY literal 0 HcmV?d00001 diff --git a/registry/phoenix/pgadmin/README.md b/registry/phoenix/pgadmin/README.md new file mode 100644 index 00000000..397e11f2 --- /dev/null +++ b/registry/phoenix/pgadmin/README.md @@ -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 +} +``` diff --git a/registry/phoenix/pgadmin/main.test.ts b/registry/phoenix/pgadmin/main.test.ts new file mode 100644 index 00000000..90047100 --- /dev/null +++ b/registry/phoenix/pgadmin/main.test.ts @@ -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", + }); +}); \ No newline at end of file diff --git a/registry/phoenix/pgadmin/main.tf b/registry/phoenix/pgadmin/main.tf new file mode 100644 index 00000000..cab0c096 --- /dev/null +++ b/registry/phoenix/pgadmin/main.tf @@ -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)) + ) + ]) +} \ No newline at end of file diff --git a/registry/phoenix/pgadmin/run.sh b/registry/phoenix/pgadmin/run.sh new file mode 100644 index 00000000..ebf2a507 --- /dev/null +++ b/registry/phoenix/pgadmin/run.sh @@ -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 \ No newline at end of file From 35a42c9002f21a6c7d4c6ce0bcd7cd7e72099c28 Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 13:36:45 -0500 Subject: [PATCH 2/7] Adjust Location --- registry/.DS_Store | Bin 6148 -> 6148 bytes registry/{phoenix => coder}/.DS_Store | Bin 6148 -> 6148 bytes registry/coder/modules/.DS_Store | Bin 0 -> 10244 bytes .../modules}/pgadmin/README.md | 0 .../modules}/pgadmin/main.test.ts | 0 .../modules}/pgadmin/main.tf | 0 .../{phoenix => coder/modules}/pgadmin/run.sh | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename registry/{phoenix => coder}/.DS_Store (93%) create mode 100644 registry/coder/modules/.DS_Store rename registry/{phoenix => coder/modules}/pgadmin/README.md (100%) rename registry/{phoenix => coder/modules}/pgadmin/main.test.ts (100%) rename registry/{phoenix => coder/modules}/pgadmin/main.tf (100%) rename registry/{phoenix => coder/modules}/pgadmin/run.sh (100%) diff --git a/registry/.DS_Store b/registry/.DS_Store index 6702a3309d8e175d92a7e6674c7a11cc450f1944..321b8385d76c8a0b420f6257635ebed974b1903f 100644 GIT binary patch delta 68 zcmZoMXfc@J&&aniU^g=(-((&ZU2ax}WQKf(6oyoWqRIDIj*BDl%YuvYa`N-i85kHC PH=D6MW!lWn@s}R}X=@U5 delta 31 ncmZoMXfc@J&&abeU^g=(&tx7J-OZ}3kC-MlyxGjo@s}R}o)ijw diff --git a/registry/phoenix/.DS_Store b/registry/coder/.DS_Store similarity index 93% rename from registry/phoenix/.DS_Store rename to registry/coder/.DS_Store index 02ef6f90a653906e34878e84a3dbe8346bb80bbd..9412da7e79e7ae1e8163a9aea9fc87c7a906eeab 100644 GIT binary patch delta 206 zcmZoMXfc@J&(F%hz`)4BAi%(o!;s2QyfJPqqcBK}ogtSYpCN^z6e2!Zj!BUhRm6ws zWIc*VS#VKaPJUiG#6$*8h9Cx421f=L245hp2Q)9mGbcYeDJMS(r~+sq!+Idr`ws>{ l76VX63D6C>3g5=6n!skCr(^u+7Tno2FVf|7A>?RW;7C;&>0qN34#S5B~H@RGmaf%r%|ao z%6jHM@E6$fN8o3$X9ee6yWzc;q+*2tJy-Vi$36GGd(M5&d9G4QpUeiwN<~Vk06Xp8 zE)HupKIgu&HR?MDuo`%!O4U;nm3*4!{S|M2!!zI+@Cc zz%$?(STex*A;M1EsqLb&GIih}O90qy+?EaJSO*9us%@vXi^>WVF{{;suA#bKV(1Ev z=MmjuJGEU@wt_2N!IiFC*7XWSOY6Wz;;wY3vi|59@C>Xnz_ojTRr^Q{Rc5Z=<1~-) zjKk?;?C<{}8_ty4fq$X~Kuo#PH#~oGJnzGEjQt0dBl;mQeRTml2R_49jBLG=-~)0p=}5AyMx)4KF$Pj3$8J8a3S(Zft?8(hq%glX1CV( zWerOF(8q!-f|C_4x1Mc8O@T|%5_5Ah6RmzUw7P>nF|Pvt>(nxR_a%!9$)c(Ss>J@0 zO=c=zcK*^^v@#xGPi zw9a>kyBvSzN)13wD?&@X5IwH%S1JSqPhbajcfRBd~2xWc*pZ%QqOlk$CETE z%A=!Sbz^IL=T0+d24V0`_dK6>%U(GvPI}X?c=dUnr}52sFa9DK&QJH=ewJrtFUf{e z0VIPVT)zG?$p-oSB%fu2La^QHLC^|Xr+W{tu8u!Eh>jmUx;}`mj*p(;;_2hZ*VnD! z!Mh)P^x5glbe!d{F>7Jd^$%n9R&~8Ra?W+Ky68@`G|%`pBdQ6lSr>gMId=J!I{wXI zXctw%imygG-$AH-&M>xmij{2QS{CjFD!>`3QoAN1v=AFcjAr$ksJlQF$mQk@%ik#l zG9%upFuqwVY}>)kInM07q^`~O!oOY1CMsB>3UD`7XLc)6#isujD_sq2FKS~|?^1Ms z;u-J^cm_NJo`H=FY*kO95cZSJ|Nq~J_YXV+o`L^91A6;;_xTC(xLHEDDe+r-g#A10 z+~~KctUz#(&+)MGIUX1M9RD76`X148!+EE+i^}2-wtxJe0sJmud~d+|)35(!i6?US N_5bo~!T)#t|0hX(fvx}m literal 0 HcmV?d00001 diff --git a/registry/phoenix/pgadmin/README.md b/registry/coder/modules/pgadmin/README.md similarity index 100% rename from registry/phoenix/pgadmin/README.md rename to registry/coder/modules/pgadmin/README.md diff --git a/registry/phoenix/pgadmin/main.test.ts b/registry/coder/modules/pgadmin/main.test.ts similarity index 100% rename from registry/phoenix/pgadmin/main.test.ts rename to registry/coder/modules/pgadmin/main.test.ts diff --git a/registry/phoenix/pgadmin/main.tf b/registry/coder/modules/pgadmin/main.tf similarity index 100% rename from registry/phoenix/pgadmin/main.tf rename to registry/coder/modules/pgadmin/main.tf diff --git a/registry/phoenix/pgadmin/run.sh b/registry/coder/modules/pgadmin/run.sh similarity index 100% rename from registry/phoenix/pgadmin/run.sh rename to registry/coder/modules/pgadmin/run.sh From 847275205a0136abda6b8a611097c1abcf473b26 Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 13:40:04 -0500 Subject: [PATCH 3/7] Remove --- registry/.DS_Store | Bin 6148 -> 6148 bytes registry/coder/modules/.DS_Store | Bin 10244 -> 10244 bytes registry/coder/modules/pgadmin/README.md | 23 ----- registry/coder/modules/pgadmin/main.test.ts | 10 -- registry/coder/modules/pgadmin/main.tf | 108 -------------------- registry/coder/modules/pgadmin/run.sh | 76 -------------- 6 files changed, 217 deletions(-) delete mode 100644 registry/coder/modules/pgadmin/README.md delete mode 100644 registry/coder/modules/pgadmin/main.test.ts delete mode 100644 registry/coder/modules/pgadmin/main.tf delete mode 100644 registry/coder/modules/pgadmin/run.sh diff --git a/registry/.DS_Store b/registry/.DS_Store index 321b8385d76c8a0b420f6257635ebed974b1903f..07f40eef15e84efd4b3843ecec2d0479eb678746 100644 GIT binary patch delta 68 zcmZoMXfc=|#>B)qu~2NHo+2ar#(>?7jO?3vSQ;58+q0k8tiZ8}c{4i)KL=3FWB!ku~2NHo+2aP#(>?7i&&T#`8M+~H8R?=GZZjnFyu3&GUPF2GE{ix zTPvOFbFU(Fhv1r?f+l^WHB(Hsh;e@bi5u-EGOMCI5|JJ0IVKDpsC2scX5H* z!SUqrDHRcs$S)5rNh~QX zc1kRY2Ju4j^K+75?8Kz7`pnewcmWaT{JfIH%)Hbhu#U`>RG^xe@XWlF{Bo!K(!7*n zu;yTh1P3PvXS{$!b+w_1j)I|)QLTA*!rz9TcCPlbe^{1$HM&Li1Nya8X`PeqK6IhH>*NvES^Q*%e-l_>dCE5mEq+cA`lD diff --git a/registry/coder/modules/pgadmin/README.md b/registry/coder/modules/pgadmin/README.md deleted file mode 100644 index 397e11f2..00000000 --- a/registry/coder/modules/pgadmin/README.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -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 -} -``` diff --git a/registry/coder/modules/pgadmin/main.test.ts b/registry/coder/modules/pgadmin/main.test.ts deleted file mode 100644 index 90047100..00000000 --- a/registry/coder/modules/pgadmin/main.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -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", - }); -}); \ No newline at end of file diff --git a/registry/coder/modules/pgadmin/main.tf b/registry/coder/modules/pgadmin/main.tf deleted file mode 100644 index cab0c096..00000000 --- a/registry/coder/modules/pgadmin/main.tf +++ /dev/null @@ -1,108 +0,0 @@ -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)) - ) - ]) -} \ No newline at end of file diff --git a/registry/coder/modules/pgadmin/run.sh b/registry/coder/modules/pgadmin/run.sh deleted file mode 100644 index ebf2a507..00000000 --- a/registry/coder/modules/pgadmin/run.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/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 \ No newline at end of file From e73fd5b966ad265624dff59f73cc4dfb418c6271 Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 14:09:57 -0500 Subject: [PATCH 4/7] Init - Linode --- registry/coder/templates/linode/README.md | 48 ++++++++ registry/coder/templates/linode/main.tf | 135 ++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 registry/coder/templates/linode/README.md create mode 100644 registry/coder/templates/linode/main.tf diff --git a/registry/coder/templates/linode/README.md b/registry/coder/templates/linode/README.md new file mode 100644 index 00000000..74ca8bbb --- /dev/null +++ b/registry/coder/templates/linode/README.md @@ -0,0 +1,48 @@ +--- +display_name: Docker Containers +description: Provision Docker containers as Coder workspaces +icon: ../../../../.icons/docker.svg +maintainer_github: coder +verified: true +tags: [docker, container] +--- + +# Remote Development on Docker Containers + +Provision Docker containers as [Coder workspaces](https://coder.com/docs/workspaces) with this example template. + + + +## Prerequisites + +### Infrastructure + +The VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group: + +```sh +# Add coder user to Docker group +sudo adduser coder docker + +# Restart Coder server +sudo systemctl restart coder + +# Test Docker +sudo -u coder docker ps +``` + +## Architecture + +This template provisions the following resources: + +- Docker image (built by Docker socket and kept locally) +- Docker container pod (ephemeral) +- Docker volume (persistent on `/home/coder`) + +This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the container image. Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles. + +> **Note** +> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. + +### Editing the image + +Edit the `Dockerfile` and run `coder templates push` to update workspaces. diff --git a/registry/coder/templates/linode/main.tf b/registry/coder/templates/linode/main.tf new file mode 100644 index 00000000..4bf75912 --- /dev/null +++ b/registry/coder/templates/linode/main.tf @@ -0,0 +1,135 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + linode = { + source = "linode/linode" + } + } +} + +locals { + username = data.coder_workspace_owner.me.name +} + +variable "linode_token" {} +variable "size" {} + +provider "linode" { + token = var.linode_token +} + +data "coder_provisioner" "me" {} +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +resource "linode_instance" "main" { + region = data.coder_parameter.region.value + label = "coder-${data.coder_workspace.me.id}-home" +} + +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = "linux" + startup_script = <<-EOT + set -e + + # Prepare user home with default files on first start. + if [ ! -f ~/.init_done ]; then + cp -rT /etc/skel ~ + touch ~/.init_done + fi + + # Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here + EOT + + # These environment variables allow you to make Git commits right away after creating a + # workspace. Note that they take precedence over configuration defined in ~/.gitconfig! + # You can remove this block if you'd prefer to configure Git manually or using + # dotfiles. (see docs/dotfiles.md) + env = { + GIT_AUTHOR_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_AUTHOR_EMAIL = "${data.coder_workspace_owner.me.email}" + GIT_COMMITTER_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_COMMITTER_EMAIL = "${data.coder_workspace_owner.me.email}" + } + + # The following metadata blocks are optional. They are used to display + # information about your workspace in the dashboard. You can remove them + # if you don't want to display any information. + # For basic resources, you can use the `coder stat` command. + # If you need more control, you can write your own script. + metadata { + display_name = "CPU Usage" + key = "0_cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "1_ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Home Disk" + key = "3_home_disk" + script = "coder stat disk --path $${HOME}" + interval = 60 + timeout = 1 + } + + metadata { + display_name = "CPU Usage (Host)" + key = "4_cpu_usage_host" + script = "coder stat cpu --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Memory Usage (Host)" + key = "5_mem_usage_host" + script = "coder stat mem --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Load Average (Host)" + key = "6_load_host" + # get load avg scaled by number of cores + script = < Date: Wed, 16 Jul 2025 14:19:56 -0500 Subject: [PATCH 5/7] Fix - Linode --- registry/coder/templates/linode/main.tf | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/registry/coder/templates/linode/main.tf b/registry/coder/templates/linode/main.tf index 4bf75912..c72b7729 100644 --- a/registry/coder/templates/linode/main.tf +++ b/registry/coder/templates/linode/main.tf @@ -14,7 +14,11 @@ locals { } variable "linode_token" {} -variable "size" {} +variable "storage_size" { + type = number + description = "The Size of the VM HDD" + default = 25 +} provider "linode" { token = var.linode_token @@ -26,7 +30,14 @@ data "coder_workspace_owner" "me" {} resource "linode_instance" "main" { region = data.coder_parameter.region.value - label = "coder-${data.coder_workspace.me.id}-home" + label = "linode-${data.coder_workspace.me.id}-home" +} + +resource "linode_instance_disk" "boot" { + label = "boot" + linode_id = linode_instance.my-instance.id + size = var.storage_size + filesystem = "ext4" } resource "coder_agent" "main" { From b43a7eb68a6cf8e4ffa7e8473cf36a81af1a3870 Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 14:56:24 -0500 Subject: [PATCH 6/7] functioning (barely) --- registry/coder/.DS_Store | Bin 6148 -> 8196 bytes registry/coder/templates/linode/main.tf | 32 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/registry/coder/.DS_Store b/registry/coder/.DS_Store index 9412da7e79e7ae1e8163a9aea9fc87c7a906eeab..2cc53c66e6b6aaa51e24eea857be6fce504485a9 100644 GIT binary patch literal 8196 zcmeHMU2GIp6u#fI&>6bW0a_{8kxdH`uq|z&w(^r~|C9o4vD?xgewN*xkq*qxl%3hO zSTK!=FCZG9H2y`N{EL{VDDlMyMbSq^6O8czqfuWp!55W8&)hp(poIq#Lm(y$FZ5PIN$=>h-!5T)wVSU{%)<*yEE_!WR? zAr13FeYyv5n`l5|0i6<*o6?-(_JF_?!4(6-oa9koooFneQ-TU}24T(+tc>7>0=_!g zMY%ddOwh0mJrH_ewg>#XdlAbphv_VL_5IyRk;D(C7OJ)X@It*=+Np7OG-Yw^GpSL_ zbiKN|Zy*&E&Y4>z7sokrFrnovtzI%a3uv3Fz*Up|m_tX#%+6Y9cr(n{y7q-V5PR@{8lps^A+ zopmg0hvS<5G(&@)G2!{LS)##V*U5Tqe6m54<`-IO&NX@sn$#RK+G%RHboy|j1Lf3$ zCCgW=s%dE26zk~hdiZ>ax^U6rNLgf<{AqjUBc_oZO1f#o)=hhV|G24pBLicmYo;ut z&rW6xWg)7S^Cjg=m)%{VX+q(OL0)w*mog9KOz*H-CChw`s8$)-t<#>m9Nk|fo#kGD}{ZdY-s%ejz1b%v~ zA_nBDShsj4Rk1ZeC;zaxqpM$UdYOH~^v+Zmj%d$y!f<4DhviI0o_9^?Ceb0Vj zm)M^G=AsDmP>fP6!wOWR5lv{u187ALcAyt=?8XR89Ds`n9L6M$;0YYVah$+Ycor|= zWxRrucmwa?U7W`I_z36lIljPGxQHL{BYwhf_zQpIvNT6pB9%)^rAnz$W>5;4UoS zAy!&;*OKVUHEY*5Z*G}}qQGt*u2%;ENB%YO!jaFBF$1;dc`QcmS)LERE8!@@v!6o7 zn2`O*Rf_`csuePYj5;S^SFI*?n>tsp6*aXog{LZUHd4{BPN5)F3j(&LiC73GvT>6_ z;iwh{>^(7J8D}ag+B;~PbE^DbVf_NT$bM$Ov&)3_1z3!7+>1Iwcq_J`n`1nVe(Xg8 z`;dZ;3~V?!L})*Pqj(Hcc$~2QB%%FjJcH-)0$wD!38+&bo-!QnJ;>C-UhO`!;D^ zonjT{(TDU58>NJtz#ZcO6t>6P zTWP!bd_8mL{#`ptbstr~_QuS?O0i6<*MyTBK4*|F8 R2X~nN!~D-9<@U_~{{qMY#)1F< delta 116 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50$jG`eU^gQp>t-GSF~-U9;wv^b y*s?5U=im@z2C4!A0d64S3evE#@H_Klei=uQi42Sk3@jj;31TEzY;!!%9A*GZtPv{! diff --git a/registry/coder/templates/linode/main.tf b/registry/coder/templates/linode/main.tf index c72b7729..639d8b99 100644 --- a/registry/coder/templates/linode/main.tf +++ b/registry/coder/templates/linode/main.tf @@ -19,6 +19,11 @@ variable "storage_size" { description = "The Size of the VM HDD" default = 25 } +variable "region" { + type = string + description = "Where do you want your linode instance to be hosted?" + default = "us-central" +} provider "linode" { token = var.linode_token @@ -35,11 +40,36 @@ resource "linode_instance" "main" { resource "linode_instance_disk" "boot" { label = "boot" - linode_id = linode_instance.my-instance.id + linode_id = linode_instance.main.id size = var.storage_size filesystem = "ext4" } +data "coder_parameter" "region" { + name = "region" + display_name = "Region" + description = "This is the region where your workspace will be created." + type = "string" + default = "us-central" + mutable = false + option { + name = "Dallas, TX" + value = "us-central" + } + option { + name = "Fremont, CA" + value = "us-west" + } + option { + name = "Atlanta, GA" + value = "us-southeast" + } + option { + name = "Newark, NJ" + value= "us-east" + } +} + resource "coder_agent" "main" { arch = data.coder_provisioner.me.arch os = "linux" From 259535946b15b65eb50b84b992fd664306f4e6eb Mon Sep 17 00:00:00 2001 From: Phoenix Shepherd Date: Wed, 16 Jul 2025 15:42:28 -0500 Subject: [PATCH 7/7] Frustrated w/converting user-entered storage size to string for terraform, seeking assistance. --- registry/coder/templates/linode/README.md | 42 ++++------------------- registry/coder/templates/linode/main.tf | 29 ++++++++++++---- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/registry/coder/templates/linode/README.md b/registry/coder/templates/linode/README.md index 74ca8bbb..b805b7bf 100644 --- a/registry/coder/templates/linode/README.md +++ b/registry/coder/templates/linode/README.md @@ -1,48 +1,18 @@ --- -display_name: Docker Containers -description: Provision Docker containers as Coder workspaces +display_name: Linode +description: Provision Linode instaces as Coder workspaces icon: ../../../../.icons/docker.svg maintainer_github: coder verified: true -tags: [docker, container] +tags: [linode, vps] --- -# Remote Development on Docker Containers +# Remote Development on Linode compute -Provision Docker containers as [Coder workspaces](https://coder.com/docs/workspaces) with this example template. +Provision Linode instances as [Coder workspaces](https://coder.com/docs/workspaces) with this example template. ## Prerequisites -### Infrastructure - -The VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group: - -```sh -# Add coder user to Docker group -sudo adduser coder docker - -# Restart Coder server -sudo systemctl restart coder - -# Test Docker -sudo -u coder docker ps -``` - -## Architecture - -This template provisions the following resources: - -- Docker image (built by Docker socket and kept locally) -- Docker container pod (ephemeral) -- Docker volume (persistent on `/home/coder`) - -This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the container image. Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles. - -> **Note** -> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. - -### Editing the image - -Edit the `Dockerfile` and run `coder templates push` to update workspaces. +Linode Token - Grab this from their website after logging in. \ No newline at end of file diff --git a/registry/coder/templates/linode/main.tf b/registry/coder/templates/linode/main.tf index 639d8b99..a0231665 100644 --- a/registry/coder/templates/linode/main.tf +++ b/registry/coder/templates/linode/main.tf @@ -13,12 +13,12 @@ locals { username = data.coder_workspace_owner.me.name } -variable "linode_token" {} -variable "storage_size" { - type = number - description = "The Size of the VM HDD" - default = 25 +variable "linode_token" { + type = string + description = "Your Linode Token" + default = "null" } + variable "region" { type = string description = "Where do you want your linode instance to be hosted?" @@ -36,12 +36,14 @@ data "coder_workspace_owner" "me" {} resource "linode_instance" "main" { region = data.coder_parameter.region.value label = "linode-${data.coder_workspace.me.id}-home" + type = data.coder_parameter.type.value } resource "linode_instance_disk" "boot" { label = "boot" linode_id = linode_instance.main.id - size = var.storage_size + size = tostring(data.coder_parameter.storage_size) + # this is making me aggrovated, I can't figure out how to convert this value gathered later on (in create workspace vs. import template) to a string so TF will accept it. filesystem = "ext4" } @@ -70,6 +72,21 @@ data "coder_parameter" "region" { } } +data "coder_parameter" "type" { + name = "type" + display_name = "Instance Type" + type = "string" + default = "g6-standard-2" + # Linode documentation does not specify a list of types, so I'm not sure what to put here. I'm not currently a Linode customer. +} + +data "coder_parameter" "storage_size" { + name = "storage_size" + display_name = "Storage Size" + type = "number" + default = "25" +} + resource "coder_agent" "main" { arch = data.coder_provisioner.me.arch os = "linux"