From 50921f6fa011142b9caeb2546f896cb6a6f85bf5 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 3 Nov 2025 18:48:30 +0000 Subject: [PATCH] fix: Build the ADRs in doc Reorder the doc to also build and include ADR records and add unrelated improvement to the readme. --- README.md | 71 +++++++++++++++++++++---- doc/book.toml | 2 +- doc/src/SUMMARY.md | 23 +++++--- doc/src/adr/0002-open-policy-agent.md | 2 +- doc/src/adr/0004-v4-api.md | 4 +- doc/src/adr/0005-auth-passkey.md | 3 +- doc/src/adr/0007-federation-mapping.md | 3 +- doc/src/adr/0008-workload-federation.md | 2 +- doc/src/adr/index.md | 12 ++--- doc/src/intro.md | 70 +++++++++++++++++++----- doc/src/oidc.md | 2 +- loadtest/report_py.html | 28 +++++----- loadtest/report_python_server.html | 28 +++++----- loadtest/report_rust.html | 28 +++++----- loadtest/report_rust_server.html | 28 +++++----- typos.toml | 2 +- 16 files changed, 202 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 0fa58eb2..16099243 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,65 @@ # OpenStack Keystone in Rust -Successor to the OpenStack Keystone written in Rust. - -This project aims at implementing OpenStack Identity service using the Rust as -the programming language. It focuses on implementing v4 API, while certain set -of the v3 API is also going to be implemented making transition easier. - -As of now it can be easily deployed in parallel to the python Keystone just by -forwarding v3 APIs to the python Keystone and v4 APIs to the rust -implementation. +The legacy Keystone identity service (written in Python and maintained upstream +by OpenStack Foundation) has served the OpenStack ecosystem reliably for years. +It handles authentication, authorization, token issuance, service catalog, +project/tenant management, and federation services across thousands of +deployments. However, as we embarked on adding next-generation identity +features—such as native WebAuthn (“passkeys”), modern federation flows, direct +OIDC support, JWT login, workload authorization, restricted tokens and +service-accounts—it became clear that certain design and performance +limitations of the Python codebase would hamper efficient implementation of +these new features. + +Consequently, we initiated a project termed “Keystone-NG”: a Rust-based +component that augments rather than fully replaces the existing Keystone +service. The original plan was to implement only the new feature-set in Rust +and route those new API paths to the Rust component, while keeping the core +Python Keystone service in place for existing users and workflows. + +As development progressed, however, the breadth of new functionality (and the +opportunity to revisit some of the existing limitations) led to a partial +re-implementation of certain core identity flows in Rust. This allows us to +benefit from Rust’s memory safety, concurrency model, performance, and modern +tooling, while still preserving the upstream Keystone Python service as the +canonical “master” identity service, routing only the new endpoints and +capabilities through the Rust component. + +In practice, this architecture means: + +- The upstream Python Keystone remains the main identity interface, preserving + backward compatibility, integration with other OpenStack services, existing + user workflows, catalogs, policies and plugins. + +- The Rust “Keystone-NG” component handles new functionality, specifically: + + - Native WebAuthN (passkeys) support for passwordless / phishing-resistant MFA + + - A reworked federation service, enabling modern identity brokering and + advanced federation semantics OIDC (OpenID Connect) Direct in Keystone, + enabling Keystone to act as an OIDC Provider or integrate with external + OIDC identity providers natively JWT login flows, enabling stateless, + compact tokens suitable for new micro-services, CLI, SDK, and + workload-to-workload scenarios + + - Workload Authorization, designed for service-to-service authorization in + cloud native contexts (not just human users) + + - Restricted Tokens and Service Accounts, which allow fine-grained, + limited‐scope credentials for automation, agents, and service accounts, + with explicit constraints and expiry + +By routing only the new flows through the Rust component we preserve the +stability and ecosystem compatibility of Keystone, while enabling a +forward-looking identity architecture. Over time, additional identity flows +may be migrated or refactored into the Rust component as needed, but our +current objective is to retain the existing Keystone Python implementation as +the trusted, mature baseline and incrementally build the “Keystone-NG” Rust +service as the complement. + +We believe this approach allows the best of both worlds: the trusted maturity +of Keystone’s Python code-base, combined with the modern, high-safety, +high-performance capabilities of Rust where they matter most. ## Config @@ -34,7 +85,7 @@ throughput (RPS). For every PR load test suite is being executed. It is absolutely clear that the Rust implementation currently misses certain things original Keystone doe, but -the gap is being closed over the time. However test shows difference of factor +the gap is being closed over the time. However test shows difference of factor **10-100** which is already remarkable. New tests will appear to have a more thorough coverage of the exposed API. diff --git a/doc/book.toml b/doc/book.toml index c6fa18fd..51656500 100644 --- a/doc/book.toml +++ b/doc/book.toml @@ -13,7 +13,7 @@ create-missing = false [output.html.fold] enable = true -level = 2 +level = 1 [preprocessor] diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 0ba0a807..acbabb88 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -5,11 +5,26 @@ --- -[Architecture](./architecture.md) -[Policy enforcement](./policy.md) +# Keystone internals + +* [Architecture](./architecture.md) + * [Architecture decision records](adr/index.md) + * [Record architecture decisions](adr/0001-record-architecture-decisions.md) + * [Open Policy Agent](adr/0002-open-policy-agent.md) + * [Sea ORM](adr/0003-sea-orm.md) + * [v4 API](adr/0004-v4-api.md) + * [Passkey Auth](adr/0005-auth-passkey.md) + * [Federation IDP](adr/0006-federation-idp.md) + * [Federation Mapping](adr/0007-federation-mapping.md) + * [Workload Federation](adr/0008-workload-federation.md) +* [Policy enforcement](./policy.md) +* [Fernet token]() + * [Token payloads]() --- +# Features + - [Federation](./federation.md) - [Oidc RP mode](./oidc.md) - [JWT](./jwt.md) @@ -18,8 +33,4 @@ --- -[Architecture Decision Records](adr/index.md) - ---- - [Performance comparison](./performance.md) diff --git a/doc/src/adr/0002-open-policy-agent.md b/doc/src/adr/0002-open-policy-agent.md index 90efca80..8d136b9e 100644 --- a/doc/src/adr/0002-open-policy-agent.md +++ b/doc/src/adr/0002-open-policy-agent.md @@ -38,7 +38,7 @@ Engine. ## Consequences -- Policy evaluation requires external service (OPA) to be running. +- Policy evaluation requires external service (OPA) to be running. - When covering existing functionality of the python Keystone policies SHOULD be converted as is and do not introduce a changed flow. diff --git a/doc/src/adr/0004-v4-api.md b/doc/src/adr/0004-v4-api.md index 3b43b975..f5a31a3e 100644 --- a/doc/src/adr/0004-v4-api.md +++ b/doc/src/adr/0004-v4-api.md @@ -12,11 +12,11 @@ New authentication workflows cannot be covered with the existing Keystone v3 API. As such it is required to add new API methods and eventually change the existing. As such not to break compatibility and provide a relatively easy way to route the traffic allowing both project (python and rust) to co-exist a new -v4 API version should be introduced. +v4 API version should be introduced. ## Decision -- All new auth methods MUST be implemented in v4. +- All new auth methods MUST be implemented in v4. - Known issues with the v3 API SHOULD be addressed in the v3. diff --git a/doc/src/adr/0005-auth-passkey.md b/doc/src/adr/0005-auth-passkey.md index 465adef9..6997a145 100644 --- a/doc/src/adr/0005-auth-passkey.md +++ b/doc/src/adr/0005-auth-passkey.md @@ -12,7 +12,7 @@ Nowadays password-less authentication becomes standard. In OpenStack it is at the moment not implemented whether on the API level (for the CLI) nor on the UI. [Webauthn](https://webauthn.io/) is a well accepted standard for implementing -password-less authentication with the help of hardware or software +password-less authentication with the help of hardware or software authenticators. Keystone should implement support for new authentication methods relying on the webauthn. @@ -40,4 +40,3 @@ state. New authentication method allows users to get valid token without requiring user to pass any secrets on the wire. Overall security of the system is increased. - diff --git a/doc/src/adr/0007-federation-mapping.md b/doc/src/adr/0007-federation-mapping.md index 5d106b9f..a828c003 100644 --- a/doc/src/adr/0007-federation-mapping.md +++ b/doc/src/adr/0007-federation-mapping.md @@ -21,7 +21,7 @@ for Keystone. "Mapping" (attribute mapping) MUST describe how the information from OIDC claims need to be translated into the Keystone data model. It MUST also describe -user defined bounds to allow use restriction. +user defined bounds to allow use restriction. When `domain_id` is not being set on the IdP level it MUST be defined either on the mapping entry, or the mapping MUST define `domain_id_claim` to extract the @@ -38,4 +38,3 @@ used. - Mappings MUST be configured carefully to prevent login of users across the domain borders. `bound_xxx` should be used extensively to guard this. - diff --git a/doc/src/adr/0008-workload-federation.md b/doc/src/adr/0008-workload-federation.md index b71326b3..3125d83b 100644 --- a/doc/src/adr/0008-workload-federation.md +++ b/doc/src/adr/0008-workload-federation.md @@ -14,7 +14,7 @@ platform which the service provider can trust. This is very similar (and technically relates) to the OIDC standard. In the JWT flow the "user" is exchanging a JWT token issued by the trusted -IdP for a Keystone token. This authentication response includes a token and a +IdP for a Keystone token. This authentication response includes a token and a service catalog to provide a known OpenStack usage scenario. ## Decision diff --git a/doc/src/adr/index.md b/doc/src/adr/index.md index 209898d3..1435497d 100644 --- a/doc/src/adr/index.md +++ b/doc/src/adr/index.md @@ -1,10 +1,4 @@ -# Architecture decision records +# Architecture Decision Records -* [1. Record architecture decisions](0001-record-architecture-decisions.md) -* [2. Open Policy Agent](0002-open-policy-agent.md) -* [3. Sea ORM](0003-sea-orm.md) -* [4. v4 API](0004-v4-api.md) -* [5. Passkey Auth](0005-auth-passkey.md) -* [6. Federation IDP](0006-federation-idp.md) -* [7. Federation Mapping](0007-federation-mapping.md) -* [8. Workload Federation](0008-workload-federation.md) +Keystone project uses Architecture Decision Records to describe why the software +is built how it is built. diff --git a/doc/src/intro.md b/doc/src/intro.md index daff840e..bae750cd 100644 --- a/doc/src/intro.md +++ b/doc/src/intro.md @@ -1,23 +1,65 @@ # OpenStack Keystone in Rust -What happens if OpenStack Keystone would be rewritten in Rust? Is it possible? -How complex is it? Which improvements are possible? +The legacy Keystone identity service (written in Python and maintained upstream +by OpenStack Foundation) has served the OpenStack ecosystem reliably for years. +It handles authentication, authorization, token issuance, service catalog, +project/tenant management, and federation services across thousands of +deployments. However, as we embarked on adding next-generation identity +features—such as native WebAuthn (“passkeys”), modern federation flows, direct +OIDC support, JWT login, workload authorization, restricted tokens and +service-accounts—it became clear that certain design and performance +limitations of the Python codebase would hamper efficient implementation of +these new features. -This project exists to answer this questions. +Consequently, we initiated a project termed “Keystone-NG”: a Rust-based +component that augments rather than fully replaces the existing Keystone +service. The original plan was to implement only the new feature-set in Rust +and route those new API paths to the Rust component, while keeping the core +Python Keystone service in place for existing users and workflows. -Primary target of the project is to implement a Rust library implementing -Keystone functionality to be able to split a Keystone monolith into smaller -pieces (similar to the microservices). Once this is done, adding an API is -becoming also pretty simple. +As development progressed, however, the breadth of new functionality (and the +opportunity to revisit some of the existing limitations) led to a partial +re-implementation of certain core identity flows in Rust. This allows us to +benefit from Rust’s memory safety, concurrency model, performance, and modern +tooling, while still preserving the upstream Keystone Python service as the +canonical “master” identity service, routing only the new endpoints and +capabilities through the Rust component. -It targets deploying Python and Rust implementation in parallel and do request -routing on the web server level to get the speed and security of Rust -implementation while keeping functions not implemented (yet) being served by the -original Keystone. This approach also makes it possible to deploy Rust -implementation in parallel to a much older version of Keystone giving -possibility for the operators to enable new features while still using older -version of Keystone (whatever the reason for that is). +In practice, this architecture means: +- The upstream Python Keystone remains the main identity interface, preserving + backward compatibility, integration with other OpenStack services, existing + user workflows, catalogs, policies and plugins. + +- The Rust “Keystone-NG” component handles new functionality, specifically: + + - Native WebAuthN (passkeys) support for passwordless / phishing-resistant MFA + + - A reworked federation service, enabling modern identity brokering and + advanced federation semantics OIDC (OpenID Connect) Direct in Keystone, + enabling Keystone to act as an OIDC Provider or integrate with external + OIDC identity providers natively JWT login flows, enabling stateless, + compact tokens suitable for new micro-services, CLI, SDK, and + workload-to-workload scenarios + + - Workload Authorization, designed for service-to-service authorization in + cloud native contexts (not just human users) + + - Restricted Tokens and Service Accounts, which allow fine-grained, + limited‐scope credentials for automation, agents, and service accounts, + with explicit constraints and expiry + +By routing only the new flows through the Rust component we preserve the +stability and ecosystem compatibility of Keystone, while enabling a +forward-looking identity architecture. Over time, additional identity flows +may be migrated or refactored into the Rust component as needed, but our +current objective is to retain the existing Keystone Python implementation as +the trusted, mature baseline and incrementally build the “Keystone-NG” Rust +service as the complement. + +We believe this approach allows the best of both worlds: the trusted maturity +of Keystone’s Python code-base, combined with the modern, high-safety, +high-performance capabilities of Rust where they matter most. ## Compatibility diff --git a/doc/src/oidc.md b/doc/src/oidc.md index 6fcb11e5..987b0b28 100644 --- a/doc/src/oidc.md +++ b/doc/src/oidc.md @@ -155,7 +155,7 @@ be set. For the sake of example simplicity domains are modelled as user groups in Keycloak. Such group gets the attribute with the value of the domain_id. Users belonging to such group inherit this attribute automatically. Alternatively every user may be extended with the domain_id attribute -individually. +individually. Keycloak can be used as an Identity provider by the Keystone. diff --git a/loadtest/report_py.html b/loadtest/report_py.html index 80b75fc5..2cfb9505 100644 --- a/loadtest/report_py.html +++ b/loadtest/report_py.html @@ -136,7 +136,7 @@

