Skip to main content

Check out Port for yourself ➜ 

Backstage

Loading version...

Port's Backstage integration allows you to model Backstage resources in your software catalog and ingest data into them.

Prerequisites

Create a Backstage token

Port will authenticate to Backstage via static tokens. Configure a token for Port using the following Backstage configuration:

backend:
auth:
externalAccess:
- type: static
options:
token: YOUR-TOKEN
subject: port-ocean-access

Replace YOUR-TOKEN with your Backstage token. To create a token, Backstage recommends to use the following command:

node -p 'require("crypto").randomBytes(24).toString("base64")'

Setup

Choose one of the following installation methods: Not sure which method is right for your use case? Check the available installation methods.

Configuration

Port integrations use a YAML mapping block to ingest data from the third-party api into Port.

The mapping makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from the integration API.

Default mapping configuration

This is the default mapping configuration for this integration:

Default mapping configuration (Click to expand)
resources:
- kind: component
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"component"'
properties:
type: .spec.type
lifecycle: .spec.lifecycle
language: .spec.language
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
subcomponentOf: .relations[] | select(.type == "subcomponentOf" and (.targetRef | startswith("component:"))) | .targetRef
providesApis: .relations[] | select(.type == "providesApi" and (.targetRef | startswith("api:"))) | .targetRef
consumesApis: .relations[] | select(.type == "consumesApi" and (.targetRef | startswith("api:"))) | .targetRef
dependsOnComponent: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("component:"))) | .targetRef
dependsOnResource: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("resource:"))) | .targetRef
- kind: API
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"api"'
properties:
type: .spec.type
lifecycle: .spec.lifecycle
definition: .spec.definition | tostring
definitionOpenAPI: if .spec.type == "open-api" then .spec.definition else null end
definitionAsyncAPI: if .spec.type == "async-api" then .spec.definition else null end
definitionGRPC: if .spec.type == "grpc" then .spec.definition else null end
definitionGraphQL: if .spec.type == "graphql" then .spec.definition else null end
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
- kind: group
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"group"'
properties:
description: .metadata.description
type: .metadata.type
email: .metadata.email
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
parent: .relations[] | select(.type == "childOf" and (.targetRef | startswith("group:"))) | .targetRef
members: .relations[] | select(.type == "hasMember" and (.targetRef | startswith("user:"))) | .targetRef
- kind: user
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"user"'
properties:
email: .metadata.email
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
- kind: resource
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"resource"'
properties:
type: .spec.type
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
dependsOnResource: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("resource:"))) | .targetRef
dependsOnComponent: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("component:"))) | .targetRef
- kind: system
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"system"'
properties:
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
domain: .relations[] | select(.type == "partOf" and (.targetRef | startswith("domain:"))) | .targetRef
- kind: domain
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"domain"'
properties:
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef

Monitoring and sync status

To learn more about how to monitor and check the sync status of your integration, see the relevant documentation.

Mapping & examples per resource

To view and test the integration's mapping against examples of the third-party API responses, use the jq playground in your data sources page. Find the integration in the list of data sources and click on it to open the playground.

Additional examples of blueprints and the relevant integration configurations:

Limitations

Currently, the integration does not support custom entity kinds.