posit-dev / posit-dev/team-operator
Add Support for Posit Workbench Session Hooks
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 10
- Forks
- 1
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 4
Description
Problem Statement
Posit Workbench supports Session Hooks - executable shell scripts that run at specific points in a session's lifecycle (start/stop). Currently, PTD does not support configuring or deploying session hooks. This feature is needed to allow customers to inject custom behavior into their Workbench sessions.
Background
Session Hooks require:
- Shell scripts present in the filesystem accessible by both Workbench server and session pods
- Configuration in
rserver.conf:session-hooks-enabled=1session-hooks-path=/path/to/scriptssession-hooks-start=script1.sh,script2.sh(comma-separated list)session-hooks-stop=script1.sh,script2.sh(comma-separated list)
Proposed Solution
1. Directory Structure
Admins will create an optional session_hooks/ directory at the workload level:
infra/__work__/<customer>-<env>/
├── session_hooks/ # New directory (optional)
│ ├── start.sh
│ ├── stop.sh
│ ├── custom-start.sh
│ └── cleanup.sh
├── site_main/
│ └── site.yaml
└── site_alt/
└── site.yaml
All sites in a workload share the same pool of available scripts, but each site configures which scripts to execute.
2. Site Configuration
In each site.yaml, admins configure session hooks:
workbench:
sessionHooks:
enabled: true
path: /opt/rstudio/session-hooks # Optional, defaults to /opt/rstudio/session-hooks
start:
- start.sh
- custom-start.sh
stop:
- stop.sh
- cleanup.sh
3. Implementation Details
A. Python/Pulumi Changes (clusters step)
Create new module python-pulumi/src/ptd/pulumi_resources/session_hooks.py following the pattern from custom_k8s_resources.py:
- Check if
session_hooks/directory exists at workload level - For each site that has
workbench.sessionHooks.enabled=true:- Validate that all scripts referenced in
startandstoparrays exist in the directory - Create a Kubernetes ConfigMap named
<site-name>-session-hooksin the site's namespace - ConfigMap data contains all scripts from
session_hooks/directory - Apply ConfigMap before site resources are created
- Validate that all scripts referenced in
Example ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: site-main-session-hooks
namespace: site-main
labels:
posit.team/managed-by: ptd-clusters
data:
start.sh: |
#!/bin/bash
echo "Session starting..."
stop.sh: |
#!/bin/bash
echo "Session stopping..."
B. Site CRD Changes (team-operator/api/core/v1beta1/site_types.go)
Add new struct for session hooks configuration:
type SessionHooksConfig struct {
Enabled bool `json:"enabled,omitempty"`
// +kubebuilder:default="/opt/rstudio/session-hooks"
Path string `json:"path,omitempty"`
Start []string `json:"start,omitempty"`
Stop []string `json:"stop,omitempty"`
}
Add to InternalWorkbenchSpec:
type InternalWorkbenchSpec struct {
// ... existing fields ...
// SessionHooks configures session lifecycle hooks
SessionHooks *SessionHooksConfig `json:"sessionHooks,omitempty"`
}
C. Workbench Config Changes (team-operator/api/core/v1beta1/workbench_config.go)
Add fields to WorkbenchRServerConfig struct:
type WorkbenchRServerConfig struct {
// ... existing fields ...
SessionHooksEnabled int `json:"session-hooks-enabled,omitempty"`
SessionHooksPath string `json:"session-hooks-path,omitempty"`
SessionHooksStart []string `json:"session-hooks-start,omitempty"`
SessionHooksStop []string `json:"session-hooks-stop,omitempty"`
}
The existing GenerateConfigMap() method will automatically convert these to proper rserver.conf format (comma-separated lists for array fields).
D. Workbench Controller Changes
In the Workbench controller where pod specs are constructed:
-
Populate RServer Config: When building
WorkbenchRServerConfig, check ifSite.Spec.Workbench.SessionHooksis configured:if site.Spec.Workbench.SessionHooks != nil && site.Spec.Workbench.SessionHooks.Enabled { rserverConfig.SessionHooksEnabled = 1 rserverConfig.SessionHooksPath = site.Spec.Workbench.SessionHooks.Path rserverConfig.SessionHooksStart = site.Spec.Workbench.SessionHooks.Start rserverConfig.SessionHooksStop = site.Spec.Workbench.SessionHooks.Stop } -
Mount ConfigMap in Workbench Server Pods:
- Add volume referencing
<site-name>-session-hooksConfigMap - Mount at the configured path (default:
/opt/rstudio/session-hooks) - Use
defaultMode: 0755to make scripts executable
- Add volume referencing
-
Mount ConfigMap in Session Pods:
- Add the same volume and volumeMount to session pod templates
- Ensure sessions can execute the scripts at the same path
4. Example End-to-End Flow
- Admin creates
infra/__work__/pew01-production/session_hooks/start.shwith custom logic - Admin configures in
site_main/site.yaml:workbench: sessionHooks: enabled: true start: [start.sh] - During
ptd ensure <workload-name> --only-steps clustersdeployment:- Pulumi validates
start.shexists - Creates ConfigMap
site-main-session-hookswith script content
- Pulumi validates
- Team Operator sees
SessionHooksconfig in Site CRD - Workbench controller:
- Generates
rserver.confwithsession-hooks-enabled=1,session-hooks-path=/opt/rstudio/session-hooks,session-hooks-start=start.sh - Mounts ConfigMap in Workbench server pods at
/opt/rstudio/session-hooks/ - Mounts ConfigMap in session pod templates at same path
- Generates
- When users start sessions,
start.shexecutes automatically
5. Validation & Error Handling
- Pulumi validation: Fail deployment if referenced scripts don't exist in
session_hooks/directory - ConfigMap check: Team Operator should log warning (but not fail) if ConfigMap doesn't exist when
sessionHooks.enabled=true - Empty configuration: If
sessionHooksis not specified orenabled=false, skip all session hooks logic
6. Testing Plan
- Unit tests: Test config generation in
workbench_config_test.go - Integration test: Deploy to test cluster (e.g., ganso01) with:
- Simple
start.shthat writes to/tmp/session-started - Simple
stop.shthat writes to/tmp/session-stopped - Verify files appear when starting/stopping sessions
- Simple
- Validation test: Ensure Pulumi fails when referencing non-existent scripts
7. Documentation Updates
- Add
infra/SESSION_HOOKS.mddocumenting the feature (followingCUSTOM_K8S_RESOURCES.mdpattern) - Update site.yaml schema documentation
Migrated from rstudio/ptd#2549
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading python-pulumi/src/ptd/pulumi_resources/custom_k8s_resources.py and the API definitions in team-operator/api/core/v1beta1/site_types.go and workbench_config.go. Run the existing workbench_config_test.go before tracing the Workbench controller pod construction. Done means validated ConfigMaps, CRD and rserver.conf support, mounts in both pod types, tests, and the requested documentation are covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes, python, shell
- Domain
- devops, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100