Request Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -204,7 +204,7 @@

Request Metrics

}, data: [["2025-02-17 08:19:14",3],["2025-02-17 08:19:15",4],["2025-02-17 08:19:16",8],["2025-02-17 08:19:17",9],["2025-02-17 08:19:18",12],["2025-02-17 08:19:19",15],["2025-02-17 08:19:20",13],["2025-02-17 08:19:21",8],["2025-02-17 08:19:22",12],["2025-02-17 08:19:23",16],["2025-02-17 08:19:24",16],["2025-02-17 08:19:25",17],["2025-02-17 08:19:26",13],["2025-02-17 08:19:27",11],["2025-02-17 08:19:28",15],["2025-02-17 08:19:29",10],["2025-02-17 08:19:30",14],["2025-02-17 08:19:31",9],["2025-02-17 08:19:32",12],["2025-02-17 08:19:33",11],["2025-02-17 08:19:34",11],["2025-02-17 08:19:35",18],["2025-02-17 08:19:36",13],["2025-02-17 08:19:37",10],["2025-02-17 08:19:38",14],["2025-02-17 08:19:39",10],["2025-02-17 08:19:40",16],["2025-02-17 08:19:41",16]], }, - + ] }); @@ -251,7 +251,7 @@

Request Metrics

- +

Response Time Metrics

