Skip to content

Commit 5f2d4dc

Browse files
Add PRs from last week to Grafana docs (#1393)
* docs: fix small typos PR #1385 * Add Azure B2C OAuth example PR #1336 * Document Pod termination fault PR #1381 * Update docs/sources/v0.47.x/javascript-api/xk6-disruptor/faults/pod-termination.md Co-authored-by: Jack Baldry <[email protected]> * Update vus and iterations to code format --------- Co-authored-by: Jack Baldry <[email protected]>
1 parent 5a30f54 commit 5f2d4dc

File tree

10 files changed

+290
-7
lines changed

10 files changed

+290
-7
lines changed

docs/sources/v0.47.x/examples/oauth-authentication.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,207 @@ export function authenticateUsingAzure(tenantId, clientId, clientSecret, scope,
6161

6262
{{< /code >}}
6363

64+
### Azure B2C
65+
66+
The following example shows how you can authenticate with Azure B2C using the [Client Credentials Flow](https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code#client-credentials-flow).
67+
68+
This example is based on a JMeter example found at the [azure-ad-b2c/load-tests](https://github.com/azure-ad-b2c/load-tests) repository.
69+
70+
To use this script, you need to:
71+
72+
1. [Set up your own Azure B2C tenant](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant)
73+
* Copy the tenant name, it will be used in your test script.
74+
1. [Register a web application](https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga)
75+
* Register a single page application with the redirect URL of: https://jwt.ms. That's needed for the flow to receive a token.
76+
* After the creation, you can get the Application (client) ID, and the Directory (tenant) ID. Copy both of them, they'll be used in your test script.
77+
1. [Create a user flow so that you can sign up and create a user](https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows)
78+
* Create a new user, and copy the username and password. They'll be used in the test script.
79+
80+
You can find the settings in the B2C settings in the Azure portal if you need to refer to them later on. Make sure to fill out all the variables for the `B2CGraphSettings` object, as well as replace `USERNAME` and `PASSWORD` in `export default function`.
81+
82+
{{< code >}}
83+
84+
```javascript
85+
import http from "k6/http";
86+
import crypto from "k6/crypto";
87+
import { randomString } from "https://jslib.k6.io/k6-utils/1.2.0/index.js";
88+
89+
const B2CGraphSettings = {
90+
B2C: {
91+
client_id: "", // Application ID in Azure
92+
user_flow_name: "",
93+
tenant_id: "", // Directory ID in Azure
94+
tenant_name: "",
95+
scope: "openid",
96+
redirect_url: "https://jwt.ms",
97+
},
98+
};
99+
100+
/**
101+
* Authenticate using OAuth against Azure B2C
102+
* @function
103+
* @param {string} username - Username of the user to authenticate
104+
* @param {string} password
105+
* @return {string} id_token
106+
*/
107+
export function GetB2cIdToken(username, password) {
108+
const state = GetState();
109+
SelfAsserted(state, username, password);
110+
const code = CombinedSigninAndSignup(state);
111+
return GetToken(code, state.codeVerifier);
112+
}
113+
114+
/**
115+
* @typedef {object} b2cStateProperties
116+
* @property {string} csrfToken
117+
* @property {string} stateProperty
118+
* @property {string} codeVerifier
119+
*
120+
*/
121+
122+
/**
123+
* Get the id token from Azure B2C
124+
* @function
125+
* @param {string} code
126+
* @returns {string} id_token
127+
*/
128+
const GetToken = (code, codeVerifier) => {
129+
const url =
130+
`https://${B2CGraphSettings.B2C.tenant_name}.b2clogin.com/${B2CGraphSettings.B2C.tenant_id}` +
131+
`/oauth2/v2.0/token` +
132+
`?p=${B2CGraphSettings.B2C.user_flow_name}` +
133+
`&client_id=${B2CGraphSettings.B2C.client_id}` +
134+
`&grant_type=authorization_code` +
135+
`&scope=${B2CGraphSettings.B2C.scope}` +
136+
`&code=${code}` +
137+
`&redirect_uri=${B2CGraphSettings.B2C.redirect_url}` +
138+
`&code_verifier=${codeVerifier}`;
139+
140+
const response = http.post(url, "", {
141+
tags: {
142+
b2c_login: "GetToken",
143+
},
144+
});
145+
146+
return JSON.parse(response.body).id_token;
147+
};
148+
149+
/**
150+
* Signs in the user using the CombinedSigninAndSignup policy
151+
* extraqct B2C code from response
152+
* @function
153+
* @param {b2cStateProperties} state
154+
* @returns {string} code
155+
*/
156+
const CombinedSigninAndSignup = (state) => {
157+
const url =
158+
`https://${B2CGraphSettings.B2C.tenant_name}.b2clogin.com/${B2CGraphSettings.B2C.tenant_name}.onmicrosoft.com` +
159+
`/${B2CGraphSettings.B2C.user_flow_name}/api/CombinedSigninAndSignup/confirmed` +
160+
`?csrf_token=${state.csrfToken}` +
161+
`&rememberMe=false` +
162+
`&tx=StateProperties=${state.stateProperty}` +
163+
`&p=${B2CGraphSettings.B2C.user_flow_name}`;
164+
165+
const response = http.get(url, "", {
166+
tags: {
167+
b2c_login: "CombinedSigninAndSignup",
168+
},
169+
});
170+
const codeRegex = '.*code=([^"]*)';
171+
return response.url.match(codeRegex)[1];
172+
};
173+
174+
/**
175+
* Signs in the user using the SelfAsserted policy
176+
* @function
177+
* @param {b2cStateProperties} state
178+
* @param {string} username
179+
* @param {string} password
180+
*/
181+
const SelfAsserted = (state, username, password) => {
182+
const url =
183+
`https://${B2CGraphSettings.B2C.tenant_name}.b2clogin.com/${B2CGraphSettings.B2C.tenant_id}` +
184+
`/${B2CGraphSettings.B2C.user_flow_name}/SelfAsserted` +
185+
`?tx=StateProperties=${state.stateProperty}` +
186+
`&p=${B2CGraphSettings.B2C.user_flow_name}` +
187+
`&request_type=RESPONSE` +
188+
`&email=${username}` +
189+
`&password=${password}`;
190+
191+
const params = {
192+
headers: {
193+
"X-CSRF-TOKEN": `${state.csrfToken}`,
194+
},
195+
tags: {
196+
b2c_login: "SelfAsserted",
197+
},
198+
};
199+
http.post(url, "", params);
200+
};
201+
202+
/**
203+
* Calls the B2C login page to get the state property
204+
* @function
205+
* @returns {b2cStateProperties} b2cState
206+
*/
207+
const GetState = () => {
208+
const nonce = randomString(50);
209+
const challenge = crypto.sha256(nonce.toString(), "base64rawurl");
210+
211+
const url =
212+
`https://${B2CGraphSettings.B2C.tenant_name}.b2clogin.com` +
213+
`/${B2CGraphSettings.B2C.tenant_id}/oauth2/v2.0/authorize?` +
214+
`p=${B2CGraphSettings.B2C.user_flow_name}` +
215+
`&client_id=${B2CGraphSettings.B2C.client_id}` +
216+
`&nonce=${nonce}` +
217+
`&redirect_uri=${B2CGraphSettings.B2C.redirect_url}` +
218+
`&scope=${B2CGraphSettings.B2C.scope}` +
219+
`&response_type=code` +
220+
`&prompt=login` +
221+
`&code_challenge_method=S256` +
222+
`&code_challenge=${challenge}` +
223+
`&response_mode=fragment`;
224+
225+
const response = http.get(url, "", {
226+
tags: {
227+
b2c_login: "GetCookyAndState",
228+
},
229+
});
230+
231+
const vuJar = http.cookieJar();
232+
const responseCookies = vuJar.cookiesForURL(response.url);
233+
234+
const b2cState = {};
235+
b2cState.codeVerifier = nonce;
236+
b2cState.csrfToken = responseCookies["x-ms-cpim-csrf"][0];
237+
b2cState.stateProperty = response.body.match('.*StateProperties=([^"]*)')[1];
238+
return b2cState;
239+
};
240+
241+
/**
242+
* Helper function to get the authorization header for a user
243+
* @param {user} user
244+
* @returns {object} httpsOptions
245+
*/
246+
export const GetAuthorizationHeaderForUser = (user) => {
247+
const token = GetB2cIdToken(user.username, user.password);
248+
249+
return {
250+
headers: {
251+
"Content-Type": "application/json",
252+
Authorization: "Bearer " + token,
253+
},
254+
};
255+
};
256+
257+
export default function () {
258+
const token = GetB2cIdToken("USERNAME", "PASSWORD");
259+
console.log(token);
260+
}
261+
```
262+
263+
{{< /code >}}
264+
64265
### Okta
65266

66267
{{< code >}}

docs/sources/v0.47.x/javascript-api/xk6-disruptor/faults/_index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: 'Faults'
33
excerpt: 'xk6-disruptor: Fault Description'
4-
weight: 01
4+
weight: 100
55
---
66

77
# Faults
@@ -12,3 +12,4 @@ A fault is as an abnormal condition that affects a system component and which ma
1212
| ------------------------------------------------------------------------------------ | ------------------------------------------- |
1313
| [gRPC Fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/grpc) | Fault affecting gRPC requests from a target |
1414
| [HTTP Fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/http) | Fault affecting HTTP requests from a target |
15+
| [Pod Termination Fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/pod-termination) | Fault terminating a number of target Pods |
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
title: 'Pod Termination'
3+
description: 'xk6-disruptor: Pod Termination Fault attributes'
4+
weight: 03
5+
---
6+
7+
# Pod Termination
8+
9+
A Pod Termination Fault allows terminating either a fixed number or a percentage of the pods that matching a selector or back a service.
10+
11+
A Pod Termination fault is defined by the following attributes:
12+
13+
| Attribute | Type | Description |
14+
| ------------- | ------ | --------|
15+
| count | integer or percentage | the number of pods to be terminated. It can be specified as a integer number or as a percentage, for example `30%`, that defines the fraction of target pods to be terminated|
16+
17+
{{% admonition type="note" %}}
18+
19+
If the count is a percentage and there are no enough elements in the target pod list, the number is rounded up.
20+
For example '25%' of a list of 2 target pods will terminate one pod.
21+
If the list of target pods is not empty, at least one pod is always terminated.
22+
23+
{{% /admonition %}}
24+
25+
## Example
26+
27+
This example defines a PorTermination fault that will terminate `30%` of target pods
28+
29+
```javascript
30+
const fault = {
31+
count: '30%'
32+
};
33+
```

docs/sources/v0.47.x/javascript-api/xk6-disruptor/get-started/_index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
title: 'Get started'
33
excerpt: 'xk6-disruptor is an extension that adds fault injection capabilities to k6. Start here to learn the basics and how to use the disruptor'
44
weight: 01
5-
weight: 01
65
---
76

87
# Get started

docs/sources/v0.47.x/javascript-api/xk6-disruptor/poddisruptor/_index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: 'PodDisruptor'
33
excerpt: 'xk6-disruptor: PodDisruptor class'
4-
weight: 02
4+
weight: 200
55
---
66

77
# PodDisruptor
@@ -17,6 +17,7 @@ To construct a `PodDisruptor`, use the [PodDisruptor() constructor](https://graf
1717
| [PodDisruptor.injectGrpcFaults()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/poddisruptor/injectgrpcfaults) | Inject [gRPC faults](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/grpc) in the target Pods |
1818
| [PodDisruptor.injectHTTPFaults()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/poddisruptor/injecthttpfaults) | Inject [HTTP faults](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/http) in the target Pods |
1919
| PodDisruptor.targets() | Returns the list of target Pods of the PodDisruptor |
20+
| [PodDisruptor.terminatePods()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/poddisruptor/terminate-pods) | executes a [Pod Termination fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/pod-termination) in the target Pods |
2021

2122
## Example
2223

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: 'terminatePods()'
3+
description: 'xk6-disruptor: PodDisruptor.terminatePods method'
4+
---
5+
6+
# terminatePods()
7+
8+
`terminatePods` terminates a number of the pods matching the selector configured in the PodDisruptor.
9+
10+
| Parameter | Type | Description |
11+
| --------- | ------ |------- |
12+
| fault | object | description of the [Pod Termination fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/pod-termination) |
13+
14+
## Example
15+
16+
<!-- eslint-skip -->
17+
18+
```javascript
19+
const fault = {
20+
count: 2,
21+
}
22+
disruptor.terminatePods(fault)
23+
```

docs/sources/v0.47.x/javascript-api/xk6-disruptor/servicedisruptor/_index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: 'ServiceDisruptor'
33
excerpt: 'xk6-disruptor: ServiceDisruptor class'
4-
weight: 03
4+
weight: 300
55
---
66

77
# ServiceDisruptor
@@ -16,6 +16,8 @@ To construct a `ServiceDisruptor`, use the [ServiceDisruptor() constructor](http
1616
| ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
1717
| [ServiceDisruptor.injectGrpcFaults()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/servicedisruptor/injectgrpcfaults) | Inject [gRPC faults](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/grpc) in the target Pods |
1818
| [ServiceDisruptor.injectHTTPFaults()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/servicedisruptor/injecthttpfaults) | Inject [HTTTP faults](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/http) in the target Pods |
19+
| ServiceDisruptor.targets() | Returns the list of target Pods of the ServiceDisruptor |
20+
| [ServiceDisruptor.terminatePods()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/servicedisruptor/terminate-pods) | executes a [Pod Termination fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/pod-termination) in the target Pods|
1921

2022
## Example
2123

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: 'terminatePods()'
3+
description: 'xk6-disruptor: ServiceDisruptor.terminatePods method'
4+
---
5+
6+
# terminatePods()
7+
8+
`terminatePods` terminates a number of pods that belong to the service specified in the ServiceDisruptor.
9+
10+
| Parameter | Type | Description |
11+
| --------- | ------ |------- |
12+
| fault | object | description of the [Pod Termination fault](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/xk6-disruptor/faults/pod-termination) |
13+
14+
## Example
15+
16+
<!-- eslint-skip -->
17+
18+
```javascript
19+
const fault = {
20+
count: 2,
21+
}
22+
disruptor.terminatePods(fault)
23+
```

docs/sources/v0.47.x/results-output/end-of-test/custom-summary.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ They determine where k6 displays or saves the content:
7272

7373
The value of a key can have a type of either `string` or [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).
7474

75-
You can return mutiple summary outputs in a script.
75+
You can return multiple summary outputs in a script.
7676
As an example, this `return` statement sends a report to standard output and writes the `data` object to a JSON file.
7777

7878
{{< code >}}

docs/sources/v0.47.x/using-k6/scenarios/executors/shared-iterations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ weight: 01
99
The `shared-iterations` executor shares iterations between the number of VUs.
1010
The test ends once k6 executes all iterations.
1111

12-
For a shortcut to this executor, use the [vus](https://grafana.com/docs/k6/<K6_VERSION>/using-k6/k6-options/reference#vus) and [iterations](https://grafana.com/docs/k6/<K6_VERSION>/using-k6/k6-options/reference#iterations) options.
12+
For a shortcut to this executor, use the [`vus`](https://grafana.com/docs/k6/<K6_VERSION>/using-k6/k6-options/reference#vus) and [`iterations`](https://grafana.com/docs/k6/<K6_VERSION>/using-k6/k6-options/reference#iterations) options.
1313

1414
{{% admonition type="note" %}}
1515

@@ -37,7 +37,7 @@ This executor is suitable when you want a specific number of VUs to complete a f
3737
number of total iterations, and the amount of iterations per VU is unimportant.
3838
If the **time to complete** a number of test iterations is your concern, this executor should perform best.
3939

40-
An example use case is for quick performance tests in the developement build cycle.
40+
An example use case is for quick performance tests in the development build cycle.
4141
As developers make changes, they might run the test against the local code to test for performance regressions.
4242
Thus the executor works well with a _shift-left_ policy, where emphasizes testing performance early in the development cycle, when the cost of a fix is lowest.
4343

0 commit comments

Comments
 (0)