Humanitec Platform Orchestratorr logo

Backstage Humanitec Platform Orchestrator Plugin

Created by Humanitec

Humanitec Platform Orchestrator is the backend of an Internal Developer Platform. It standardizes how apps get config and infrastructure across environments. It keeps a live view of resources and exposes APIs so your portal tooling can show the right context. It is not a portal or a CI system. It complements tools like Backstage by handling orchestration behind the scenes.

This plugin brings Humanitec data into your Backstage catalog. On each service page you can see environments, workloads, and resources tied to a Humanitec app. A small backend in your Backstage instance proxies requests to the Humanitec API. There is a scaffolder module that adds actions to create Humanitec apps or validate inputs during templates. The goal is simple. Give engineers the status and context they need without leaving Backstage.Common use cases include showing what runs where across dev, staging, and production. Surfacing linked resources such as databases or ingress. Starting new services from templates that are wired to your standards in Humanitec. This setup pairs a familiar portal with a consistent platform backend. It reduces context switching and helps teams follow your golden paths at scale.

Installation Instructions

These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.

Install the frontend package

Copy
yarn workspace app add @humanitec/backstage-plugin

Add the card to the entity page

Edit packages/app/src/components/catalog/EntityPage.tsx

Copy
import React from 'react';
import { Grid } from '@material-ui/core';
import { EntitySwitch } from '@backstage/plugin-catalog';
import { HumanitecCardComponent } from '@humanitec/backstage-plugin';

export const EntityPage = () => {
  return (
    <Grid container>
      <Grid item md={6}>
        <HumanitecCardComponent />
      </Grid>
    </Grid>
  );
};

Only show the card when the entity has Humanitec annotations

Edit packages/app/src/components/catalog/EntityPage.tsx

Copy
import React from 'react';
import { Grid } from '@material-ui/core';
import { EntitySwitch } from '@backstage/plugin-catalog';
import { HumanitecCardComponent, hasHumanitecAnnotations } from '@humanitec/backstage-plugin';

export const EntityPage = () => {
  return (
    <Grid container>
      <EntitySwitch>
        <EntitySwitch.Case if={hasHumanitecAnnotations}>
          <Grid item md={6}>
            <HumanitecCardComponent />
          </Grid>
        </EntitySwitch.Case>
      </EntitySwitch>
    </Grid>
  );
};

Add the scaffolder field extension to the frontend

This validates a Humanitec app id in templates.

Edit packages/app/src/App.tsx

Copy
import React from 'react';
import { FlatRoutes } from '@backstage/core-app-api';
import { Route } from 'react-router';
import { ScaffolderPage, ScaffolderFieldExtensions } from '@backstage/plugin-scaffolder';
import { ValidateHumanitecAppIDFieldExtension } from '@humanitec/backstage-plugin';

export const AppRoutes = () => (
  <FlatRoutes>
    <Route
      path="/create"
      element={
        <ScaffolderPage>
          <ScaffolderFieldExtensions>
            <ValidateHumanitecAppIDFieldExtension />
          </ScaffolderFieldExtensions>
        </ScaffolderPage>
      }
    />
  </FlatRoutes>
);

Configure the app

Edit app-config.yaml

Copy
humanitec:
  orgId: my-humanitec-organization
  token: ${HUMANITEC_TOKEN}

Provide HUMANITEC_TOKEN without the word Bearer.

Example runtime

Copy
HUMANITEC_TOKEN=your_token_value yarn dev

Add entity annotations so the card can load data

Create a catalog file or update an existing one

Copy
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: name-of-application-workload
  description: Humanitec Workload Environments
  annotations:
    humanitec.com/orgId: my-humanitec-organization
    humanitec.com/appId: my-humanitec-application
spec:
  type: service
  owner: [email protected]
  lifecycle: experimental

Install the backend package new backend system

Copy
yarn workspace backend add @humanitec/backstage-plugin-backend

Edit packages/backend/src/index.ts

Copy
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

// Humanitec backend plugin
backend.add(import('@humanitec/backstage-plugin-backend'));

backend.start();

Install the scaffolder backend module new backend system

Copy
yarn workspace backend add @humanitec/backstage-plugin-scaffolder-backend-module

Edit packages/backend/src/index.ts

Copy
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

// Humanitec backend plugin
backend.add(import('@humanitec/backstage-plugin-backend'));

// Humanitec scaffolder actions
backend.add(import('@humanitec/backstage-plugin-scaffolder-backend-module'));

backend.start();

Use the scaffolder actions in a template

Add steps to a template yaml

Copy
steps:
  - name: Create Humanitec App
    id: humanitec-create-app
    action: humanitec:create-app
    input:
      setupFile: humanitec-apps.yaml
      appId: ${{ parameters.componentName }}

  - name: Fetch configured humanitec.orgId
    id: humanitec-environment
    action: humanitec:get-environment

The setupFile can be omitted to use the default humanitec-app.yaml. The file describes the initial app, environments, modules, and automations.