@@ -302,7 +302,7 @@

Response Time Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -370,7 +370,7 @@

Response Time Metrics

}, data: [["2025-02-17 08:19:14",533.0],["2025-02-17 08:19:15",503.25],["2025-02-17 08:19:16",381.0],["2025-02-17 08:19:17",429.8888854980469],["2025-02-17 08:19:18",468.08331298828125],["2025-02-17 08:19:19",481.39996337890625],["2025-02-17 08:19:20",628.84619140625],["2025-02-17 08:19:21",970.5],["2025-02-17 08:19:22",560.75],["2025-02-17 08:19:23",556.8124389648438],["2025-02-17 08:19:24",495.1249694824219],["2025-02-17 08:19:25",459.23529052734375],["2025-02-17 08:19:26",592.1538696289062],["2025-02-17 08:19:27",686.0908813476562],["2025-02-17 08:19:28",659.6000366210938],["2025-02-17 08:19:29",689.3999633789062],["2025-02-17 08:19:30",649.357177734375],["2025-02-17 08:19:31",867.5555419921875],["2025-02-17 08:19:32",736.6666870117188],["2025-02-17 08:19:33",568.5454711914062],["2025-02-17 08:19:34",580.8181762695312],["2025-02-17 08:19:35",521.3888549804688],["2025-02-17 08:19:36",719.3077392578125],["2025-02-17 08:19:37",833.5999755859375],["2025-02-17 08:19:38",634.4285888671875],["2025-02-17 08:19:39",527.2999877929688],["2025-02-17 08:19:40",477.0625],["2025-02-17 08:19:41",600.3124389648438]], }, - + ] }); @@ -420,7 +420,7 @@

Response Time Metrics

- +

Status Code Metrics

@@ -496,7 +496,7 @@

Transaction Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -564,7 +564,7 @@

Transaction Metrics

}, data: [["2025-02-17 08:19:14",3],["2025-02-17 08:19:15",4],["2025-02-17 08:19:16",8],["2025-02-17 08:19:17",9],["2025-02-17 08:19:18",12],["2025-02-17 08:19:19",15],["2025-02-17 08:19:20",13],["2025-02-17 08:19:21",8],["2025-02-17 08:19:22",12],["2025-02-17 08:19:23",16],["2025-02-17 08:19:24",16],["2025-02-17 08:19:25",17],["2025-02-17 08:19:26",13],["2025-02-17 08:19:27",11],["2025-02-17 08:19:28",15],["2025-02-17 08:19:29",10],["2025-02-17 08:19:30",14],["2025-02-17 08:19:31",9],["2025-02-17 08:19:32",12],["2025-02-17 08:19:33",11],["2025-02-17 08:19:34",11],["2025-02-17 08:19:35",18],["2025-02-17 08:19:36",13],["2025-02-17 08:19:37",10],["2025-02-17 08:19:38",14],["2025-02-17 08:19:39",10],["2025-02-17 08:19:40",16],["2025-02-17 08:19:41",16]], }, - + ] }); @@ -660,7 +660,7 @@

Scenario Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -728,7 +728,7 @@

Scenario Metrics

}, data: [["2025-02-17 08:19:14",2],["2025-02-17 08:19:15",3],["2025-02-17 08:19:16",7],["2025-02-17 08:19:17",8],["2025-02-17 08:19:18",11],["2025-02-17 08:19:19",14],["2025-02-17 08:19:20",12],["2025-02-17 08:19:21",7],["2025-02-17 08:19:22",12],["2025-02-17 08:19:23",16],["2025-02-17 08:19:24",16],["2025-02-17 08:19:25",17],["2025-02-17 08:19:26",13],["2025-02-17 08:19:27",11],["2025-02-17 08:19:28",15],["2025-02-17 08:19:29",10],["2025-02-17 08:19:30",14],["2025-02-17 08:19:31",9],["2025-02-17 08:19:32",12],["2025-02-17 08:19:33",11],["2025-02-17 08:19:34",11],["2025-02-17 08:19:35",18],["2025-02-17 08:19:36",13],["2025-02-17 08:19:37",10],["2025-02-17 08:19:38",14],["2025-02-17 08:19:39",10],["2025-02-17 08:19:40",16],["2025-02-17 08:19:41",16]], }, - + ] }); @@ -820,7 +820,7 @@

User Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -888,15 +888,15 @@

User Metrics

}, data: [["2025-02-17 08:19:14",8],["2025-02-17 08:19:15",8],["2025-02-17 08:19:16",8],["2025-02-17 08:19:17",8],["2025-02-17 08:19:18",8],["2025-02-17 08:19:19",8],["2025-02-17 08:19:20",8],["2025-02-17 08:19:21",8],["2025-02-17 08:19:22",8],["2025-02-17 08:19:23",8],["2025-02-17 08:19:24",8],["2025-02-17 08:19:25",8],["2025-02-17 08:19:26",8],["2025-02-17 08:19:27",8],["2025-02-17 08:19:28",8],["2025-02-17 08:19:29",8],["2025-02-17 08:19:30",8],["2025-02-17 08:19:31",8],["2025-02-17 08:19:32",8],["2025-02-17 08:19:33",8],["2025-02-17 08:19:34",0]], }, - + ] });
- + - \ No newline at end of file + diff --git a/loadtest/report_python_server.html b/loadtest/report_python_server.html index 6a8abc71..e0d30016 100644 --- a/loadtest/report_python_server.html +++ b/loadtest/report_python_server.html @@ -137,7 +137,7 @@

Request Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -205,7 +205,7 @@

Request Metrics

}, data: [["2025-03-25 14:10:24",51],["2025-03-25 14:10:25",152],["2025-03-25 14:10:26",190],["2025-03-25 14:10:27",184],["2025-03-25 14:10:28",175],["2025-03-25 14:10:29",182],["2025-03-25 14:10:30",171],["2025-03-25 14:10:31",183],["2025-03-25 14:10:32",177],["2025-03-25 14:10:33",184],["2025-03-25 14:10:34",173],["2025-03-25 14:10:35",184],["2025-03-25 14:10:36",189],["2025-03-25 14:10:37",199],["2025-03-25 14:10:38",196],["2025-03-25 14:10:39",192],["2025-03-25 14:10:40",197],["2025-03-25 14:10:41",195],["2025-03-25 14:10:42",203],["2025-03-25 14:10:43",192],["2025-03-25 14:10:44",177],["2025-03-25 14:10:45",187],["2025-03-25 14:10:46",160],["2025-03-25 14:10:47",155],["2025-03-25 14:10:48",172],["2025-03-25 14:10:49",190],["2025-03-25 14:10:50",196],["2025-03-25 14:10:51",199],["2025-03-25 14:10:52",196],["2025-03-25 14:10:53",192],["2025-03-25 14:10:54",182],["2025-03-25 14:10:55",181],["2025-03-25 14:10:56",187],["2025-03-25 14:10:57",192],["2025-03-25 14:10:58",179],["2025-03-25 14:10:59",188],["2025-03-25 14:11:00",184],["2025-03-25 14:11:01",176],["2025-03-25 14:11:02",180],["2025-03-25 14:11:03",181],["2025-03-25 14:11:04",189],["2025-03-25 14:11:05",203],["2025-03-25 14:11:06",207],["2025-03-25 14:11:07",208],["2025-03-25 14:11:08",206],["2025-03-25 14:11:09",201],["2025-03-25 14:11:10",177],["2025-03-25 14:11:11",175],["2025-03-25 14:11:12",184],["2025-03-25 14:11:13",181],["2025-03-25 14:11:14",181],["2025-03-25 14:11:15",199],["2025-03-25 14:11:16",121],["2025-03-25 14:11:17",4]], }, - + ] }); @@ -252,7 +252,7 @@

Request Metrics

- +

Response Time Metrics

@@ -303,7 +303,7 @@

Response Time Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -371,7 +371,7 @@

Response Time Metrics

}, data: [["2025-03-25 14:10:24",19.411762237548828],["2025-03-25 14:10:25",12.23684024810791],["2025-03-25 14:10:26",14.89473819732666],["2025-03-25 14:10:27",20.657604217529297],["2025-03-25 14:10:28",27.199996948242188],["2025-03-25 14:10:29",31.258241653442383],["2025-03-25 14:10:30",39.4970703125],["2025-03-25 14:10:31",41.59016799926758],["2025-03-25 14:10:32",48.48023223876953],["2025-03-25 14:10:33",52.652164459228516],["2025-03-25 14:10:34",60.6242790222168],["2025-03-25 14:10:35",62.913028717041016],["2025-03-25 14:10:36",65.68782043457031],["2025-03-25 14:10:37",67.336669921875],["2025-03-25 14:10:38",74.1173324584961],["2025-03-25 14:10:39",76.47396087646484],["2025-03-25 14:10:40",81.18273162841797],["2025-03-25 14:10:41",85.89232635498047],["2025-03-25 14:10:42",87.75858306884766],["2025-03-25 14:10:43",98.4687728881836],["2025-03-25 14:10:44",112.47457122802734],["2025-03-25 14:10:45",112.28340148925781],["2025-03-25 14:10:46",135.70623779296875],["2025-03-25 14:10:47",143.6903076171875],["2025-03-25 14:10:48",137.3778839111328],["2025-03-25 14:10:49",128.6052703857422],["2025-03-25 14:10:50",130.87754821777344],["2025-03-25 14:10:51",132.72865295410156],["2025-03-25 14:10:52",139.71437072753906],["2025-03-25 14:10:53",147.4270782470703],["2025-03-25 14:10:54",162.24725341796875],["2025-03-25 14:10:55",168.69061279296875],["2025-03-25 14:10:56",167.94110107421875],["2025-03-25 14:10:57",167.32815551757812],["2025-03-25 14:10:58",174.6592559814453],["2025-03-25 14:10:59",169.55316162109375],["2025-03-25 14:11:00",176.57061767578125],["2025-03-25 14:11:01",180.59088134765625],["2025-03-25 14:11:02",175.711181640625],["2025-03-25 14:11:03",178.60223388671875],["2025-03-25 14:11:04",164.34922790527344],["2025-03-25 14:11:05",157.67984008789062],["2025-03-25 14:11:06",153.32850646972656],["2025-03-25 14:11:07",153.21151733398438],["2025-03-25 14:11:08",155.7864532470703],["2025-03-25 14:11:09",160.44776916503906],["2025-03-25 14:11:10",178.63275146484375],["2025-03-25 14:11:11",183.9542999267578],["2025-03-25 14:11:12",173.4347686767578],["2025-03-25 14:11:13",173.93373107910156],["2025-03-25 14:11:14",174.8453369140625],["2025-03-25 14:11:15",162.02516174316406],["2025-03-25 14:11:16",156.1487274169922],["2025-03-25 14:11:17",157.0]], }, - + ] }); @@ -421,7 +421,7 @@

Response Time Metrics

- +

Status Code Metrics

@@ -497,7 +497,7 @@

Transaction Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -565,7 +565,7 @@

Transaction Metrics

}, data: [["2025-03-25 14:10:24",51],["2025-03-25 14:10:25",152],["2025-03-25 14:10:26",190],["2025-03-25 14:10:27",184],["2025-03-25 14:10:28",175],["2025-03-25 14:10:29",182],["2025-03-25 14:10:30",171],["2025-03-25 14:10:31",183],["2025-03-25 14:10:32",177],["2025-03-25 14:10:33",184],["2025-03-25 14:10:34",173],["2025-03-25 14:10:35",184],["2025-03-25 14:10:36",189],["2025-03-25 14:10:37",199],["2025-03-25 14:10:38",196],["2025-03-25 14:10:39",192],["2025-03-25 14:10:40",197],["2025-03-25 14:10:41",195],["2025-03-25 14:10:42",203],["2025-03-25 14:10:43",192],["2025-03-25 14:10:44",177],["2025-03-25 14:10:45",187],["2025-03-25 14:10:46",160],["2025-03-25 14:10:47",155],["2025-03-25 14:10:48",172],["2025-03-25 14:10:49",190],["2025-03-25 14:10:50",196],["2025-03-25 14:10:51",199],["2025-03-25 14:10:52",196],["2025-03-25 14:10:53",192],["2025-03-25 14:10:54",182],["2025-03-25 14:10:55",181],["2025-03-25 14:10:56",187],["2025-03-25 14:10:57",192],["2025-03-25 14:10:58",179],["2025-03-25 14:10:59",188],["2025-03-25 14:11:00",184],["2025-03-25 14:11:01",177],["2025-03-25 14:11:02",179],["2025-03-25 14:11:03",181],["2025-03-25 14:11:04",189],["2025-03-25 14:11:05",203],["2025-03-25 14:11:06",207],["2025-03-25 14:11:07",208],["2025-03-25 14:11:08",206],["2025-03-25 14:11:09",201],["2025-03-25 14:11:10",177],["2025-03-25 14:11:11",175],["2025-03-25 14:11:12",184],["2025-03-25 14:11:13",181],["2025-03-25 14:11:14",181],["2025-03-25 14:11:15",199],["2025-03-25 14:11:16",121],["2025-03-25 14:11:17",4]], }, - + ] }); @@ -661,7 +661,7 @@

Scenario Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -729,7 +729,7 @@

Scenario Metrics

}, data: [["2025-03-25 14:10:24",50],["2025-03-25 14:10:25",151],["2025-03-25 14:10:26",189],["2025-03-25 14:10:27",183],["2025-03-25 14:10:28",174],["2025-03-25 14:10:29",181],["2025-03-25 14:10:30",170],["2025-03-25 14:10:31",182],["2025-03-25 14:10:32",176],["2025-03-25 14:10:33",183],["2025-03-25 14:10:34",172],["2025-03-25 14:10:35",183],["2025-03-25 14:10:36",188],["2025-03-25 14:10:37",198],["2025-03-25 14:10:38",195],["2025-03-25 14:10:39",192],["2025-03-25 14:10:40",196],["2025-03-25 14:10:41",194],["2025-03-25 14:10:42",202],["2025-03-25 14:10:43",191],["2025-03-25 14:10:44",176],["2025-03-25 14:10:45",186],["2025-03-25 14:10:46",159],["2025-03-25 14:10:47",154],["2025-03-25 14:10:48",171],["2025-03-25 14:10:49",189],["2025-03-25 14:10:50",195],["2025-03-25 14:10:51",198],["2025-03-25 14:10:52",195],["2025-03-25 14:10:53",191],["2025-03-25 14:10:54",181],["2025-03-25 14:10:55",180],["2025-03-25 14:10:56",186],["2025-03-25 14:10:57",192],["2025-03-25 14:10:58",179],["2025-03-25 14:10:59",188],["2025-03-25 14:11:00",184],["2025-03-25 14:11:01",177],["2025-03-25 14:11:02",179],["2025-03-25 14:11:03",181],["2025-03-25 14:11:04",189],["2025-03-25 14:11:05",203],["2025-03-25 14:11:06",207],["2025-03-25 14:11:07",208],["2025-03-25 14:11:08",206],["2025-03-25 14:11:09",201],["2025-03-25 14:11:10",177],["2025-03-25 14:11:11",175],["2025-03-25 14:11:12",184],["2025-03-25 14:11:13",181],["2025-03-25 14:11:14",181],["2025-03-25 14:11:15",199],["2025-03-25 14:11:16",121],["2025-03-25 14:11:17",4]], }, - + ] }); @@ -821,7 +821,7 @@

User Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -889,7 +889,7 @@

