@backstage-community/plugin-cost-insights 0.12.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2017 -0
- package/README.md +244 -0
- package/config.d.ts +148 -0
- package/dist/esm/index-BA6m_qFS.esm.js +109 -0
- package/dist/esm/index-BA6m_qFS.esm.js.map +1 -0
- package/dist/esm/index-BFM2mP6Z.esm.js +4084 -0
- package/dist/esm/index-BFM2mP6Z.esm.js.map +1 -0
- package/dist/esm/index-BPzWHt3A.esm.js +169 -0
- package/dist/esm/index-BPzWHt3A.esm.js.map +1 -0
- package/dist/esm/index-BTIHr4n_.esm.js +83 -0
- package/dist/esm/index-BTIHr4n_.esm.js.map +1 -0
- package/dist/esm/index-DaitkcPN.esm.js +1136 -0
- package/dist/esm/index-DaitkcPN.esm.js.map +1 -0
- package/dist/esm/selector-D7iXJwd9.esm.js +594 -0
- package/dist/esm/selector-D7iXJwd9.esm.js.map +1 -0
- package/dist/index.d.ts +655 -0
- package/dist/index.esm.js +83 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +90 -0
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Cost Insights
|
|
2
|
+
|
|
3
|
+
Cost Insights is a plugin to help engineers visualize, understand and optimize their cloud costs. The Cost Insights page shows daily cost data for a team, trends over time, and comparisons with the business metrics you care about.
|
|
4
|
+
|
|
5
|
+
At Spotify, we find that cloud costs are optimized organically when:
|
|
6
|
+
|
|
7
|
+
- Engineers see cost data in their daily work (that is, in Backstage).
|
|
8
|
+
- It's clear when cloud costs need attention.
|
|
9
|
+
- The data is shown in software terms familiar to them.
|
|
10
|
+
- Alerts and recommendations are targeted and actionable.
|
|
11
|
+
|
|
12
|
+
Cost Insights shows trends over time, at the granularity of Backstage catalog entities - rather than the cloud provider's concepts. It can be used to troubleshoot cost anomalies, and promote cost-saving infrastructure migrations.
|
|
13
|
+
|
|
14
|
+
Learn more with the Backstage blog post [New Cost Insights plugin: The engineer's solution to taming cloud costs](https://backstage.io/blog/2020/10/22/cost-insights-plugin).
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# From your Backstage root directory
|
|
20
|
+
yarn --cwd packages/app add @backstage-community/plugin-cost-insights
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
1. Configure `app-config.yaml`. See [Configuration](#configuration).
|
|
26
|
+
|
|
27
|
+
2. Create a CostInsights client. Clients must implement the [CostInsightsApi](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/api/CostInsightsApi.ts) interface. Create your own or [use a template](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/example/templates/CostInsightsClient.ts) to get started.
|
|
28
|
+
|
|
29
|
+
Tip: You can also use the `ExampleCostInsightsClient` from `@backstage-community/plugin-cost-insights` to see how the plugin looks with some mock data.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// path/to/CostInsightsClient.ts
|
|
33
|
+
import { CostInsightsApi } from '@backstage-community/plugin-cost-insights';
|
|
34
|
+
|
|
35
|
+
export class CostInsightsClient implements CostInsightsApi { ... }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Note:** We've briefly explored using the AWS Cost Explorer API to implement a Cost Insights client. Learn more about our findings [here](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/contrib/aws-cost-explorer-api.md).
|
|
39
|
+
|
|
40
|
+
3. Import the client and the Cost Insights plugin API to your Backstage instance.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// packages/app/src/api.ts
|
|
44
|
+
import { createApiFactory } from '@backstage/core-plugin-api';
|
|
45
|
+
import { costInsightsApiRef } from '@backstage-community/plugin-cost-insights';
|
|
46
|
+
import { CostInsightsClient } from './path/to/file';
|
|
47
|
+
|
|
48
|
+
export const apis = [
|
|
49
|
+
createApiFactory({
|
|
50
|
+
api: costInsightsApiRef,
|
|
51
|
+
deps: {},
|
|
52
|
+
factory: () => new CostInsightsClient(),
|
|
53
|
+
}),
|
|
54
|
+
];
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
4. Add the `CostInsightsPage` extension to your `App.tsx`:
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
// packages/app/src/App.tsx
|
|
61
|
+
import { CostInsightsPage } from '@backstage-community/plugin-cost-insights';
|
|
62
|
+
|
|
63
|
+
<FlatRoutes>
|
|
64
|
+
...
|
|
65
|
+
<Route path="/cost-insights" element={<CostInsightsPage />} />
|
|
66
|
+
...
|
|
67
|
+
</FlatRoutes>;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
5. Add Cost Insights to your app Sidebar.
|
|
71
|
+
|
|
72
|
+
To expose the plugin to your users, you can integrate the `cost-insights` route anyway that suits your application, but most commonly it is added to the Sidebar.
|
|
73
|
+
|
|
74
|
+
```diff
|
|
75
|
+
// packages/app/src/components/Root/Root.tsx
|
|
76
|
+
+ import MoneyIcon from '@material-ui/icons/MonetizationOn';
|
|
77
|
+
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
export const Root = ({ children }: PropsWithChildren<{}>) => (
|
|
81
|
+
<SidebarPage>
|
|
82
|
+
<Sidebar>
|
|
83
|
+
<SidebarLogo />
|
|
84
|
+
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
|
|
85
|
+
<SidebarSearchModal>
|
|
86
|
+
{({ toggleModal }) => <SearchModal toggleModal={toggleModal} />}
|
|
87
|
+
</SidebarSearchModal>
|
|
88
|
+
</SidebarGroup>
|
|
89
|
+
<SidebarDivider />
|
|
90
|
+
<SidebarItem icon={ExtensionIcon} to="api-docs" text="APIs" />
|
|
91
|
+
<SidebarItem icon={LibraryBooks} to="docs" text="Docs" />
|
|
92
|
+
<SidebarItem icon={LayersIcon} to="explore" text="Explore" />
|
|
93
|
+
<SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
|
|
94
|
+
{/* End global nav */}
|
|
95
|
+
<SidebarDivider />
|
|
96
|
+
<SidebarScrollWrapper>
|
|
97
|
+
+ <SidebarItem
|
|
98
|
+
+ icon={MoneyIcon}
|
|
99
|
+
+ to="cost-insights"
|
|
100
|
+
+ text="Cost Insights"
|
|
101
|
+
+ />
|
|
102
|
+
</SidebarScrollWrapper>
|
|
103
|
+
<SidebarDivider />
|
|
104
|
+
<Shortcuts />
|
|
105
|
+
</SidebarGroup>
|
|
106
|
+
<SidebarSpace />
|
|
107
|
+
<SidebarDivider />
|
|
108
|
+
<SidebarGroup
|
|
109
|
+
label="Settings"
|
|
110
|
+
icon={<UserSettingsSignInAvatar />}
|
|
111
|
+
to="/settings"
|
|
112
|
+
>
|
|
113
|
+
<SidebarSettings />
|
|
114
|
+
</SidebarGroup>
|
|
115
|
+
</Sidebar>
|
|
116
|
+
{children}
|
|
117
|
+
</SidebarPage>
|
|
118
|
+
);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
Cost Insights has only one required configuration field: `engineerCost` - the average yearly cost of an engineer including benefits.
|
|
124
|
+
|
|
125
|
+
### Basic
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
## ./app-config.yaml
|
|
129
|
+
costInsights:
|
|
130
|
+
engineerCost: 200000
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Products (Optional)
|
|
134
|
+
|
|
135
|
+
For showing cost breakdowns you can define a map of cloud products. They must be defined as keys on the `products` field. A user-friendly name is **required**.
|
|
136
|
+
|
|
137
|
+
You can optionally supply a product `icon` to display in Cost Insights navigation. See the [type file](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Icon.ts) for supported types and Material UI icon [mappings](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/utils/navigation.tsx).
|
|
138
|
+
|
|
139
|
+
**Note:** Product keys should be unique and on `camelCase` form. Backstage does not support underscores in configuration keys.
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
## ./app-config.yaml
|
|
143
|
+
costInsights:
|
|
144
|
+
engineerCost: 200000
|
|
145
|
+
products:
|
|
146
|
+
productA:
|
|
147
|
+
name: Some Cloud Product ## required
|
|
148
|
+
icon: storage
|
|
149
|
+
productB:
|
|
150
|
+
name: Some Other Cloud Product
|
|
151
|
+
icon: data
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Metrics (Optional)
|
|
155
|
+
|
|
156
|
+
In the `Cost Overview` panel, users can choose from a dropdown of business metrics to see costs as they relate to a metric, such as daily active users. Metrics must be defined as keys on the `metrics` field. A user-friendly name is **required**. Metrics will be provided to the `getDailyMetricData` API method via the `metric` parameter.
|
|
157
|
+
|
|
158
|
+
An optional `default` field can be set to `true` to set the default comparison metric to daily cost in the Cost Overview panel.
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
## ./app-config.yaml
|
|
162
|
+
costInsights:
|
|
163
|
+
engineerCost: 200000
|
|
164
|
+
products:
|
|
165
|
+
productA:
|
|
166
|
+
name: Some Cloud Product
|
|
167
|
+
icon: storage
|
|
168
|
+
productB:
|
|
169
|
+
name: Some Other Cloud Product
|
|
170
|
+
icon: data
|
|
171
|
+
metrics:
|
|
172
|
+
metricA:
|
|
173
|
+
name: Metric A ## required
|
|
174
|
+
default: true
|
|
175
|
+
metricB:
|
|
176
|
+
name: Metric B
|
|
177
|
+
metricC:
|
|
178
|
+
name: Metric C
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Base Currency (Optional)
|
|
182
|
+
|
|
183
|
+
In the case you would like to show your baseline costs on the graph on other currency than US dollars.
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
## ./app-config.yaml
|
|
187
|
+
costInsights:
|
|
188
|
+
engineerCost: 200000
|
|
189
|
+
baseCurrency:
|
|
190
|
+
locale: nl-NL
|
|
191
|
+
options:
|
|
192
|
+
currency: EUR
|
|
193
|
+
minimumFractionDigits: 3
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Currencies (Optional)
|
|
197
|
+
|
|
198
|
+
In the `Cost Overview` panel, users can choose from a dropdown of currencies to see costs in, such as Engineers or USD. Currencies must be defined as keys on the `currencies` field. A user-friendly label and unit are **required**. If not set, the `defaultCurrencies` in `currency.ts` will be used.
|
|
199
|
+
|
|
200
|
+
A currency without `kind` is reserved to calculate cost for `engineers`. There should only be one currency without `kind`.
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
## ./app-config.yaml
|
|
204
|
+
costInsights:
|
|
205
|
+
engineerCost: 200000
|
|
206
|
+
products:
|
|
207
|
+
productA:
|
|
208
|
+
name: Some Cloud Product
|
|
209
|
+
icon: storage
|
|
210
|
+
productB:
|
|
211
|
+
name: Some Other Cloud Product
|
|
212
|
+
icon: data
|
|
213
|
+
currencies:
|
|
214
|
+
currencyA:
|
|
215
|
+
label: Currency A
|
|
216
|
+
unit: Unit A
|
|
217
|
+
currencyB:
|
|
218
|
+
label: Currency B
|
|
219
|
+
kind: CURRENCY_B
|
|
220
|
+
unit: Unit B
|
|
221
|
+
prefix: B
|
|
222
|
+
rate: 3.5
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Engineer Threshold (Optional; default 0.5)
|
|
226
|
+
|
|
227
|
+
This threshold determines whether to show 'Negligible', or a percentage with a fraction of 'engineers' for cost savings or cost excess on top of the charts.
|
|
228
|
+
A threshold of 0.5 means that `Negligible` is shown when the difference in costs is lower than that fraction of engineers in that time frame,
|
|
229
|
+
and show `XX% or ~N engineers` when it's above the threshold.
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
## ./app-config.yaml
|
|
233
|
+
costInsights:
|
|
234
|
+
engineerCost: 200000
|
|
235
|
+
engineerThreshold: 0.5
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Alerts
|
|
239
|
+
|
|
240
|
+
The CostInsightsApi `getAlerts` method may return any type of alert or recommendation (called collectively "Action Items" in Cost Insights) that implements the [Alert type](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/types/Alert.ts). This allows you to deliver any alerts or recommendations specific to your infrastructure or company migrations.
|
|
241
|
+
|
|
242
|
+
To learn more about using Cost Insights' ready-to-use alerts, see the alerts [README](https://github.com/backstage/backstage/blob/master/plugins/cost-insights/src/alerts/README.md).
|
|
243
|
+
|
|
244
|
+
Example implementations of custom alerts, forms and components can be found in the [examples](https://github.com/backstage/backstage/tree/master/plugins/cost-insights/src/example) directory.
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface Config {
|
|
18
|
+
costInsights: {
|
|
19
|
+
/**
|
|
20
|
+
* @visibility frontend
|
|
21
|
+
*/
|
|
22
|
+
engineerCost: number;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @visibility frontend
|
|
26
|
+
*/
|
|
27
|
+
engineerThreshold?: number;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @visibility frontend
|
|
31
|
+
*/
|
|
32
|
+
hideTrendLine?: boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @visibility frontend
|
|
36
|
+
*/
|
|
37
|
+
baseCurrency?: {
|
|
38
|
+
/**
|
|
39
|
+
* @visibility frontend
|
|
40
|
+
*/
|
|
41
|
+
locale?: string;
|
|
42
|
+
options?: {
|
|
43
|
+
/**
|
|
44
|
+
* @visibility frontend
|
|
45
|
+
*/
|
|
46
|
+
localeMatcher?: string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* @visibility frontend
|
|
49
|
+
*/
|
|
50
|
+
style?: string | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* @visibility frontend
|
|
53
|
+
*/
|
|
54
|
+
currency?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* @visibility frontend
|
|
57
|
+
*/
|
|
58
|
+
currencySign?: string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* @visibility frontend
|
|
61
|
+
*/
|
|
62
|
+
useGrouping?: boolean | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* @visibility frontend
|
|
65
|
+
*/
|
|
66
|
+
minimumIntegerDigits?: number | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* @visibility frontend
|
|
69
|
+
*/
|
|
70
|
+
minimumFractionDigits?: number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* @visibility frontend
|
|
73
|
+
*/
|
|
74
|
+
maximumFractionDigits?: number | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* @visibility frontend
|
|
77
|
+
*/
|
|
78
|
+
minimumSignificantDigits?: number | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* @visibility frontend
|
|
81
|
+
*/
|
|
82
|
+
maximumSignificantDigits?: number | undefined;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
products?: {
|
|
87
|
+
[kind: string]: {
|
|
88
|
+
/**
|
|
89
|
+
* @visibility frontend
|
|
90
|
+
*/
|
|
91
|
+
name: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @visibility frontend
|
|
95
|
+
*/
|
|
96
|
+
icon?: 'compute' | 'data' | 'database' | 'storage' | 'search' | 'ml';
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
metrics?: {
|
|
101
|
+
[kind: string]: {
|
|
102
|
+
/**
|
|
103
|
+
* @visibility frontend
|
|
104
|
+
*/
|
|
105
|
+
name: string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @visibility frontend
|
|
109
|
+
*/
|
|
110
|
+
default?: boolean;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
currencies?: {
|
|
115
|
+
[id: string]: {
|
|
116
|
+
/**
|
|
117
|
+
* @visibility frontend
|
|
118
|
+
*/
|
|
119
|
+
label: string;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @visibility frontend
|
|
123
|
+
*/
|
|
124
|
+
unit: string;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @visibility frontend
|
|
128
|
+
*/
|
|
129
|
+
kind?: string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @visibility frontend
|
|
133
|
+
*/
|
|
134
|
+
prefix?: string;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @visibility frontend
|
|
138
|
+
*/
|
|
139
|
+
rate?: number;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @visibility frontend
|
|
143
|
+
*/
|
|
144
|
+
default?: boolean;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Box from '@material-ui/core/Box';
|
|
3
|
+
import Typography from '@material-ui/core/Typography';
|
|
4
|
+
import { A as AlertInstructionsLayout } from './index-BFM2mP6Z.esm.js';
|
|
5
|
+
import { Link, CodeSnippet } from '@backstage/core-components';
|
|
6
|
+
import '@backstage/core-plugin-api';
|
|
7
|
+
import 'pluralize';
|
|
8
|
+
import '@material-ui/core/styles';
|
|
9
|
+
import '@material-ui/core/Avatar';
|
|
10
|
+
import '@material-ui/core/Tooltip';
|
|
11
|
+
import '@material-ui/core/IconButton';
|
|
12
|
+
import '@material-ui/core/Badge';
|
|
13
|
+
import '@material-ui/core/Paper';
|
|
14
|
+
import '@material-ui/core/Divider';
|
|
15
|
+
import '@material-ui/icons/AccessTime';
|
|
16
|
+
import '@material-ui/icons/Check';
|
|
17
|
+
import '@material-ui/icons/Delete';
|
|
18
|
+
import 'classnames';
|
|
19
|
+
import '@material-ui/core/Card';
|
|
20
|
+
import '@material-ui/core/CardHeader';
|
|
21
|
+
import '@material-ui/icons/MonetizationOn';
|
|
22
|
+
import '@material-ui/icons/Whatshot';
|
|
23
|
+
import '@material-ui/icons/Settings';
|
|
24
|
+
import '@material-ui/icons/AccountTree';
|
|
25
|
+
import '@material-ui/icons/Storage';
|
|
26
|
+
import '@material-ui/icons/Search';
|
|
27
|
+
import '@material-ui/icons/CloudQueue';
|
|
28
|
+
import '@material-ui/icons/School';
|
|
29
|
+
import '@material-ui/icons/ViewHeadline';
|
|
30
|
+
import '@material-ui/lab/Alert';
|
|
31
|
+
import 'react-router-dom';
|
|
32
|
+
import 'qs';
|
|
33
|
+
import 'yup';
|
|
34
|
+
import '@material-ui/core/Backdrop';
|
|
35
|
+
import '@material-ui/core/CircularProgress';
|
|
36
|
+
import 'luxon';
|
|
37
|
+
import '@material-ui/core/styles/colorManipulator';
|
|
38
|
+
import '@backstage/catalog-model';
|
|
39
|
+
import '@material-ui/core/Grid';
|
|
40
|
+
import '@material-ui/core/Snackbar';
|
|
41
|
+
import '@material-ui/core/utils';
|
|
42
|
+
import '@material-ui/core/Button';
|
|
43
|
+
import '@material-ui/core/Dialog';
|
|
44
|
+
import '@material-ui/core/DialogActions';
|
|
45
|
+
import '@material-ui/core/DialogContent';
|
|
46
|
+
import '@material-ui/icons/Close';
|
|
47
|
+
import '@material-ui/core/Checkbox';
|
|
48
|
+
import '@material-ui/core/FormControl';
|
|
49
|
+
import '@material-ui/core/FormControlLabel';
|
|
50
|
+
import '@material-ui/core/RadioGroup';
|
|
51
|
+
import '@material-ui/core/Radio';
|
|
52
|
+
import '@material-ui/core/Collapse';
|
|
53
|
+
import '@material-ui/core/TextField';
|
|
54
|
+
import '@material-ui/icons/ExpandMore';
|
|
55
|
+
import '@material-ui/core/Container';
|
|
56
|
+
import '@material-ui/icons/ChevronLeft';
|
|
57
|
+
import 'recharts';
|
|
58
|
+
import '@material-ui/core/Slide';
|
|
59
|
+
import '@material-ui/icons/ChevronRight';
|
|
60
|
+
import '@material-ui/core/ButtonBase';
|
|
61
|
+
import '@material-ui/icons/Lens';
|
|
62
|
+
import '@material-ui/icons/HelpOutlineOutlined';
|
|
63
|
+
import 'react-use/esm/useCopyToClipboard';
|
|
64
|
+
import '@material-ui/icons/AssignmentOutlined';
|
|
65
|
+
import '@material-ui/icons/AssignmentTurnedInOutlined';
|
|
66
|
+
import '@material-ui/icons/SentimentVeryDissatisfied';
|
|
67
|
+
import '@material-ui/icons/ArrowDropUp';
|
|
68
|
+
import '@material-ui/icons/ArrowDropDown';
|
|
69
|
+
import 'react-use/esm/useAsync';
|
|
70
|
+
import '@material-ui/core/Menu';
|
|
71
|
+
import '@material-ui/core/MenuItem';
|
|
72
|
+
import '@material-ui/core/Tab';
|
|
73
|
+
import '@material-ui/core/Tabs';
|
|
74
|
+
import '@material-ui/core/MenuList';
|
|
75
|
+
import '@material-ui/core/ListItemIcon';
|
|
76
|
+
import '@material-ui/core/ListItemText';
|
|
77
|
+
import '@material-ui/core/InputLabel';
|
|
78
|
+
import '@material-ui/core/Select';
|
|
79
|
+
import '@material-ui/core/CardContent';
|
|
80
|
+
import '@material-ui/icons/Fullscreen';
|
|
81
|
+
import '@material-ui/core/FormGroup';
|
|
82
|
+
import 'regression';
|
|
83
|
+
|
|
84
|
+
const LabelDataflowInstructionsPage = () => {
|
|
85
|
+
return /* @__PURE__ */ React.createElement(AlertInstructionsLayout, { title: "Investigating Growth" }, /* @__PURE__ */ React.createElement(Typography, { variant: "h1" }, "Labeling Dataflow Jobs"), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "Labels in Google Cloud Platform are key-value pairs that can be added to most types of cloud resources. Since these labels are also exported in billing data, adding labels allows a granular breakdown of cloud cost by software entity."), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "In Cloud Dataflow, labels can be added to a job either programmatically or via the command-line when launching a job. Note that GCP has", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://cloud.google.com/compute/docs/labeling-resources#restrictions" }, "restrictions"), " ", "on the length and characters that can be used in labels."), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "Labels are not retroactive, so cost tracking is only possible from when the labels are first added to a Dataflow job."), /* @__PURE__ */ React.createElement(Box, { mt: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h3" }, "DataflowPipelineOptions"), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "Dataflow jobs using Beam's", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://beam.apache.org/releases/javadoc/2.3.0/org/apache/beam/runners/dataflow/options/DataflowPipelineOptions.html" }, "DataflowPipelineOptions"), " ", "directly can use the ", /* @__PURE__ */ React.createElement("b", null, "setLabels"), " function to add one or more labels:", /* @__PURE__ */ React.createElement(
|
|
86
|
+
CodeSnippet,
|
|
87
|
+
{
|
|
88
|
+
language: "java",
|
|
89
|
+
text: `private DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(DataflowPipelineOptionsImpl.class);
|
|
90
|
+
options.setLabels(ImmutableMap.of("job-id", "my-dataflow-job"));`
|
|
91
|
+
}
|
|
92
|
+
)), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "Dataflow jobs using Scio can similarly set options on the ScioContext:", /* @__PURE__ */ React.createElement(
|
|
93
|
+
CodeSnippet,
|
|
94
|
+
{
|
|
95
|
+
language: "scala",
|
|
96
|
+
text: `val (sc: ScioContext, args: Args) = ContextAndArgs(cmdLineArgs)
|
|
97
|
+
sc.optionsAs[DataflowPipelineOptions].setLabels(Map("job-id" -> "my-dataflow-job").asJava)`
|
|
98
|
+
}
|
|
99
|
+
))), /* @__PURE__ */ React.createElement(Box, { mt: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h3" }, "Command-line"), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "Dataflow jobs launched from the command-line can add labels as an argument:", /* @__PURE__ */ React.createElement(
|
|
100
|
+
CodeSnippet,
|
|
101
|
+
{
|
|
102
|
+
language: "shell",
|
|
103
|
+
text: `--labels={"job-id": "my-dataflow-job", "date-argument": "2020-09-16"}`
|
|
104
|
+
}
|
|
105
|
+
)), /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "For more information on specifying options, see the", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://cloud.google.com/dataflow/docs/guides/specifying-exec-params" }, "Dataflow documentation"), " ", "or", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://spotify.github.io/scio/api/com/spotify/scio/ScioContext.html" }, "Scio Scaladoc"), ".")));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export { LabelDataflowInstructionsPage };
|
|
109
|
+
//# sourceMappingURL=index-BA6m_qFS.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BA6m_qFS.esm.js","sources":["../../src/components/LabelDataflowInstructionsPage/LabelDataflowInstructionsPage.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Box from '@material-ui/core/Box';\nimport Typography from '@material-ui/core/Typography';\nimport { AlertInstructionsLayout } from '../AlertInstructionsLayout';\nimport { CodeSnippet, Link } from '@backstage/core-components';\n\nexport const LabelDataflowInstructionsPage = () => {\n return (\n <AlertInstructionsLayout title=\"Investigating Growth\">\n <Typography variant=\"h1\">Labeling Dataflow Jobs</Typography>\n <Typography paragraph>\n Labels in Google Cloud Platform are key-value pairs that can be added to\n most types of cloud resources. Since these labels are also exported in\n billing data, adding labels allows a granular breakdown of cloud cost by\n software entity.\n </Typography>\n <Typography paragraph>\n In Cloud Dataflow, labels can be added to a job either programmatically\n or via the command-line when launching a job. Note that GCP has{' '}\n <Link to=\"https://cloud.google.com/compute/docs/labeling-resources#restrictions\">\n restrictions\n </Link>{' '}\n on the length and characters that can be used in labels.\n </Typography>\n <Typography paragraph>\n Labels are not retroactive, so cost tracking is only possible from when\n the labels are first added to a Dataflow job.\n </Typography>\n\n <Box mt={4}>\n <Typography variant=\"h3\">DataflowPipelineOptions</Typography>\n <Typography paragraph>\n Dataflow jobs using Beam's{' '}\n <Link to=\"https://beam.apache.org/releases/javadoc/2.3.0/org/apache/beam/runners/dataflow/options/DataflowPipelineOptions.html\">\n DataflowPipelineOptions\n </Link>{' '}\n directly can use the <b>setLabels</b> function to add one or more\n labels:\n <CodeSnippet\n language=\"java\"\n text={`private DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).as(DataflowPipelineOptionsImpl.class); \noptions.setLabels(ImmutableMap.of(\"job-id\", \"my-dataflow-job\"));`}\n />\n </Typography>\n <Typography paragraph>\n Dataflow jobs using Scio can similarly set options on the ScioContext:\n <CodeSnippet\n language=\"scala\"\n text={`val (sc: ScioContext, args: Args) = ContextAndArgs(cmdLineArgs)\nsc.optionsAs[DataflowPipelineOptions].setLabels(Map(\"job-id\" -> \"my-dataflow-job\").asJava)`}\n />\n </Typography>\n </Box>\n\n <Box mt={4}>\n <Typography variant=\"h3\">Command-line</Typography>\n <Typography paragraph>\n Dataflow jobs launched from the command-line can add labels as an\n argument:\n <CodeSnippet\n language=\"shell\"\n text={`--labels={\"job-id\": \"my-dataflow-job\", \"date-argument\": \"2020-09-16\"}`}\n />\n </Typography>\n <Typography paragraph>\n For more information on specifying options, see the{' '}\n <Link to=\"https://cloud.google.com/dataflow/docs/guides/specifying-exec-params\">\n Dataflow documentation\n </Link>{' '}\n or{' '}\n <Link to=\"https://spotify.github.io/scio/api/com/spotify/scio/ScioContext.html\">\n Scio Scaladoc\n </Link>\n .\n </Typography>\n </Box>\n </AlertInstructionsLayout>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBO,MAAM,gCAAgC,MAAM;AACjD,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,uBAAA,EAAA,EAAwB,KAAM,EAAA,sBAAA,EAAA,kBAC5B,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAA,EAAK,wBAAsB,CAAA,kBAC9C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAS,IAAC,EAAA,EAAA,2OAKtB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,yIAAA,EAE4C,GAChE,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,EAAA,EAAG,uEAAwE,EAAA,EAAA,cAEjF,CAAQ,EAAA,GAAA,EAAI,0DAEd,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,EAAA,uHAGtB,CAEA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,EAAA,yBAAuB,mBAC/C,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAS,EAAA,IAAA,EAAA,EAAC,4BACO,EAAA,GAAA,kBAC1B,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAG,sHAAuH,EAAA,EAAA,yBAEhI,CAAQ,EAAA,GAAA,EAAI,uBACS,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAE,EAAA,IAAA,EAAA,WAAS,GAAI,sCAErC,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,MAAA;AAAA,MACT,IAAM,EAAA,CAAA;AAAA,gEAAA,CAAA;AAAA,KAAA;AAAA,GAGV,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,wEAEpB,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,OAAA;AAAA,MACT,IAAM,EAAA,CAAA;AAAA,0FAAA,CAAA;AAAA,KAAA;AAAA,GAGV,CACF,CAAA,kBAEC,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,IAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,QAAK,cAAY,CAAA,sCACpC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,6EAGpB,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,OAAA;AAAA,MACT,IAAM,EAAA,CAAA,qEAAA,CAAA;AAAA,KAAA;AAAA,GAEV,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAS,QAAC,qDACgC,EAAA,GAAA,kBACnD,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,EAAG,EAAA,sEAAA,EAAA,EAAuE,wBAEhF,CAAQ,EAAA,GAAA,EAAI,IACT,EAAA,GAAA,kBACF,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,EAAG,EAAA,sEAAA,EAAA,EAAuE,eAEhF,CAAA,EAAO,GAET,CACF,CACF,CAAA,CAAA;AAEJ;;;;"}
|