Example humanitec app file

Copy
---
id: ${{values.componentName | dump}}
name: ${{values.componentName | dump}}

environments:
  development:
    metadata:
      env_id: development
      name: Initial deployment

    modules:
      ${{values.componentName | dump}}:
        externals:
          http:
            type: dns
        profile: humanitec/default-module
        spec:
          containers:
            ${{values.componentName | dump}}:
              id: ${{values.componentName}}
              image: ${{values.registryUrl}}/${{values.componentName}}:dummy
              resources:
                limits:
                  cpu: 0.25
                  memory: 256Mi
                requests:
                  cpu: 0.025
                  memory: 64Mi
              variables: {}
              volume_mounts: {}
              files: {}
          ingress:
            rules:
              externals.http:
                http:
                  "/":
                    port: 9898
                    type: prefix

automations:
  development:
    - active: true
      exclude_images_filter: false
      images_filter: []
      type: update
      update_to: branch

Install the backend package legacy backend system

If your backend uses the legacy system, add the package

Copy
yarn workspace backend add @humanitec/backstage-plugin-backend

Create packages/backend/src/plugins/humanitec.ts

Copy
import { Router } from 'express';
import { PluginEnvironment } from '../types';
import { createRouter } from '@humanitec/backstage-plugin-backend';

export default async function createPlugin(env: PluginEnvironment): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
  });
}

Wire it in packages/backend/src/index.ts

Copy
import { createServiceBuilder } from '@backstage/backend-common';
import { loadBackendConfig } from '@backstage/backend-common';
import { createEnv, useHotMemoize } from './createEnv';
import humanitec from './plugins/humanitec';

async function main() {
  const config = await loadBackendConfig();
  const env = createEnv('humanitec', config);

  const apiRouter = await humanitec(env);

  const service = createServiceBuilder(module)
    .setPort(7007)
    .addRouter('/api/humanitec', apiRouter);

  await service.start();
}

main().catch(err => {
  process.exit(1);
});

Install the scaffolder backend module legacy backend system

Add the package

Copy
yarn workspace backend add @humanitec/backstage-plugin-scaffolder-backend-module

Create packages/backend/src/plugins/humanitecScaffolder.ts

Copy
import { Router } from 'express';
import { PluginEnvironment } from '../types';
import { createRouter } from '@humanitec/backstage-plugin-scaffolder-backend-module';

export default async function createPlugin(env: PluginEnvironment): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
  });
}

Wire it in packages/backend/src/index.ts

Copy
import humanitecScaffolder from './plugins/humanitecScaffolder';

async function main() {
  // previous setup
  const scaffolderRouter = await humanitecScaffolder(env);

  const service = createServiceBuilder(module)
    .setPort(7007)
    .addRouter('/api/humanitec-scaffolder', scaffolderRouter);

  await service.start();
}

Keep HUMANITEC_TOKEN set when you run the app. Configure humanitec orgId and token in app-config.yaml. Add humanitec.com annotations to the entities you want to show.

Things to Know

If the installation instructions were followed correctly, you should see the following changes:

  • Entity page now renders HumanitecCardComponent
  • Scaffolder page now has ValidateHumanitecAppIDFieldExtension
  • Backend exposes Humanitec routes for the frontend
  • Scaffolder backend module adds humanitec actions you can call from templates

Changelog

This changelog is produced from commits made to the Humanitec Platform Orchestratorr plugin since 10 months ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Breaking changes

  • No breaking changes noted

Features

  • Upgrade to Backstage 1.34.0 #75 merged 10 months ago

Security

  • Update tar fs to 2.1.4 to address a security alert #107 merged 4 days ago
  • Pull in fixes for several security alerts #104 merged 2 months ago
  • Update multer and tar fs to resolve security alerts #99 merged 3 months ago
  • Fix remaining security alerts #90 merged 6 months ago
  • Upgrade tar fs to address a security alert #87 merged 6 months ago
  • Bump xml crypto to 6.0.1 to address critical CVEs #86 merged 7 months ago
  • Bump Babel runtime corejs3 to 7.26.10 with a security fix for regex replacement #84 merged 7 months ago
  • Bump Babel runtime to 7.26.10 with the same security fix #85 merged 7 months ago
  • Bump jsonpath plus to 10.3.0 to fix an RCE risk #83 merged 7 months ago
  • Fix elliptic and koa versions to remove vulnerabilities #80 merged 7 months ago
  • Bump jsonpath plus to 10.2.0 with safer eval #76 merged 8 months ago

Dependencies

  • Refresh yarn lock including tmp #105 merged 2 months ago
  • Bump Backstage permission backend plugin to 0.6.0 #92 merged 5 months ago
  • Bump dompurify and esbuild #89 merged 6 months ago
  • Bump axios to 1.8.3 #82 merged 7 months ago

CI

  • Fix yarn release calls in the publish workflow #100 merged 3 months ago

Set up Backstage in minutes with Roadie