Skip to main content

Check out Port for yourselfย 

Set up automatic discovery

As part of the onboarding process, Port allows you to create new services, workloads, environments, users, and teams via the UI.
This involves manually selecting the components related to the new entity.

These are routine actions that most organizations perform on a regular basis, which is why this manual process is not efficient or scalable.

This guide will walk you through automating the process of creating and updating these entities in a way that suits your organization's standards.

Component definitions

Not sure what these entities mean? See their definitions here.

Discovery methodsโ€‹

This page describes two methods you can use to automatically discover and update entities in your catalog:

  1. Define one of your external tools as a "source of truth" for the resources you want to ingest.
  2. Use metadata from your external tools (e.g. labels, naming conventions) to identify and update an entity in Port.

All methods require modifying the mapping configuration of the relevant integration.

How to modify a mapping configuration (click to expand)
  1. Go to the data sources page of your portal.
  2. Under "Exporters", find the relevant integration and click on it.
  3. A window will open, containing the mapping configuration. Use the editor in the bottom-left corner to update the configuration.
  4. Click on the "Save & Resync" button to save the changes and resync the integration.

1. Define a source of truthโ€‹

This approach is useful when you want to create entities of a specific type (e.g. services, environments, teams, users) based on resources from a specific external tool.

Full exampleโ€‹

One example that works for many organizations is to define a Git repository as a source of truth for services, and automatically create a new service in Port for each repository in your Git provider.

To achieve this, we need to update the mapping configuration of the Git integration to include an entry for the service blueprint.
Here is an example using the GitHub integration:

- kind: repository
selector:
query: 'true'
teams: true
port:
entity:
mappings:
identifier: .full_name
title: .name
blueprint: '"githubRepository"'
properties:
readme: file://README.md
url: .html_url
defaultBranch: .default_branch
relations:
githubTeams: '[.teams[].id | tostring]'
- kind: repository
selector:
query: 'true'
port:
entity:
mappings:
identifier: .full_name
title: .full_name
blueprint: '"service"'
relations:
repository: .full_name

The first kind block is the default mapping when installing the GitHub integration. The meaning of this block is:
For every repository in the GitHub organization, create a new githubRepository entity in Port with the specified properties.

The second kind block is the one we need to add. The meaning of this block is:
For every repository in the GitHub organization, create a new service entity in Port, and relate it to the relevant githubRepository entity.

With this approach, services will always have a related repository upon creation, and can later be enriched with additional data from other assets in your catalog.

Additional examples by integrationโ€‹

Just like the example above, the blocks in the examples below can be added to the mapping configuration of the relevant integration to automatically create entities in your catalog.

Common examples for resources that can be used as a source of truth for services:

GitHub repository (click to expand)
- kind: repository
selector:
query: 'true'
port:
entity:
mappings:
identifier: .full_name
title: .full_name
blueprint: '"service"'
relations:
repository: .full_name

Monorepo support

If you are using a monorepo, see the working with monorepos page to learn how to tweak the mapping configuration to create entities for each folder in the repository.

Once you have done this, you can add the following block to the mapping configuration to create a service entity for each folder in the repository, and relate it to the relevant githubRepository entity:

