Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 117 additions & 1 deletion how-to-guides/bootstrap-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,121 @@ export PROVIDER_KUBECONFIG=provider-kubeconfig.yaml
kubectl --kubeconfig $PROVIDER_KUBECONFIG apply -f <your-workspace-resources>
```

## Step 5: Wire the kubeconfig into your service controllers
## Step 5: Register your provider in the Marketplace

For your provider to appear in the Platform Mesh Marketplace and project its navigation into consumer workspaces, apply three resources to the provider workspace. The `ui.platform-mesh.io/content-for` label is the join key, but its **value differs by resource**:

| Resource | `content-for` value | Purpose |
| --- | --- | --- |
| `ProviderMetadata` | `<provider-name>` — for example `my-service` | Marketplace card — name, description, icon, contacts, documentation, support links. |
| `APIExport` | `<provider-name>` — same as `ProviderMetadata.name` | The Marketplace filter joins `APIExport` to `ProviderMetadata` by this value. The Marketplace skips exports whose `status.identityHash` is empty (not yet established by kcp). UI-only providers that expose no CRD can omit `spec.latestResourceSchemas`. |
| `ContentConfiguration` | `<APIExport.name>` — for example `my-service.example.com` | The portal's nav projection reads ContentConfigurations by `content-for: <APIExport.name>` from the provider workspace once the APIBinding is installed. |

::: tip Two different values for the same label key
`ProviderMetadata` and `APIExport` share `content-for: <provider-name>` so the Marketplace can join them.
`ContentConfiguration` uses `content-for: <APIExport.name>` (the full API group name) so the portal can project nav nodes into the consumer workspace after install.
:::

A minimal example for a UI-only provider:

```yaml
# providermetadata.yaml
apiVersion: ui.platform-mesh.io/v1alpha1
kind: ProviderMetadata
metadata:
name: my-service
labels:
ui.platform-mesh.io/content-for: my-service
spec:
displayName: My Service
description: Short description shown in the Marketplace card.
tags: [example]
contacts:
- displayName: My Team
email: my-team@example.com
role: [Owner]
documentation:
- displayName: Documentation
url: https://docs.example.com
icon:
light:
url: https://example.com/icon-light.svg
dark:
url: https://example.com/icon-dark.svg
```

```yaml
# apiexport.yaml (UI-only: no latestResourceSchemas needed)
apiVersion: apis.kcp.io/v1alpha1
kind: APIExport
metadata:
name: my-service.example.com
labels:
ui.platform-mesh.io/content-for: my-service
spec: {}
```

```yaml
# contentconfiguration.yaml
apiVersion: ui.platform-mesh.io/v1alpha1
kind: ContentConfiguration
metadata:
name: my-service-ui
labels:
ui.platform-mesh.io/content-for: my-service.example.com
ui.platform-mesh.io/entity: core_platform-mesh_io_account
spec:
remoteConfiguration:
url: https://example.com/portal-config.json
contentType: json
```

Apply them using the provider kubeconfig:

```bash
export PROVIDER_KUBECONFIG=provider-kubeconfig.yaml
kubectl --kubeconfig $PROVIDER_KUBECONFIG apply -f apiexport.yaml
kubectl --kubeconfig $PROVIDER_KUBECONFIG apply -f providermetadata.yaml
kubectl --kubeconfig $PROVIDER_KUBECONFIG apply -f contentconfiguration.yaml
```

## Step 6: Grant bind permission

The Marketplace install flow creates an `APIBinding` in the consumer workspace by calling `bind` on the provider's `APIExport`. Without an explicit grant, the call fails with "no permission to bind to export". Apply a `ClusterRole` and `ClusterRoleBinding` to the provider workspace to allow it:

```yaml
# rbac-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: my-service-bind
rules:
- apiGroups: ["apis.kcp.io"]
resources: ["apiexports"]
resourceNames: ["my-service.example.com"]
verbs: ["bind"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-service-bind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-service-bind
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated
```

```bash
kubectl --kubeconfig $PROVIDER_KUBECONFIG apply -f rbac-bind.yaml
```

After both steps, open the Marketplace in a consumer workspace — the provider card appears and the **Enable** button works.

## Step 7: Wire the kubeconfig into your service controllers

Configure your service controllers to use the provider kubeconfig to watch the `APIExport` virtual workspace and reconcile service consumers. See [Integration paths](/concepts/integration-paths.md) to choose the right mechanism and find the corresponding tutorial.

Expand All @@ -81,3 +195,5 @@ Configure your service controllers to use the provider kubeconfig to watch the `
- [Provider bootstrap](/concepts/provider-bootstrap.md)
- [Integration paths](/concepts/integration-paths.md)
- [Service provider persona](/concepts/personas/service-provider.md)
- [Metadata catalog](/reference/resources/metadata-catalog.md) — `ui.platform-mesh.io/content-for` label reference
- [ContentConfiguration](/reference/resources/content-configuration.md)
5 changes: 2 additions & 3 deletions reference/resources/metadata-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ Platform Mesh attaches labels to its own resources and, in some cases, to upstre
| Label | Used on | Purpose |
| --- | --- | --- |
| `core.platform-mesh.io/org` | WorkspaceTypes managed by the account-operator | Scopes a workspace type to a specific organization so child accounts inherit the right RBAC. |
| `ui.platform-mesh.io/content-for` | `ProviderMetadata`, `APIExport`, `ContentConfiguration` | **Required by provider authors.** Links the three resources that make up a Marketplace entry and a portal nav projection, but the value differs by resource: `ProviderMetadata` and `APIExport` use the `ProviderMetadata` name (for example `my-service`) so the Marketplace can join them; `ContentConfiguration` uses the `APIExport` name (for example `my-service.example.com`) so the portal can project nav nodes into a consumer workspace after install. See [Register your provider in the Marketplace](/how-to-guides/bootstrap-provider.md#register-your-provider-in-the-marketplace). |
| `ui.platform-mesh.io/entity` | ContentConfiguration | Attaches the configuration to a portal navigation entity (for example, `core_platform-mesh_io_account` to extend Account pages). |
| `extensions.openmfp.io` | ContentConfiguration (legacy) | Maps to an `ExtensionClass` in older deployments. New deployments prefer `ui.platform-mesh.io/entity`. |

Provider authors generally do **not** need to set Platform Mesh labels on APIExports or APIBindings — onboarding scripts and operators handle that.

## Finalizers

Finalizers ensure that Platform Mesh resources are torn down in the right order — for example, an Account's IAM Store must be cleaned up before the workspace itself is deleted, otherwise stranded permissions remain in OpenFGA.
Expand Down Expand Up @@ -71,7 +70,7 @@ This catalog is updated as Platform Mesh component owners contribute the support
## Related

- [Account resource](./account-resource.md) — uses the `core.platform-mesh.io` API group and its finalizers
- [ContentConfiguration](./content-configuration.md) — uses the `ui.platform-mesh.io` API group and the `ui.platform-mesh.io/entity` label
- [ContentConfiguration](./content-configuration.md) — uses the `ui.platform-mesh.io` API group and the `ui.platform-mesh.io/entity` and `ui.platform-mesh.io/content-for` labels
- [Provider resource](./provider-resource.md) — uses the `providers.platform-mesh.io` API group and its finalizers
- [ManagedProvider resource](./managed-provider-resource.md) — uses the `providers.platform-mesh.io` API group and its finalizers
- [Account model](/concepts/account-model.md)
Expand Down