Extend Azure Org custom transformer docs to be more end-to-end
Signed-off-by: darylgraham <daryl.graham@gmail.com>
This commit is contained in:
@@ -258,21 +258,96 @@ The `myUserTransformer`, `myGroupTransformer`, `myOrganizationTransformer`, and
|
||||
|
||||
The following provides an example of each kind of transformer. We recommend creating a `transformers.ts` file in your `packages/backend/src` folder for these.
|
||||
|
||||
First, lets set up the basic structure of the file, with functions for each kind of transformer that simply passes through the default transformer unchanged.
|
||||
|
||||
```ts title="packages/backend/src/transformers.ts"
|
||||
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
|
||||
import {
|
||||
defaultGroupTransformer,
|
||||
defaultUserTransformer,
|
||||
defaultOrganizationTransformer,
|
||||
microsoftGraphOrgEntityProviderTransformExtensionPoint,
|
||||
MicrosoftGraphProviderConfig,
|
||||
} from '@backstage/plugin-catalog-backend-module-msgraph';
|
||||
import { GroupEntity, UserEntity } from '@backstage/catalog-model';
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
|
||||
// This group transformer completely replaces the built in logic with custom logic.
|
||||
// The Group transformer transforms Groups that are ingested from MS Graph
|
||||
export async function myGroupTransformer(
|
||||
group: MicrosoftGraph.Group,
|
||||
groupPhoto?: string,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
const backstageGroup = await defaultGroupTransformer(group, groupPhoto);
|
||||
return backstageGroup;
|
||||
}
|
||||
|
||||
// The User transformer transforms Users that are ingested from MS Graph
|
||||
export async function myUserTransformer(
|
||||
graphUser: MicrosoftGraph.User,
|
||||
userPhoto?: string,
|
||||
): Promise<UserEntity | undefined> {
|
||||
const backstageUser = await defaultUserTransformer(graphUser, userPhoto);
|
||||
return backstageUser;
|
||||
}
|
||||
|
||||
// The Organization transformer transforms the root MS Graph Organization into a Group
|
||||
export async function myOrganizationTransformer(
|
||||
graphOrganization: MicrosoftGraph.Organization,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
const backstageOrg = await defaultOrganizationTransformer(graphOrganization);
|
||||
return backstageOrg;
|
||||
}
|
||||
|
||||
// The Provider Config transformer enables modification of the plugin config
|
||||
export async function myProviderConfigTransformer(
|
||||
provider: MicrosoftGraphProviderConfig,
|
||||
): Promise<MicrosoftGraphProviderConfig> {
|
||||
return provider;
|
||||
}
|
||||
|
||||
// Wrapping these functions in a Module allows us to inject them into the Catalog plugin easily
|
||||
export const myMsgraphTransformersModule = createBackendModule({
|
||||
pluginId: 'catalog',
|
||||
moduleId: 'msgraph-org',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
microsoftGraphTransformers:
|
||||
microsoftGraphOrgEntityProviderTransformExtensionPoint,
|
||||
},
|
||||
async init({ microsoftGraphTransformers }) {
|
||||
// Set the transformers to our custom functions
|
||||
microsoftGraphTransformers.setUserTransformer(myUserTransformer);
|
||||
microsoftGraphTransformers.setGroupTransformer(myGroupTransformer);
|
||||
microsoftGraphTransformers.setOrganizationTransformer(
|
||||
myOrganizationTransformer,
|
||||
);
|
||||
microsoftGraphTransformers.setProviderConfigTransformer(
|
||||
myProviderConfigTransformer,
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Export a default to make importing into the backend simpler
|
||||
export default myMsgraphTransformersModule;
|
||||
```
|
||||
|
||||
Now lets customize each of the providers to suit our needs.
|
||||
|
||||
The Group Transformer will have the default logic completely removed and replaced with our custom logic:
|
||||
|
||||
```ts
|
||||
export async function myGroupTransformer(
|
||||
group: MicrosoftGraph.Group,
|
||||
groupPhoto?: string,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
// highlight-remove-start
|
||||
const backstageGroup = await defaultGroupTransformer(group, groupPhoto);
|
||||
return backstageGroup;
|
||||
// highlight-remove-end
|
||||
// highlight-add-start
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
@@ -285,40 +360,90 @@ export async function myGroupTransformer(
|
||||
children: [],
|
||||
},
|
||||
};
|
||||
// highlight-add-end
|
||||
}
|
||||
```
|
||||
|
||||
// This user transformer makes use of the built in logic, but also sets the description field
|
||||
The User Transformer makes use of the built-in logic, but also modifies the username and sets a description
|
||||
|
||||
```ts
|
||||
export async function myUserTransformer(
|
||||
graphUser: MicrosoftGraph.User,
|
||||
userPhoto?: string,
|
||||
): Promise<UserEntity | undefined> {
|
||||
const backstageUser = await defaultUserTransformer(graphUser, userPhoto);
|
||||
|
||||
// highlight-add-start
|
||||
// Make sure the default transformer returned an entity
|
||||
if (backstageUser) {
|
||||
backstageUser.metadata.description = 'Loaded from Microsoft Entra ID';
|
||||
// Update the description to make it obvious where this entity came from
|
||||
backstageUser.metadata.description =
|
||||
'Loaded from Microsoft Entra ID via MyCustomUserTransformer';
|
||||
|
||||
// The default transformer sets the username to the email address with invalid characters subbed out: 'user_domain.com'
|
||||
// Set the username to the local part of the email address in lowercase without the domain
|
||||
const newName = backstageUser.metadata.name.split('_')[0].toLowerCase();
|
||||
backstageUser.metadata.name = newName;
|
||||
|
||||
return backstageUser;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// highlight-add-end
|
||||
// highlight-remove-start
|
||||
return backstageUser;
|
||||
// highlight-remove-end
|
||||
}
|
||||
```
|
||||
|
||||
// Example organization transformer that removes the organization group completely
|
||||
The Organization Transformer removes the organization group completely by returning undefined
|
||||
|
||||
```ts
|
||||
export async function myOrganizationTransformer(
|
||||
graphOrganization: MicrosoftGraph.Organization,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
// highlight-remove-start
|
||||
const backstageOrg = await defaultOrganizationTransformer(graphOrganization);
|
||||
return backstageOrg;
|
||||
// highlight-remove-end
|
||||
// highlight-add-start
|
||||
return undefined;
|
||||
// highlight-add-end
|
||||
}
|
||||
```
|
||||
|
||||
// Example config transformer that expands the group filter to also include 'azure-group-a'
|
||||
The Config Transformer expands the group filter to also include 'azure-group-a'
|
||||
|
||||
```ts
|
||||
export async function myProviderConfigTransformer(
|
||||
provider: MicrosoftGraphProviderConfig,
|
||||
): Promise<MicrosoftGraphProviderConfig> {
|
||||
// highlight-add-start
|
||||
if (!provider.groupFilter?.includes('azure-group-a')) {
|
||||
provider.groupFilter = `${provider.groupFilter} or displayName eq 'azure-group-a'`;
|
||||
}
|
||||
// highlight-add-end
|
||||
return provider;
|
||||
}
|
||||
```
|
||||
|
||||
Now we just need to add our new module to the Backend.
|
||||
|
||||
```ts
|
||||
// packages/backend/src/index.ts
|
||||
// Your file will have more than this in it
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
...
|
||||
|
||||
// highlight-add-start
|
||||
backend.add(import('./transformers'));
|
||||
// highlight-add-end
|
||||
|
||||
...
|
||||
|
||||
backend.start();
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No data
|
||||
|
||||
Reference in New Issue
Block a user