User Metrics

}, data: [["2025-03-25 14:10:24",32],["2025-03-25 14:10:25",32],["2025-03-25 14:10:26",32],["2025-03-25 14:10:27",32],["2025-03-25 14:10:28",32],["2025-03-25 14:10:29",32],["2025-03-25 14:10:30",32],["2025-03-25 14:10:31",32],["2025-03-25 14:10:32",32],["2025-03-25 14:10:33",32],["2025-03-25 14:10:34",32],["2025-03-25 14:10:35",32],["2025-03-25 14:10:36",32],["2025-03-25 14:10:37",32],["2025-03-25 14:10:38",32],["2025-03-25 14:10:39",32],["2025-03-25 14:10:40",32],["2025-03-25 14:10:41",32],["2025-03-25 14:10:42",32],["2025-03-25 14:10:43",32],["2025-03-25 14:10:45",22],["2025-03-25 14:10:46",23],["2025-03-25 14:10:47",24],["2025-03-25 14:10:48",25],["2025-03-25 14:10:49",26],["2025-03-25 14:10:50",27],["2025-03-25 14:10:51",28],["2025-03-25 14:10:52",29],["2025-03-25 14:10:53",30],["2025-03-25 14:10:54",31],["2025-03-25 14:10:55",32]], }, - + ] }); @@ -909,11 +909,11 @@

Errors

- +
- \ No newline at end of file + diff --git a/loadtest/report_rust.html b/loadtest/report_rust.html index 2d925ae7..1baa2340 100644 --- a/loadtest/report_rust.html +++ b/loadtest/report_rust.html @@ -136,7 +136,7 @@

Request Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -204,7 +204,7 @@

Request Metrics

}, data: [["2025-02-20 17:47:56",598],["2025-02-20 17:47:57",1021],["2025-02-20 17:47:58",1306],["2025-02-20 17:47:59",1515],["2025-02-20 17:48:00",1659],["2025-02-20 17:48:01",1730],["2025-02-20 17:48:02",1782],["2025-02-20 17:48:03",1792],["2025-02-20 17:48:04",977],["2025-02-20 17:48:05",939],["2025-02-20 17:48:06",934],["2025-02-20 17:48:07",940],["2025-02-20 17:48:08",935],["2025-02-20 17:48:09",946],["2025-02-20 17:48:10",945],["2025-02-20 17:48:11",947],["2025-02-20 17:48:12",949],["2025-02-20 17:48:13",953],["2025-02-20 17:48:14",45]], }, - + ] }); @@ -251,7 +251,7 @@

Request Metrics

- +

Response Time Metrics

@@ -302,7 +302,7 @@

Response Time Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -370,7 +370,7 @@

Response Time Metrics

}, data: [["2025-02-20 17:47:56",1.0702340602874756],["2025-02-20 17:47:57",1.2095990180969238],["2025-02-20 17:47:58",1.9379770755767822],["2025-02-20 17:47:59",2.050825595855713],["2025-02-20 17:48:00",2.3152503967285156],["2025-02-20 17:48:01",2.9300577640533447],["2025-02-20 17:48:02",3.326037645339966],["2025-02-20 17:48:03",3.8281259536743164],["2025-02-20 17:48:04",7.48720121383667],["2025-02-20 17:48:05",7.855163097381592],["2025-02-20 17:48:06",7.812636375427246],["2025-02-20 17:48:07",7.8085126876831055],["2025-02-20 17:48:08",7.834228038787842],["2025-02-20 17:48:09",7.761096954345703],["2025-02-20 17:48:10",7.738626480102539],["2025-02-20 17:48:11",7.734953880310059],["2025-02-20 17:48:12",7.722865104675293],["2025-02-20 17:48:13",7.681005954742432],["2025-02-20 17:48:14",8.111112594604492]], }, - + ] }); @@ -420,7 +420,7 @@

Response Time Metrics

- +

Status Code Metrics

@@ -496,7 +496,7 @@

Transaction Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -564,7 +564,7 @@

Transaction Metrics

}, data: [["2025-02-20 17:47:56",599],["2025-02-20 17:47:57",1020],["2025-02-20 17:47:58",1306],["2025-02-20 17:47:59",1515],["2025-02-20 17:48:00",1659],["2025-02-20 17:48:01",1731],["2025-02-20 17:48:02",1781],["2025-02-20 17:48:03",1792],["2025-02-20 17:48:04",977],["2025-02-20 17:48:05",939],["2025-02-20 17:48:06",934],["2025-02-20 17:48:07",940],["2025-02-20 17:48:08",935],["2025-02-20 17:48:09",946],["2025-02-20 17:48:10",945],["2025-02-20 17:48:11",948],["2025-02-20 17:48:12",948],["2025-02-20 17:48:13",953],["2025-02-20 17:48:14",45]], }, - + ] }); @@ -660,7 +660,7 @@

Scenario Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -728,7 +728,7 @@

Scenario Metrics

}, data: [["2025-02-20 17:47:56",598],["2025-02-20 17:47:57",1019],["2025-02-20 17:47:58",1305],["2025-02-20 17:47:59",1514],["2025-02-20 17:48:00",1658],["2025-02-20 17:48:01",1730],["2025-02-20 17:48:02",1780],["2025-02-20 17:48:03",1791],["2025-02-20 17:48:04",977],["2025-02-20 17:48:05",939],["2025-02-20 17:48:06",934],["2025-02-20 17:48:07",940],["2025-02-20 17:48:08",935],["2025-02-20 17:48:09",946],["2025-02-20 17:48:10",945],["2025-02-20 17:48:11",948],["2025-02-20 17:48:12",948],["2025-02-20 17:48:13",953],["2025-02-20 17:48:14",45]], }, - + ] }); @@ -820,7 +820,7 @@

User Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -888,15 +888,15 @@

User Metrics

}, data: [["2025-02-20 17:47:56",8],["2025-02-20 17:47:57",8],["2025-02-20 17:47:58",8],["2025-02-20 17:47:59",8],["2025-02-20 17:48:00",8],["2025-02-20 17:48:01",8],["2025-02-20 17:48:02",8],["2025-02-20 17:48:03",8],["2025-02-20 17:48:04",8],["2025-02-20 17:48:05",8],["2025-02-20 17:48:06",0]], }, - + ] });
- + - \ No newline at end of file + diff --git a/loadtest/report_rust_server.html b/loadtest/report_rust_server.html index d3083b01..96143bcf 100644 --- a/loadtest/report_rust_server.html +++ b/loadtest/report_rust_server.html @@ -136,7 +136,7 @@

