Merge branch 'backstage:master' into master

This commit is contained in:
Bogdan Nechyporenko
2022-07-19 18:14:24 +02:00
committed by GitHub
632 changed files with 10619 additions and 6425 deletions
+113
View File
@@ -0,0 +1,113 @@
---
id: cfaccess
title: Cloudflare Access Provider
sidebar_label: cfaccess
# prettier-ignore
description: Adding Cloudflare Access as an authentication provider in Backstage
---
Similar to GCP IAP Proxy Provider or AWS ALB provider, developers can offload authentication
support to Cloudflare Access.
This tutorial shows how to use authentication on Cloudflare Access sitting in
front of Backstage.
It is assumed a Cloudflare tunnel is already serving traffic in front of a
Backstage instance configured to serve the frontend app from the backend and is
already gated using Cloudflare Access.
## Configuration
Let's start by adding the following `auth` configuration in your
`app-config.yaml` or `app-config.production.yaml` or similar:
```yaml
auth:
providers:
cfaccess:
teamName: <Team Name>
```
You can find the team name in the Cloudflare Zero Trust dashboard.
This config section must be in place for the provider to load at all. Now let's
add the provider itself.
## Backend Changes
Add a `providerFactories` entry to the router in
`packages/backend/plugin/auth.ts`.
```ts
import { providers } from '@backstage/plugin-auth-backend';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
logger: env.logger,
config: env.config,
database: env.database,
discovery: env.discovery,
providerFactories: {
'cfaccess': providers.cfAccess.create({
// Replace the auth handler if you want to customize the returned user
// profile info (can be left out; the default implementation is shown
// below which only returns the email). You may want to amend this code
// with something that loads additional user profile data out.
async authHandler({ accessToken }) {
return { profile: { email: accessToken.email } };
},
signIn: {
// You need to supply an identity resolver, that takes the profile
// and the access token and produces the Backstage token with the
// relevant user info.
async resolver({ profile, result }, ctx) {
// Somehow compute the Backstage token claims. Just some dummy code
// shown here, but you may want to query your LDAP server, or
// https://<teamName>.cloudflareaccess.com/cdn-cgi/access/get-identity
// https://developers.cloudflare.com/cloudflare-one/identity/users/validating-json/#groups-within-a-jwt
const id = profile.email.split('@')[0];
const sub = stringifyEntityRef({ kind: 'User', name: id });
const ent = [sub, stringifyEntityRef({ kind: 'Group', name: 'team-name' });
return ctx.issueToken({ claims: { sub, ent } });
},
},
}),
},
});
}
```
Now the backend is ready to serve auth requests on the
`/api/auth/cfaccess/refresh` endpoint. All that's left is to update the
frontend sign-in mechanism to poll that endpoint through Cloudflare Access, on
the user's behalf.
## Frontend Changes
It is recommended to use the `ProxiedSignInPage` for this provider, which is
installed in `packages/app/src/App.tsx` like this:
```diff
+import { ProxiedSignInPage } from '@backstage/core-components';
const app = createApp({
components: {
+ SignInPage: props => <ProxiedSignInPage {...props} provider="cfaccess" />,
```
## Adding the provider to the Backstage frontend
It is recommended to use the `ProxiedSignInPage` for this provider, which is
installed in `packages/app/src/App.tsx` like this:
```diff
+import { ProxiedSignInPage } from '@backstage/core-components';
const app = createApp({
components: {
+ SignInPage: props => <ProxiedSignInPage {...props} provider="cfaccess" />,
```
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page to also work smoothly for local development.
+44 -33
View File
@@ -273,46 +273,57 @@ that the user belongs to using the user access token in the provided result obje
```ts
// File: packages/backend/src/plugins/auth.ts
import { DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model';
import { createRouter, providers } from '@backstage/plugin-auth-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
import {
stringifyEntityRef,
DEFAULT_NAMESPACE,
} from '@backstage/catalog-model';
export default async function createPlugin(
// ...
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
// ...
...env,
providerFactories: {
// ...
google: async ({ profile }, ctx) => {
if (!profile.email) {
throw new Error(
'Login failed, user profile does not contain an email',
);
}
// Split the email into the local part and the domain.
const [localPart, domain] = profile.email.split('@');
google: providers.google.create({
signIn: {
resolver: async ({ profile }, ctx) => {
if (!profile.email) {
throw new Error(
'Login failed, user profile does not contain an email',
);
}
// Split the email into the local part and the domain.
const [localPart, domain] = profile.email.split('@');
// Next we verify the email domain. It is recommended to include this
// kind of check if you don't look up the user in an external service.
if (domain !== 'acme.org') {
throw new Error('Login failed, user email domain check failed');
}
// Next we verify the email domain. It is recommended to include this
// kind of check if you don't look up the user in an external service.
if (domain !== 'acme.org') {
throw new Error(
`Login failed, this email ${profile.email} does not belong to the expected domain`,
);
}
// By using `stringifyEntityRef` we ensure that the reference is formatted correctly
const userEntityRef = stringifyEntityRef({
kind: 'User',
name: localPart,
namespace: DEFAULT_NAMESPACE,
});
return ctx.issueToken({
claims: {
sub: userEntityRef,
ent: [userEntityRef],
// By using `stringifyEntityRef` we ensure that the reference is formatted correctly
const userEntity = stringifyEntityRef({
kind: 'User',
name: localPart,
namespace: DEFAULT_NAMESPACE,
});
return ctx.issueToken({
claims: {
sub: userEntity,
ent: [userEntity],
},
});
},
});
},
}
})
)
},
}),
},
});
}
```
## AuthHandler
+2 -1
View File
@@ -18,6 +18,7 @@ Backstage comes with many common authentication providers in the core library:
- [Auth0](auth0/provider.md)
- [Azure](microsoft/provider.md)
- [Bitbucket](bitbucket/provider.md)
- [Cloudflare Access](cloudflare/access.md)
- [GitHub](github/provider.md)
- [GitLab](gitlab/provider.md)
- [Google](google/provider.md)
@@ -131,7 +132,7 @@ allows allowing guest access:
Some auth providers are so-called "proxy" providers, meaning they're meant to be used
behind an authentication proxy. Examples of these are
[AWS ALB](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md),
[AWS ALB](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md), [Cloudflare Access](./cloudflare/access.md),
[GCP IAP](./google/gcp-iap-auth.md), and [OAuth2 Proxy](./oauth2-proxy/provider.md).
When using a proxy provider, you'll end up wanting to use a different sign-in page, as
+24
View File
@@ -0,0 +1,24 @@
---
id: scaling
title: Scaling Backstage Deployments
sidebar_label: Scaling
description: Scaling Backstage production deployments
---
There are several different methods for scaling Backstage deployments. The most
straight-forward one is to simply deploy multiple identical instances and distributing
incoming requests across them. The one requirement for this to work is that all instances
need to share the same external resources, such as the database, and optional caching or
search services. The Backstage backend plugins will coordinate through the database
to share state and coordinate work.
Another method for scaling Backstage deployments is to break apart the backend
into multiple different services, each running a different set of plugins. This
is a more advanced approach and requires you to be able to route requests to
the appropriate backends based on the plugin ID. Both for ingress, but also
internal traffic between Backstage backends, which is done by creating a custom
implementation of the [PluginEndpointDiscover](../reference/backend-common.pluginendpointdiscovery.md) interface.
Lastly, you can also replicate the Backstage deployments across multiple regions.
This is not a pattern that there is built-in support for and typically only makes
sense to do for individual backend plugins.
@@ -57,11 +57,16 @@ This is an array used to determine where to retrieve cluster configuration from.
Valid cluster locator methods are:
- [`catalog`](#catalog)
- [`localKubectlProxy`](#localKubectlProxy)
- [`config`](#config)
- [`gke`](#gke)
- [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier)
#### `catalog`
This cluster locator method will read cluster information from the catalog.
#### `localKubectlProxy`
This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001).
+36 -66
View File
@@ -14,60 +14,16 @@ Backstage Search lets you find the right information you are looking for in the
## Features
- A federated, faceted search, searching across all entities registered in your Backstage instance.
- A search that lets you bring your own search engine.
- A search that lets you extend it by creating collators for easily indexing content from plugins and other sources.
- A search that lets you create composable search page experiences.
- A search that lets you customize the look and feel of each search result.
- A search that lets you plug in your own search engine of choice.
- A standardized search API where you can choose to index data from other plugins.
## Project roadmap
### Now
**Backstage Search 1.0**
A stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users.
We will consider Backstage Search to be 1.0 when the above
use-cases are met, and an ecosystem of search-enabled plugins are available and
stable.
- As a plugin developer, there should be at least one example of a Backstage
plugin that integrates with search that I can use as inspiration for my own
plugin's search capabilities (for example, the TechDocs plugin).
- As an app integrator, there should be plenty of examples and documentation on
how to customize and extend search in my Backstage instance to meet my
organization's needs.
### Next
_Not specified_
### Someday/Maybe
_Not specified_
### Done
See [Done](#done) below for a list of completed roadmap items.
See the more detailed [architecture](./architecture.md) and [tech stack](./architecture.md#tech-stack).
## Supported
The following sections show the search engines and plugins currently supported by Backstage Search.
### Search engines
See [Backstage Search Architecture](architecture.md) to get an overview of how
the search engines are used.
| Search Engines | Support Status |
| -------------------------------------------------- | -------------- |
| [Lunr](./search-engines.md#lunr) | ✅ |
| [ElasticSearch](./search-engines.md#elasticsearch) | ✅ |
| [Postgres](./search-engines.md#postgres) | ✅ |
[Reach out to us](#get-involved) if you want to chat about support for more
search engines.
The following sections show the plugins and search engines currently supported by Backstage Search.
### Plugins integrated with Backstage Search
@@ -77,20 +33,19 @@ search engines.
| [TechDocs](./how-to-guides.md#how-to-index-techdocs-documents) | ✅ |
| [Stack Overflow](https://github.com/backstage/backstage/blob/master/plugins/stack-overflow-backend/README.md#index-stack-overflow-questions-to-search) | ✅ |
[Reach out to us](#get-involved) if you want to chat about support for more
plugins integrated to search.
### Search engines
## Tech Stack
See [Backstage Search Architecture](architecture.md) to get an overview of how
the search engines are used.
| Stack | Location |
| ------------------------- | ----------------------------------------------------- |
| Frontend Plugin | @backstage/plugin-search |
| Frontend Plugin Library | @backstage/plugin-search-react |
| Isomorphic Plugin Library | @backstage/plugin-search-common |
| Backend Plugin | @backstage/plugin-search-backend |
| Backend Plugin Library | @backstage/plugin-search-backend-node |
| Backend Plugin Module | @backstage/plugin-search-backend-module-elasticsearch |
| Backend Plugin Module | @backstage/plugin-search-backend-module-pg |
| Search Engines | Support Status |
| -------------------------------------------------- | -------------- |
| [ElasticSearch](./search-engines.md#elasticsearch) | ✅ |
| [Lunr](./search-engines.md#lunr) | ✅ |
| [Postgres](./search-engines.md#postgres) | Community ✅ |
[Reach out to us](#get-involved) if you want to chat about support for more plugin integrations and
search engines.
## Get involved
@@ -98,9 +53,9 @@ For any questions, feedback, or to help move search forward, reach out to us in
the **#search** channel of our
[Discord chatroom](https://github.com/backstage/backstage#community).
## Done
## Use Cases supported
**Backstage Search Pre-Alpha**
#### **Backstage Search Pre-Alpha**
Search Frontend letting you search through the entities of the software catalog.
@@ -118,7 +73,7 @@ there by means of a front-end only, non-extensible MVP.
- As a software engineer I should be able to hide the filters if I dont need to
use them.
**Backstage Search Alpha**
#### **Backstage Search Alpha**
Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog.
@@ -136,7 +91,7 @@ met, but built on top of a flexible, extensible platform.
should be possible to have the pre-alpha user experiences covered without
having to set up and configure a search engine.
**Backstage Search Beta**
#### **Backstage Search Beta**
At least one production-ready search engine that supports the same use-cases as in the alpha.
@@ -151,3 +106,18 @@ are met, and can be deployed using a production-ready search engine.
- As an integrator, I should be able to tune the queries sent to my chosen
search engine according to my organization's needs, but a sensible default
query should be in place so that I am not required to do so.
#### **Backstage Search 1.0**
A stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users.
We will consider Backstage Search to be 1.0 when the above
use-cases are met, and an ecosystem of search-enabled plugins are available and
stable.
- As a plugin developer, there should be at least one example of a Backstage
plugin that integrates with search that I can use as inspiration for my own
plugin's search capabilities (for example, the TechDocs plugin).
- As an app integrator, there should be plenty of examples and documentation on
how to customize and extend search in my Backstage instance to meet my
organization's needs.
+12 -4
View File
@@ -4,10 +4,6 @@ title: Search Architecture
description: Documentation on Search Architecture
---
> _This architecture has not been fully implemented yet. Find our milestones to
> follow our progress and help contribute on the
> [Search Roadmap](./README.md#project-roadmap)._
Below you can explore the Search Architecture. Our aim with this architecture is
to support a wide variety of search engines, while providing a simple developer
experience for plugin developers, and a good out-of-the-box experience for
@@ -44,3 +40,15 @@ Architecture non-goals:
- At this time, we do not intend to directly support event-driven or incremental
index management. Instead, we'll be focused on scheduled, bulk index
management.
## Tech Stack
| Stack | Location |
| ------------------------- | ----------------------------------------------------- |
| Frontend Plugin | @backstage/plugin-search |
| Frontend Plugin Library | @backstage/plugin-search-react |
| Isomorphic Plugin Library | @backstage/plugin-search-common |
| Backend Plugin | @backstage/plugin-search-backend |
| Backend Plugin Library | @backstage/plugin-search-backend-node |
| Backend Plugin Module | @backstage/plugin-search-backend-module-elasticsearch |
| Backend Plugin Module | @backstage/plugin-search-backend-module-pg |
+1 -1
View File
@@ -34,7 +34,7 @@ import {
DefaultResultListItem,
SearchFilter,
} from '@backstage/plugin-search-react';
import { CatalogResultListItem } from '@backstage/plugin-catalog';
import { CatalogSearchResultListItem } from '@backstage/plugin-catalog';
export const searchPage = (
<Page themeId="home">
-265
View File
@@ -148,271 +148,6 @@ indexBuilder.addCollator({
As shown above, you can add a catalog entity filter to narrow down what catalog
entities are indexed by the search engine.
## How to migrate from Search Alpha to Beta
For the purposes of this guide, Search Beta version is defined as:
- **Search Plugin**: At least `v0.7.2`
- **Search Backend Plugin**: At least `v0.4.6`
- **Search Backend Node**: At least `v0.5.0`
- **Search Common**: At least `v0.3.0`
In the Beta version, the Search Platform's indexing process has been rewritten
as a stream pipeline in order to improve efficiency and performance on large
sets of documents.
If you've not yet extended the Search Platform with custom code, and have
instead taken advantage of default collators, decorators, and search engines
provided by existing plugins, the migration process is fairly straightforward:
1. Upgrade to at least version `0.5.0` of
`@backstage/plugin-search-backend-node`, as well as any backend plugins whose
collators you are using (e.g. at least version `0.23.0` of
`@backstage/plugin-catalog-backend` and/or version `0.14.1` of
`@backstage/plugin-techdocs-backend`), as well as any search-engine specific
plugin you are using (e.g. at least version `0.3.0` of
`@backstage/plugin-search-backend-module-pg` or version `0.1.0` of
`@backstage/plugin-search-backend-module-elasticsearch`).
2. Then, make the following changes to your
`/packages/backend/src/plugins/search.ts` file:
```diff
-import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
-import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
+import { DefaultCatalogCollatorFactory } from '@backstage/plugin-catalog-backend';
+import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
// ...
const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine });
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
- collator: DefaultCatalogCollator.fromConfig(env.config, {
discovery: env.discovery,
}),
+ factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
}),
});
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
- collator: DefaultTechDocsCollator.fromConfig(env.config, {
+ factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
logger: env.logger,
}),
});
```
Any custom collators, decorators, or search engine implementations will require
minor refactoring. Continue on for details.
### Rewriting alpha-style collators for beta
In alpha versions of the Backstage Search Platform, collators were classes that
implemented an `execute` method which resolved an `IndexableDocument` array.
In beta versions, the logic encapsulated by the aforementioned `execute` method
is contained within an [object-mode][obj-mode] `Readable` stream where each
object pushed onto the stream is of type `IndexableDocument`. Instances of this
stream are instantiated by a factory class conforming to the
`DocumentCollatorFactory` interface.
The optimal conversion strategy will vary depending on the collator's logic, but
the simplest conversion can follow a process like this:
1. Rename your collator class to something like `YourCollatorFactory` and update
it to implement `DocumentCollatorFactory` instead of `DocumentCollator`.
2. Update its `execute` method so that it resolves
`AsyncGenerator<YourIndexableDocument>` instead of `YourIndexableDocument[]`.
3. Implement `DocumentCollatorFactory`'s `getCollator` method which resolves to
`Readable.from(this.execute())` (which is a utility for creating [readable
streams][read-stream] from [async generators][async-gen]).
```ts
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
import { Readable } from 'stream';
export class YourCollatorFactory implements DocumentCollatorFactory {
public readonly type: string = 'your-type';
async *execute(): AsyncGenerator<YourIndexableDocument> {
const widgets = await this.client.getWidgets();
for (const widget of widgets) {
yield {
title: widget.name,
location: widget.url,
text: widget.description,
};
}
}
async getCollator() {
return Readable.from(this.execute());
}
}
```
Note: it may be possible to simplify your collator dramatically! If your custom
collator was previously using streams under the hood (for example, by reading
newline delimited JSON from a local or remote file), you could just expose the
stream directly via a simple factory class:
```ts
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
import { createReadStream } from 'fs';
import { parse } from '@jsonlines/core';
export class YourCollatorFactory implements DocumentCollatorFactory {
public readonly type: string = 'your-type';
async getCollator() {
const parseStream = parse();
return createReadStream('./documents.ndjson').pipe(parseStream);
}
}
```
### Rewriting alpha-style decorators for beta
In alpha versions of the Backstage Search Platform, decorators were classes that
implemented an `execute` method which took an `IndexableDocument` array as an
argument, and resolved a modified array of the same type.
In beta versions, the logic encapsulated by the aforementioned `execute` method
is contained within an object-mode `Transform` stream which reads objects of
type `IndexableDocument`, and writes objects of a conforming type. Similar to
collators, instances of this stream are instantiated by a factory class
conforming to the `DocumentDecoratorFactory` interface.
Although you can choose to implement a `Transform` stream from scratch, the
`@backstage/plugin-search-backend-node` package provides a `DecoratorBase` class
in order to simplify the developer experience. With this base class, all that's
needed is to transfer your old decorator class logic into the base class' three
methods (`initialize`, `decorate`, and `finalize`), and implement the factory
class that instantiates the stream:
```ts
import { DecoratorBase } from '@backstage/plugin-search-backend-node';
export class YourDecorator extends DecoratorBase {
async initialize() {
// Setup logic. Performed once before any documents are consumed.
}
async decorate(
document: YourIndexableDocument,
): Promise<YourIndexableDocument | YourIndexableDocument[] | undefined> {
// Perform transformation logic here.
return document;
}
async finalize() {
// Teardown logic. Performed once after all documents have been consumed.
}
}
export class YourDecoratorFactory implements DocumentDecoratorFactory {
async getDecorator() {
return new YourDecorator();
}
}
```
Note the return type of the `decorate` method and how each can be used to
different effect.
- By resolving a single `YourIndexableDocument` object, your decorator can be
used to make simple transformations:
```ts
class BooleanWidgetCoolnessDecorator extends DecoratorBase {
async decorator(widget) {
// Perform a simple, 1:1 transformation.
widget.isCool = widget.isCool === 'true' ? true : false;
return widget;
}
}
```
- By resolving `undefined`, your decorator can filter out documents which
shouldn't be in the index:
```ts
class OnlyCoolWidgetsDecorator extends DecoratorBase {
async decorator(widget) {
// Perform a simple filter operation.
return widget.isCool ? widget : undefined;
}
}
```
- By resolving an array of `YourIndexableDocument` objects, you can generate
multiple documents based on the content of one:
```ts
class WidgetByVariantDecorator extends DecoratorBase {
async decorator(widget) {
// Generate one widget doc per widget variant.
return widget.variants.map(variant => {
// Each widget doc is the given widget plus a "variant" property
// pulled from a widget.variants string array.
return {
...widget,
variant,
};
});
}
}
```
In alpha versions, a decorator had access to every `IndexableDocument`
simultaneously. This is no longer possible in beta versions (precisely to make
the indexing process more efficient and performant). You will need to modify
your decorator's logic so that it does not need access to every document at
once.
### Rewriting alpha-style search engines for beta
Search Engines are responsible for both querying and indexing documents to an
underlying search engine technology. While the search engine query interface
didn't change between alpha and beta versions, the indexing half of the
interface _did_ change.
In alpha versions of the Backstage Search Platform, a search engine implemented
an `index` method which took a `type` and an `IndexableDocument` array and was
responsible for writing these documents to the underlying search engine.
In beta versions, the logic encapsulated by the aforementioned `index` method is
contained within an object-mode `Writable` stream which expects objects of type
`IndexableDocument`. On the search engine class itself, the `index` method is
replaced with a `getIndexer` factory method which still takes the `type`, but
resolves an instance of the aforementioned `Writable` stream.
Although you can choose to implement a `Writable` stream from scratch, the
`@backstage/plugin-search-backend-node` package provides a
`BatchSearchEngineIndexer` class in order to simplify the developer experience.
With this base class, which collects documents in batches of a configurable size
on your behalf, all that's needed is to transfer your old `index` method logic
into the base class' three methods (`initialize`, `index`, and `finalize`), and
implement the factory method that instantiates the stream:
```ts
import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';
import { SearchEngine } from '@backstage/plugin-search-common';
export class YourSearchEngineIndexer extends BatchSearchEngineIndexer {
constructor({ type }: { type: string }) {
// Customize the number of documents passed to the index method per batch.
super({ batchSize: 500 });
// An imaginary search engine indexing client.
this.index = new SomeSearchEngineIndex({ indexName: type });
}
async initialize() {
// Setup logic. Performed once before any documents are consumed.
}
async index(documents: IndexableDocument[]) {
await this.index.batchOf(documents);
}
async finalize() {
// Teardown logic. Performed once after all documents have been consumed.
}
}
export class YourSearchEngine implements SearchEngine {
async getIndexer(type: string) {
return new YourSearchEngineIndexer({ type });
}
}
```
## How to customize search results highlighting styling
The default highlighting styling for matched terms in search results is your
+20
View File
@@ -232,3 +232,23 @@ search:
auth:
apiKey: base64EncodedKey
```
### Elastic search batch size
Default batch size of the elastic search engine is set to 1000. If you are using a lower spec computing resources (like AWS small instance),
you may get an error caused by limited `thread_pool` configuration. ( `429 Too Many Requests /_bulk` )
In this case you need to decrease the batch size to index the resources to prevent this kind of error. You can easily decrease
or increase the batch size in your `app-config.yaml` using the `batchSize` option provided for elasticsearch configuration.
#### Configuration example
**Set batch size to 100**
```yaml
search:
elasticsearch:
batchSize: 100
```
> You can also increase the batch size if you are using a large ES instance.
@@ -93,8 +93,12 @@ spec:
# some outputs which are saved along with the job for use in the frontend
output:
remoteUrl: ${{ steps.publish.output.remoteUrl }}
entityRef: ${{ steps.register.output.entityRef }}
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
```
Let's dive in and pick apart what each of these sections do and what they are.
@@ -495,8 +499,12 @@ The main two that are used are the following:
```yaml
output:
remoteUrl: ${{ steps.publish.output.remoteUrl }} # link to the remote repository
entityRef: ${{ steps.register.output.entityRef }} # link to the entity that has been ingested to the catalog
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }} # link to the remote repository
- title: Open in catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }} # link to the entity that has been ingested to the catalog
```
## The templating syntax
-24
View File
@@ -76,27 +76,3 @@ builder.addEntityProvider(
}),
);
```
## Alternative Processor
As alternative to the entity provider `AwsS3EntityProvider`
you can still use the `AwsS3DiscoveryProcessor`.
```yaml
# app-config.yaml
catalog:
locations:
- type: s3-discovery
target: https://sample-bucket.s3.us-east-2.amazonaws.com/prefix/
```
```ts
/* packages/backend/src/plugins/catalog.ts */
import { AwsS3DiscoveryProcessor } from '@backstage/plugin-catalog-backend-module-aws';
const builder = await CatalogBuilder.create(env);
/** ... other processors ... */
builder.addProcessor(new AwsS3DiscoveryProcessor(env.reader));
```
+1 -1
View File
@@ -69,7 +69,7 @@ Alternatively you can use VSCode with the Azure extension if you install `@azure
When these are set up, the plugin will authenticate with the Microsoft Graph API without you needing to configure any credentials, or granting any special permissions.
If you can't do this, you'll have to create an App Registration.
## App Registration
### App Registration
If none of the other authentication methods work, you can create an app registration in the azure portal.
By default the graph plugin requires the following Application permissions (not Delegated) for Microsoft Graph:
@@ -24,6 +24,8 @@ app:
# env: 'staging'
```
If your [`app-config.yaml`](https://github.com/backstage/backstage/blob/master/app-config.yaml#L5) file does not have this configuration, you may have to adjust your [`packages/app/public/index.html`](https://github.com/backstage/backstage/blob/master/packages/app/public/index.html#L64) to include the Datadog RUM `init()` section manually.
The `clientToken` and `applicationId` are generated from the Datadog RUM page
following
[these instructions](https://docs.datadoghq.com/real_user_monitoring/browser/).
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
---
id: v1.4.0
title: v1.4.0
description: Backstage Release v1.4.0
---
These are the release notes for the v1.4.0 release of [Backstage](https://backstage.io/).
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
## Highlights
### Search is V1!
Backstage Search is now promoted to v1.0 with a stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users.
No additional features are released as part of the major release as the maintainers of the search packages focused on the following for this release:
- Bug fixes and clean up of deprecations.
- Improved error handling for missing indices.
- Separation of AWS Elastic and Open Elastic support.
- Refactor the packages by moving reusable components from `@backstage/plugin-search` to `@backstage/plugin-search-react`.
- Improved documentation including tutorials for how to [Integrate Search into a plugin](https://backstage.io/docs/plugins/integrating-search-into-plugins).
With moving to v1.0 we also recommend using Elasticsearch for production usage. Moving forward, the search maintainers will prioritize the Elasticsearch engine while well rely on the community to maintain the Postgres engine.
### Experimental Backend System Evolution
This release adds the new `@backstage/backend-app-api` and `@backstage/backend-plugin-api` packages, both part of the [evolution of the backend system](https://github.com/backstage/backstage/issues/11611). These packages are highly experimental and we do not recommend using them for any purpose, yet.
### `@backstage/cli` Deprecation Removals
The `@backstage/cli` had a large number of deprecated commands removed, for example, `app:build` is now gone and should be replaced with `package build`. For a full list of commands that were removed, see the [changelog](https://github.com/backstage/backstage/blob/master/packages/cli/CHANGELOG.md#0180).
### `@backstage/plugin-auth-backend` Deprecation Removals
Many deprecated symbols have now been removed from `@backstage/plugin-auth-backend`, most notably the provider factories such as `createGithubProvider` have been removed, which should be replaced with `providers.github.create`. See the [changelog](https://github.com/backstage/backstage/blob/master/plugins/auth-backend/CHANGELOG.md#0150) for more details.
### New module: `@backstage/plugin-api-docs-module-protoc-gen-doc`
This is a new module for `@backstage/plugin-api-docs` that exports a widget implementation for rendering gRPC docs generated by `protoc-gen-doc`. Contributed by [@kissmikijr](https://github.com/kissmikijr) [#11923](https://github.com/backstage/backstage/pull/11923).
### New module: `@backstage/plugin-catalog-backend-module-openapi`
This is a new module for `@backstage/plugin-catalog-backend` that exports a catalog processor which de-references `$ref` fields in OpenAPI definitions. Contributed by [@mfrinnstrom](https://github.com/mfrinnstrom) [#11645](https://github.com/backstage/backstage/pull/11645).
### New plugin: `@backstage/plugin-apollo-explorer`
A plugin to embed the [Apollo Explorer](https://github.com/apollographql/embeddable-explorer/tree/main/packages/explorer) inside your Backstage instance to run queries against GraphQL endpoints. Contributed by [@unredundant](https://github.com/unredundant) [#12600](https://github.com/backstage/backstage/pull/12600).
## Security Fixes
`@backstage/plugin-scaffolder-backend`, please upgrade to the latest version if you are using this module.
## Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
## Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
- [GitHub repository](https://github.com/backstage/backstage)
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
- [Community Discord](https://discord.gg/bFESRKVt) for discussions and support
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.4.0-changelog.md)
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
Sign up for our [newsletter](https://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage.