Plugin Architecture
Stratos uses a plugin system to extend both the backend (Jetstream) and frontend (Angular) with modular, independently loadable capabilities. Plugins add endpoint types, HTTP routes, middleware, and frontend UI packages to the console.
Overview
Backend Plugins
Plugin Interface
Every backend plugin implements api.StratosPlugin
(src/jetstream/api/plugin.go):
type StratosPlugin interface {
Init() error
GetMiddlewarePlugin() (MiddlewarePlugin, error)
GetEndpointPlugin() (EndpointPlugin, error)
GetRoutePlugin() (RoutePlugin, error)
}
A plugin returns a concrete implementation from one or more of these
methods and nil for the rest. The sub-interfaces are:
| Interface | Purpose | Methods |
|---|---|---|
EndpointPlugin | Defines an endpoint type (CF, K8s, metrics) | GetType, Register, Connect, Validate, Info, UpdateMetadata |
RoutePlugin | Adds HTTP routes to the Echo server | AddAdminGroupRoutes, AddSessionGroupRoutes |
MiddlewarePlugin | Injects request/response middleware | EchoMiddleware, SessionEchoMiddleware |
Two optional interfaces provide additional lifecycle hooks:
| Interface | Purpose |
|---|---|
StratosPluginCleanup | Called on shutdown (Destroy()) |
EndpointNotificationPlugin | Notified when endpoints are added/removed |
A ConfigPlugin interface allows early configuration before plugin
loading via RegisterJetstreamConfigPlugin().
Registration
Plugins register themselves in a Go init() function using blank
imports. The init() function calls api.AddPlugin with the plugin
name, an optional dependency list, and an initializer function:
package cloudfoundry
func init() {
api.AddPlugin("cloudfoundry", nil, Init)
}
func Init(portalProxy api.PortalProxy) (api.StratosPlugin, error) {
return &CloudFoundrySpecification{portalProxy: portalProxy}, nil
}
Plugins that depend on other plugins declare them explicitly:
func init() {
api.AddPlugin("cfapppush", []string{"cloudfoundry"}, Init)
}
The loader in load_plugins.go resolves dependencies recursively.
A plugin with an unmet dependency is skipped with a log warning.
Import Files
Two Go files control which plugins are compiled into the binary:
| File | Purpose | Maintained by |
|---|---|---|
src/jetstream/default_plugins.go | Core plugins always included | Developer (manual) |
src/jetstream/extra_plugins.go | Feature plugins from plugin-config.yaml | Build system (auto-generated) |
src/jetstream/plugin-config.yaml | Extra plugin list (single source of truth) | Developer (manual) |
default_plugins.go — hardcoded imports for plugins that every
deployment needs regardless of which frontend packages are enabled:
import (
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/backup"
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/cloudfoundryhosting"
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/metrics"
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/userfavorites"
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/userinfo"
)
extra_plugins.go — auto-generated by the prebuild step. Do not
edit manually. See Decoupled Builds
for details.
Plugin Loading Order
main() → portalProxy.loadPlugins()
1. yamlgenerated.MakePluginsFromConfig() ← reads plugins.yaml
2. for each name in api.PluginInits:
addPlugin(name)
→ resolve dependencies (recursive)
→ call Init(portalProxy)
→ store in pp.Plugins map
Plugin Catalog
Default Plugins
These are always compiled in via default_plugins.go.
| Plugin | Type | Purpose |
|---|---|---|
| backup | Route | Endpoint and token backup/restore (admin-only) |
| cloudfoundryhosting | Middleware, Config | Stratos-in-CF deployment support — auto-registration, session affinity, CF UAA config |
| metrics | Endpoint, Route | Prometheus endpoint type; correlates metrics with CF and K8s endpoints |
| userfavorites | Route | User favorites/bookmarks persistence in the database |
| userinfo | Route | User profile management — get/update info and password; supports UAA, local, and no-auth modes |
Extra Plugins
These are compiled in via the auto-generated extra_plugins.go based
on frontend package declarations.
| Plugin | Depends On | Frontend Package | Purpose |
|---|---|---|---|
| cloudfoundry | — | cloud-foundry | CF endpoint type, auth, firehose and app stream endpoints |
| cfapppush | cloudfoundry | cloud-foundry | Application deployment/push workflow from the UI |
| cfappssh | cloudfoundry | cloud-foundry | SSH into CF app instances via WebSocket proxy |
| userinvite | cloudfoundry | cloud-foundry | User invitation system with email and UAA client auth |
| autoscaler | cloudfoundry | cf-autoscaler | Autoscaling policies, metrics, and events for CF apps |
| kubernetes | — | kubernetes | K8s endpoint type with multi-auth (GKE, AWS, Azure, OIDC, cert, token) |
| analysis | kubernetes | kubernetes | Cluster analysis and reporting via Popeye (tech preview) |
| monocular | kubernetes | kubernetes | Helm chart repository management and ArtifactHub integration |
Special Plugins
| Plugin | Purpose |
|---|---|
| desktop | Desktop hosting mode — local endpoint/token store overlay; declared by desktop-extensions frontend package |
| yamlgenerated | Generates endpoint type plugins at runtime from plugins.yaml (currently GitHub and GitLab git endpoints) |
Dependency Graph
cloudfoundry
├── cfapppush
├── cfappssh
├── userinvite
└── autoscaler
kubernetes
├── analysis
└── monocular
(no dependencies)
├── backup
├── cloudfoundryhosting
├── metrics
├── userfavorites
├── userinfo
└── desktop
YAML-Generated Plugins
src/jetstream/plugins.yaml defines lightweight endpoint types that
are created at runtime by the yamlgenerated plugin. These do not
require a Go source directory — they are configured entirely via YAML:
- name: git
sub_type: github
auth_type: Token
user_info: /user
user_info_path: login
- name: git
sub_type: gitlab
auth_type: Bearer
user_info: /user
user_info_path: username
Each entry generates a plugin that implements EndpointPlugin and
RoutePlugin with standard connect/validate/info flows. This is the
preferred way to add simple token-authenticated endpoint types without
writing Go code.
Frontend Integration
Frontend Package Metadata
Frontend packages declare their Angular integration metadata in
package.json under the stratos key:
{
"name": "@stratosui/cloud-foundry",
"stratos": {
"module": "CloudFoundryPackageModule",
"routingModule": "CloudFoundryRoutingModule",
"theming": "sass/_all-theme#apply-theme-stratos-cloud-foundry"
}
}
The stratos metadata fields are:
| Field | Purpose |
|---|---|
module | Angular standalone module class name |
routingModule | Routing module for lazy-loaded routes |
theming | SASS theme file and mixin to apply |
assets | Asset configuration |
Backend plugin declarations are managed centrally in
src/jetstream/plugin-config.yaml, not in individual package.json
files.
Plugin Configuration
The list of extra plugins is defined in
src/jetstream/plugin-config.yaml, which serves as the single source
of truth for both the backend and frontend builds.
Backend Build (go generate)
The backend uses a standard go generate directive to produce
extra_plugins.go from plugin-config.yaml:
cd src/jetstream && go generate ./...
└── cmd/gen-plugins/main.go
→ reads plugin-config.yaml
→ validates plugin dirs exist
→ writes extra_plugins.go
The Makefile's build-backend target runs go generate automatically
before go build.
Frontend Build (prebuild)
The frontend prebuild pipeline also reads plugin-config.yaml to
generate the same extra_plugins.go:
npm prebuild
└── build-orchestrator.js
└── backend.ts → reads plugin-config.yaml
→ validates plugin dirs exist
→ writes extra_plugins.go
npm build (ng build)
└── Angular CLI compiles frontend
Decoupled Builds
Either build can run independently. The backend only needs Go tooling
(go generate ./...). The frontend prebuild reads the same YAML file
with Node.js. Both produce identical extra_plugins.go output.
The stratos.yaml backend key is still supported as an override
mechanism for custom builds.
Creating a New Plugin
Backend Plugin
# 1. Create plugin directory and main file
mkdir -p src/jetstream/plugins/myplugin
// src/jetstream/plugins/myplugin/main.go
package myplugin
import (
"github.com/cloudfoundry/stratos/src/jetstream/api"
"github.com/labstack/echo/v4"
)
func init() {
api.AddPlugin("myplugin", nil, Init)
}
type MyPlugin struct {
portalProxy api.PortalProxy
}
func Init(portalProxy api.PortalProxy) (api.StratosPlugin, error) {
return &MyPlugin{portalProxy: portalProxy}, nil
}
func (p *MyPlugin) Init() error { return nil }
func (p *MyPlugin) GetMiddlewarePlugin() (api.MiddlewarePlugin, error) {
return nil, errors.New("not implemented")
}
func (p *MyPlugin) GetEndpointPlugin() (api.EndpointPlugin, error) {
return nil, errors.New("not implemented")
}
func (p *MyPlugin) GetRoutePlugin() (api.RoutePlugin, error) {
return p, nil
}
func (p *MyPlugin) AddAdminGroupRoutes(echoGroup *echo.Group) {
// Admin-only routes
}
func (p *MyPlugin) AddSessionGroupRoutes(echoGroup *echo.Group) {
echoGroup.GET("/myplugin/data", p.getData)
}
func (p *MyPlugin) getData(c echo.Context) error {
return c.JSON(200, map[string]string{"status": "ok"})
}
Enabling an Extra Plugin
Add the plugin name to src/jetstream/plugin-config.yaml:
plugins:
- cloudfoundry
- cfapppush
# ...
- myplugin
Run go generate ./... from src/jetstream/ to regenerate
extra_plugins.go.
Adding a Default Plugin
If the plugin should always be compiled in (regardless of frontend
packages), add its import to default_plugins.go instead:
import (
_ "github.com/cloudfoundry/stratos/src/jetstream/plugins/myplugin"
)
Adding a YAML-Generated Endpoint
For simple token-authenticated endpoints, add an entry to
src/jetstream/plugins.yaml instead of writing Go code:
- name: myservice
sub_type: myvariant
auth_type: Token # Token, Bearer, or HttpBasic
user_info: /api/user # REST endpoint to fetch user info
user_info_path: username # JSON path to extract username
Key Files Reference
| File | Purpose |
|---|---|
src/jetstream/api/plugin.go | Plugin interfaces and registration API |
src/jetstream/load_plugins.go | Plugin loader with dependency resolution |
src/jetstream/default_plugins.go | Hardcoded default plugin imports |
src/jetstream/extra_plugins.go | Auto-generated plugin imports (do not edit) |
src/jetstream/plugin-config.yaml | Extra plugin list (single source of truth) |
src/jetstream/generate.go | go:generate directive for extra_plugins.go |
src/jetstream/cmd/gen-plugins/main.go | Go generator that reads plugin-config.yaml |
src/jetstream/plugins.yaml | YAML config for runtime-generated endpoint types |
src/jetstream/plugins/yamlgenerated/main.go | YAML plugin generator |
src/frontend/packages/devkit/src/backend.ts | Prebuild script that generates extra_plugins.go from plugin-config.yaml |
src/frontend/packages/devkit/src/lib/stratos.config.ts | Config parser that reads stratos/package metadata |
build/build-orchestrator.js | Prebuild pipeline orchestrator |