Request Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -204,7 +204,7 @@

Request Metrics

}, data: [["2025-03-25 13:44:41",175],["2025-03-25 13:44:42",304],["2025-03-25 13:44:43",462],["2025-03-25 13:44:44",651],["2025-03-25 13:44:45",1236],["2025-03-25 13:44:46",1445],["2025-03-25 13:44:47",1746],["2025-03-25 13:44:48",1989],["2025-03-25 13:44:49",2268],["2025-03-25 13:44:50",2366],["2025-03-25 13:44:51",2566],["2025-03-25 13:44:52",2663],["2025-03-25 13:44:53",2642],["2025-03-25 13:44:54",2451],["2025-03-25 13:44:55",2466],["2025-03-25 13:44:56",2401],["2025-03-25 13:44:57",2502],["2025-03-25 13:44:58",2597],["2025-03-25 13:44:59",2613],["2025-03-25 13:45:00",2481],["2025-03-25 13:45:01",2566],["2025-03-25 13:45:02",2613],["2025-03-25 13:45:03",2608],["2025-03-25 13:45:04",2597],["2025-03-25 13:45:05",2598],["2025-03-25 13:45:06",2580],["2025-03-25 13:45:07",2620],["2025-03-25 13:45:08",2582],["2025-03-25 13:45:09",2606],["2025-03-25 13:45:10",2594],["2025-03-25 13:45:11",2599],["2025-03-25 13:45:12",2535],["2025-03-25 13:45:13",2602],["2025-03-25 13:45:14",2614],["2025-03-25 13:45:15",2624],["2025-03-25 13:45:16",2593],["2025-03-25 13:45:17",2587],["2025-03-25 13:45:18",2549],["2025-03-25 13:45:19",2542],["2025-03-25 13:45:20",2538],["2025-03-25 13:45:21",2577],["2025-03-25 13:45:22",2553],["2025-03-25 13:45:23",2522],["2025-03-25 13:45:24",2537],["2025-03-25 13:45:25",2573],["2025-03-25 13:45:26",2581],["2025-03-25 13:45:27",2516],["2025-03-25 13:45:28",2383],["2025-03-25 13:45:29",2344],["2025-03-25 13:45:30",2402],["2025-03-25 13:45:31",2491],["2025-03-25 13:45:32",2451],["2025-03-25 13:45:33",2500],["2025-03-25 13:45:34",2545],["2025-03-25 13:45:35",336]], }, - + ] }); @@ -251,7 +251,7 @@

Request Metrics

- +

Response Time Metrics

@@ -302,7 +302,7 @@

Response Time Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'GET ', @@ -370,7 +370,7 @@

Response Time Metrics

}, data: [["2025-03-25 13:44:41",5.091427803039551],["2025-03-25 13:44:42",5.914474010467529],["2025-03-25 13:44:43",5.841992378234863],["2025-03-25 13:44:44",5.471584796905518],["2025-03-25 13:44:45",3.4239485263824463],["2025-03-25 13:44:46",3.495500087738037],["2025-03-25 13:44:47",3.3745667934417725],["2025-03-25 13:44:48",3.349924325942993],["2025-03-25 13:44:49",3.3126118183135986],["2025-03-25 13:44:50",3.3922200202941895],["2025-03-25 13:44:51",3.464533805847168],["2025-03-25 13:44:52",3.746528148651123],["2025-03-25 13:44:53",4.117340564727783],["2025-03-25 13:44:54",4.744597434997559],["2025-03-25 13:44:55",5.096113204956055],["2025-03-25 13:44:56",5.654726982116699],["2025-03-25 13:44:57",5.5883307456970215],["2025-03-25 13:44:58",5.720067977905273],["2025-03-25 13:44:59",6.067372798919678],["2025-03-25 13:45:00",6.64006233215332],["2025-03-25 13:45:01",6.799689292907715],["2025-03-25 13:45:02",7.032534599304199],["2025-03-25 13:45:03",7.229681968688965],["2025-03-25 13:45:04",7.671926021575928],["2025-03-25 13:45:05",8.024229049682617],["2025-03-25 13:45:06",8.493413925170898],["2025-03-25 13:45:07",8.722140312194824],["2025-03-25 13:45:08",9.253304481506348],["2025-03-25 13:45:09",9.531465530395508],["2025-03-25 13:45:10",9.805299758911133],["2025-03-25 13:45:11",10.14852523803711],["2025-03-25 13:45:12",10.81618595123291],["2025-03-25 13:45:13",10.862401962280273],["2025-03-25 13:45:14",11.229933738708496],["2025-03-25 13:45:15",11.616618156433105],["2025-03-25 13:45:16",11.727343559265137],["2025-03-25 13:45:17",11.790872573852539],["2025-03-25 13:45:18",11.950560569763184],["2025-03-25 13:45:19",11.967750549316406],["2025-03-25 13:45:20",11.99449634552002],["2025-03-25 13:45:21",11.832752227783203],["2025-03-25 13:45:22",11.957704544067383],["2025-03-25 13:45:23",12.096753120422363],["2025-03-25 13:45:24",11.975168228149414],["2025-03-25 13:45:25",11.81850814819336],["2025-03-25 13:45:26",11.801238059997559],["2025-03-25 13:45:27",12.114847183227539],["2025-03-25 13:45:28",12.85269832611084],["2025-03-25 13:45:29",13.082756042480469],["2025-03-25 13:45:30",12.73730754852295],["2025-03-25 13:45:31",12.25973129272461],["2025-03-25 13:45:32",12.445942878723145],["2025-03-25 13:45:33",12.213584899902344],["2025-03-25 13:45:34",11.984664916992188],["2025-03-25 13:45:35",11.886902809143066]], }, - + ] }); @@ -420,7 +420,7 @@

Response Time Metrics

- +

Status Code Metrics

@@ -496,7 +496,7 @@

Transaction Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -564,7 +564,7 @@