# Be sure to change the `path` and `repos` values to match your monorepo structure
- kind: folder
selector:
query: "true"
folders: # Specify the repositories and folders to include under this relative path
- path: apps/* # Relative path to the folders within the repositories
repos: # List of repositories to include folders from
- backend-service
- frontend-service
port:
entity:
mappings:
identifier: ".folder.name"
title: ".folder.name"
blueprint: '"service"'
relations:
repository: ".folder.name"
GitLab project (click to expand)
- kind: project
selector:
query: 'true'
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
relations:
git_lab_repositry: .path_with_namespace | gsub(" "; "")

Monorepo support

If you are using a monorepo, see the working with monorepos page to learn how to tweak the mapping configuration to create entities for each folder in the repository.

Once you have done this, you can add the following block to the mapping configuration to create a service entity for each folder in the repository, and relate it to the relevant gitlabRepository entity:

# Be sure to change the `path` and `repos` values to match your monorepo structure
- kind: folder
selector:
query: "true"
folders: # Specify the repositories and folders to include under this relative path
- path: "apps/" # Relative path to the folders within the repositories
repos: # List of repositories to include folders from
- backend-service
- frontend-service
port:
entity:
mappings:
identifier: .folder.name
title: .folder.name
blueprint: '"service"'
relations:
git_lab_repositry: .folder.name
Bitbucket repository (click to expand)
- kind: repository
selector:
query: 'true'
port:
entity:
mappings:
identifier: .name
title: .name
blueprint: '"service"'
relations:
bitbucketRepository: .name

Monorepo support

If you are using a monorepo, see the working with monorepos page to learn how to tweak the mapping configuration to create entities for each folder in the repository.

Once you have done this, you can add the following block to the mapping configuration to create a service entity for each folder in the repository, and relate it to the relevant bitbucketRepository entity:

# Be sure to change the `path` and `repos` values to match your monorepo structure
- kind: folder
selector:
query: "true"
folders: # Specify the repositories and folders to include under this relative path
- path: apps/* # Relative path to the folders within the repositories
repos: # List of repositories to include folders from
- backend-service
- frontend-service
port:
entity:
mappings:
identifier: .folder.name
blueprint: '"service"'
relations:
bitbucketRepository: .folder.name
Azure DevOps repository (click to expand)
- kind: repository
selector:
query: 'true'
port:
entity:
mappings:
identifier: .project.name + "/" + .name | gsub(" "; "")
title: .name
blueprint: '"service"'
relations:
azureDevopsRepository: .project.name + "/" + .name | gsub(" "; "")
SonarQube project (click to expand)
- kind: projects_ga
selector:
query: 'true'
apiFilters:
qualifier:
- TRK
metrics:
- code_smells
- coverage
- bugs
- vulnerabilities
- duplicated_files
- security_hotspots
- new_violations
- new_coverage
- new_duplicated_lines_density
port:
entity:
mappings:
identifier: .key
title: .name
blueprint: '"service"'
relations:
sonar_project: .key
Snyk target (click to expand)
- kind: target
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .attributes.display_name
blueprint: '"service"'
relations:
snyk_target: .id
PagerDuty service (click to expand)
- kind: services
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"service"'
relations:
pager_duty_service: .id
OpsGenie service (click to expand)
- kind: service
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"service"'
relations:
_opsGenieService: .id

2. Use predefined metadataโ€‹

In addition to defining "sources of truth", you can use data from your external tools to identify and update entities in Port.
This is useful when you want to update entities of a specific type (e.g. services, environments, teams, users) based on a label, naming convention, or other piece of metadata in a specific external tool.

See below for various examples of how to implement this.

Identifier is knownโ€‹

The most straightforward way to identify and update an entity is to have its identifier somewhere in the metadata of the external tool, for instance:

  • In a label/tag.
  • Using a naming convention, e.g. naming all PagerDuty services with the prefix service-<identifier>.

Here are some examples:

After installing the PagerDuty integration and ingesting our PagerDuty services, we may want to automatically connect them to their corresponding service entities.

To achieve this, we need to update the mapping configuration of the PagerDuty integration to include an entry for the service blueprint.

This example assumes that each PagerDuty service has a label named portService with the value being the identifier of the relevant service entity in Port.

- kind: services
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.labels.portService
blueprint: '"service"'
relations:
pager_duty_service: .id

The meaning of this configuration is:
For every PagerDuty service ingested from PagerDuty, update the service entity with the identifier matching the portService label, relating it to this pagerdutyService entity.

Identifier is unknownโ€‹

If the metadata in your external tool is not an identifier, but some other property of the entity you want to update, you can use a query rule to find the relevant entity and update it.

Let's see some examples:

The following example assumes that each PagerDuty service has a label named portService with the value being the title of the service entity in Port:

- kind: application
selector:
query: 'true'
port:
entity:
mappings:
identifier:
combinator: '"and"'
rules:
- operator: '"="'
property: '"$title"'
value: .metadata.labels.portService
blueprint: '"service"'
relations:
pager_duty_service: .id

The meaning of this configuration is:
For every PagerDuty service ingested from PagerDuty, update the service entity with the title matching the portService label, relating it to this pagerdutyService entity.

Connect workloads to their respective servicesโ€‹

The methods above demonstrate how to connect services and workloads to their respective resources.
To complete our service catalog, we need to connect workloads to their respective services.

This too is achieved by updating the mapping configuration of the relevant integration, and adding an entry for the workload blueprint.
One common way to match workloads to services is to use a label.

For example, say we use ArgoCD applications to represent our workloads, and we have a label on each ArgoCD application that matches the identifier of the relevant service entity in Port.
We can then update the mapping configuration of the ArgoCD integration like this:

- kind: application
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.uid
blueprint: '"workload"'
relations:
service: .metadata.labels.portService

Note that you do not need a separate entry for this relation in the mapping configuration.
This page separates the steps for clarity, but you can add multiple relations in the same mapping configuration block.

For example, this is what the mapping configuration for Kubernetes workloads may look like if we added both the service and k8s_workload relations at once:

- kind: apps/v1/deployments
selector:
query: .metadata.namespace | startswith("kube") | not
port:
entity:
mappings:
- identifier: .metadata.labels.portWorkload
title: .metadata.name
blueprint: '"workload"'
relations:
k8s_workload: .metadata.name + "-Deployment-" + .metadata.namespace + "-" + env.CLUSTER_NAME
service: .metadata.labels.portService