Skip to main content

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:

InterfacePurposeMethods
EndpointPluginDefines an endpoint type (CF, K8s, metrics)GetType, Register, Connect, Validate, Info, UpdateMetadata
RoutePluginAdds HTTP routes to the Echo serverAddAdminGroupRoutes, AddSessionGroupRoutes
MiddlewarePluginInjects request/response middlewareEchoMiddleware, SessionEchoMiddleware

Two optional interfaces provide additional lifecycle hooks:

InterfacePurpose
StratosPluginCleanupCalled on shutdown (Destroy())
EndpointNotificationPluginNotified 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:

FilePurposeMaintained by
src/jetstream/default_plugins.goCore plugins always includedDeveloper (manual)
src/jetstream/extra_plugins.goFeature plugins from plugin-config.yamlBuild system (auto-generated)
src/jetstream/plugin-config.yamlExtra 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.

PluginTypePurpose
backupRouteEndpoint and token backup/restore (admin-only)
cloudfoundryhostingMiddleware, ConfigStratos-in-CF deployment support — auto-registration, session affinity, CF UAA config
metricsEndpoint, RoutePrometheus endpoint type; correlates metrics with CF and K8s endpoints
userfavoritesRouteUser favorites/bookmarks persistence in the database
userinfoRouteUser 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.

PluginDepends OnFrontend PackagePurpose
cloudfoundrycloud-foundryCF endpoint type, auth, firehose and app stream endpoints
cfapppushcloudfoundrycloud-foundryApplication deployment/push workflow from the UI
cfappsshcloudfoundrycloud-foundrySSH into CF app instances via WebSocket proxy
userinvitecloudfoundrycloud-foundryUser invitation system with email and UAA client auth
autoscalercloudfoundrycf-autoscalerAutoscaling policies, metrics, and events for CF apps
kuberneteskubernetesK8s endpoint type with multi-auth (GKE, AWS, Azure, OIDC, cert, token)
analysiskuberneteskubernetesCluster analysis and reporting via Popeye (tech preview)
monocularkuberneteskubernetesHelm chart repository management and ArtifactHub integration

Special Plugins

PluginPurpose
desktopDesktop hosting mode — local endpoint/token store overlay; declared by desktop-extensions frontend package
yamlgeneratedGenerates 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:

FieldPurpose
moduleAngular standalone module class name
routingModuleRouting module for lazy-loaded routes
themingSASS theme file and mixin to apply
assetsAsset 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

FilePurpose
src/jetstream/api/plugin.goPlugin interfaces and registration API
src/jetstream/load_plugins.goPlugin loader with dependency resolution
src/jetstream/default_plugins.goHardcoded default plugin imports
src/jetstream/extra_plugins.goAuto-generated plugin imports (do not edit)
src/jetstream/plugin-config.yamlExtra plugin list (single source of truth)
src/jetstream/generate.gogo:generate directive for extra_plugins.go
src/jetstream/cmd/gen-plugins/main.goGo generator that reads plugin-config.yaml
src/jetstream/plugins.yamlYAML config for runtime-generated endpoint types
src/jetstream/plugins/yamlgenerated/main.goYAML plugin generator
src/frontend/packages/devkit/src/backend.tsPrebuild script that generates extra_plugins.go from plugin-config.yaml
src/frontend/packages/devkit/src/lib/stratos.config.tsConfig parser that reads stratos/package metadata
build/build-orchestrator.jsPrebuild pipeline orchestrator