Transaction Metrics

}, data: [["2025-03-25 13:44:41",175],["2025-03-25 13:44:42",304],["2025-03-25 13:44:43",462],["2025-03-25 13:44:44",651],["2025-03-25 13:44:45",1236],["2025-03-25 13:44:46",1445],["2025-03-25 13:44:47",1746],["2025-03-25 13:44:48",1989],["2025-03-25 13:44:49",2268],["2025-03-25 13:44:50",2367],["2025-03-25 13:44:51",2565],["2025-03-25 13:44:52",2663],["2025-03-25 13:44:53",2642],["2025-03-25 13:44:54",2451],["2025-03-25 13:44:55",2466],["2025-03-25 13:44:56",2402],["2025-03-25 13:44:57",2501],["2025-03-25 13:44:58",2597],["2025-03-25 13:44:59",2613],["2025-03-25 13:45:00",2481],["2025-03-25 13:45:01",2566],["2025-03-25 13:45:02",2614],["2025-03-25 13:45:03",2608],["2025-03-25 13:45:04",2597],["2025-03-25 13:45:05",2597],["2025-03-25 13:45:06",2580],["2025-03-25 13:45:07",2620],["2025-03-25 13:45:08",2582],["2025-03-25 13:45:09",2606],["2025-03-25 13:45:10",2595],["2025-03-25 13:45:11",2598],["2025-03-25 13:45:12",2535],["2025-03-25 13:45:13",2603],["2025-03-25 13:45:14",2613],["2025-03-25 13:45:15",2625],["2025-03-25 13:45:16",2593],["2025-03-25 13:45:17",2586],["2025-03-25 13:45:18",2549],["2025-03-25 13:45:19",2542],["2025-03-25 13:45:20",2539],["2025-03-25 13:45:21",2576],["2025-03-25 13:45:22",2553],["2025-03-25 13:45:23",2523],["2025-03-25 13:45:24",2536],["2025-03-25 13:45:25",2573],["2025-03-25 13:45:26",2581],["2025-03-25 13:45:27",2516],["2025-03-25 13:45:28",2383],["2025-03-25 13:45:29",2344],["2025-03-25 13:45:30",2402],["2025-03-25 13:45:31",2491],["2025-03-25 13:45:32",2452],["2025-03-25 13:45:33",2499],["2025-03-25 13:45:34",2545],["2025-03-25 13:45:35",336]], }, - + ] }); @@ -660,7 +660,7 @@

Scenario Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -728,7 +728,7 @@

Scenario Metrics

}, data: [["2025-03-25 13:44:41",174],["2025-03-25 13:44:42",303],["2025-03-25 13:44:43",461],["2025-03-25 13:44:44",650],["2025-03-25 13:44:45",1235],["2025-03-25 13:44:46",1444],["2025-03-25 13:44:47",1745],["2025-03-25 13:44:48",1988],["2025-03-25 13:44:49",2267],["2025-03-25 13:44:50",2366],["2025-03-25 13:44:51",2564],["2025-03-25 13:44:52",2662],["2025-03-25 13:44:53",2641],["2025-03-25 13:44:54",2451],["2025-03-25 13:44:55",2465],["2025-03-25 13:44:56",2401],["2025-03-25 13:44:57",2500],["2025-03-25 13:44:58",2596],["2025-03-25 13:44:59",2612],["2025-03-25 13:45:00",2481],["2025-03-25 13:45:01",2565],["2025-03-25 13:45:02",2613],["2025-03-25 13:45:03",2607],["2025-03-25 13:45:04",2597],["2025-03-25 13:45:05",2595],["2025-03-25 13:45:06",2579],["2025-03-25 13:45:07",2619],["2025-03-25 13:45:08",2581],["2025-03-25 13:45:09",2605],["2025-03-25 13:45:10",2595],["2025-03-25 13:45:11",2597],["2025-03-25 13:45:12",2534],["2025-03-25 13:45:13",2602],["2025-03-25 13:45:14",2612],["2025-03-25 13:45:15",2624],["2025-03-25 13:45:16",2593],["2025-03-25 13:45:17",2586],["2025-03-25 13:45:18",2549],["2025-03-25 13:45:19",2542],["2025-03-25 13:45:20",2539],["2025-03-25 13:45:21",2576],["2025-03-25 13:45:22",2553],["2025-03-25 13:45:23",2523],["2025-03-25 13:45:24",2536],["2025-03-25 13:45:25",2573],["2025-03-25 13:45:26",2581],["2025-03-25 13:45:27",2516],["2025-03-25 13:45:28",2383],["2025-03-25 13:45:29",2344],["2025-03-25 13:45:30",2402],["2025-03-25 13:45:31",2491],["2025-03-25 13:45:32",2452],["2025-03-25 13:45:33",2499],["2025-03-25 13:45:34",2545],["2025-03-25 13:45:35",336]], }, - + ] }); @@ -820,7 +820,7 @@

User Metrics

nameGap: 45, type: 'value' }, - + series: [ { name: 'Total', @@ -888,15 +888,15 @@

User Metrics

}, data: [["2025-03-25 13:44:41",32],["2025-03-25 13:44:42",32],["2025-03-25 13:44:43",32],["2025-03-25 13:44:44",32],["2025-03-25 13:44:45",32],["2025-03-25 13:44:46",32],["2025-03-25 13:44:47",32],["2025-03-25 13:44:48",32],["2025-03-25 13:44:49",32],["2025-03-25 13:44:50",32],["2025-03-25 13:44:51",32],["2025-03-25 13:44:52",32],["2025-03-25 13:44:53",32],["2025-03-25 13:44:54",32],["2025-03-25 13:44:55",32],["2025-03-25 13:44:56",32],["2025-03-25 13:44:57",32],["2025-03-25 13:44:58",32],["2025-03-25 13:44:59",32],["2025-03-25 13:45:00",32],["2025-03-25 13:45:01",0],["2025-03-25 13:45:02",20],["2025-03-25 13:45:03",21],["2025-03-25 13:45:04",22],["2025-03-25 13:45:05",23],["2025-03-25 13:45:06",24],["2025-03-25 13:45:07",25],["2025-03-25 13:45:08",26],["2025-03-25 13:45:09",27],["2025-03-25 13:45:10",27],["2025-03-25 13:45:11",28],["2025-03-25 13:45:12",29],["2025-03-25 13:45:13",30],["2025-03-25 13:45:14",31],["2025-03-25 13:45:15",32]], }, - + ] });
- + - \ No newline at end of file + diff --git a/typos.toml b/typos.toml index 81eb31af..844ff721 100644 --- a/typos.toml +++ b/typos.toml @@ -57,4 +57,4 @@ extend-ignore-re = [] [type.js] [type.md] -extend-ignore-identifiers-re = ["HashiCorp"] +extend-ignore-identifiers-re = ["HashiCorp"]