From 7949011e1c4dd680f7847d72c21ec6153b001fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BREVET?= Date: Fri, 20 Oct 2023 12:06:09 +0200 Subject: [PATCH] feat: init openapi distribution Motivation: We want to publish our API in the public documentation. Modifications: * Copy yaml from internal project * configure build and release workflows Result: When a version is released, create a release with asset in GitHub --- .github/workflows/pages.yml | 54 +++ build.sbt | 12 + .../src/main/openapi/common/components.yaml | 93 +++++ openapi/src/main/openapi/default/path.yaml | 16 + openapi/src/main/openapi/info/components.yaml | 26 ++ openapi/src/main/openapi/info/path.yaml | 11 + openapi/src/main/openapi/openapi.yaml | 82 +++++ openapi/src/main/openapi/pkgs/components.yaml | 120 +++++++ openapi/src/main/openapi/pkgs/path.yaml | 92 +++++ .../src/main/openapi/pools/components.yaml | 27 ++ openapi/src/main/openapi/pools/path.yaml | 22 ++ .../openapi/private-locations/components.yaml | 24 ++ .../main/openapi/private-locations/path.yaml | 22 ++ openapi/src/main/openapi/runs/components.yaml | 195 +++++++++++ openapi/src/main/openapi/runs/path.yaml | 300 ++++++++++++++++ .../main/openapi/simulation/components.yaml | 321 ++++++++++++++++++ openapi/src/main/openapi/simulation/path.yaml | 230 +++++++++++++ .../src/main/openapi/teams/components.yaml | 16 + openapi/src/main/openapi/teams/path.yaml | 22 ++ project/plugins.sbt | 3 +- 20 files changed, 1687 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pages.yml create mode 100644 openapi/src/main/openapi/common/components.yaml create mode 100644 openapi/src/main/openapi/default/path.yaml create mode 100644 openapi/src/main/openapi/info/components.yaml create mode 100644 openapi/src/main/openapi/info/path.yaml create mode 100644 openapi/src/main/openapi/openapi.yaml create mode 100644 openapi/src/main/openapi/pkgs/components.yaml create mode 100644 openapi/src/main/openapi/pkgs/path.yaml create mode 100644 openapi/src/main/openapi/pools/components.yaml create mode 100644 openapi/src/main/openapi/pools/path.yaml create mode 100644 openapi/src/main/openapi/private-locations/components.yaml create mode 100644 openapi/src/main/openapi/private-locations/path.yaml create mode 100644 openapi/src/main/openapi/runs/components.yaml create mode 100644 openapi/src/main/openapi/runs/path.yaml create mode 100644 openapi/src/main/openapi/simulation/components.yaml create mode 100644 openapi/src/main/openapi/simulation/path.yaml create mode 100644 openapi/src/main/openapi/teams/components.yaml create mode 100644 openapi/src/main/openapi/teams/path.yaml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..c8f2e93 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,54 @@ +name: pages + +on: + push: + branches: [$default-branch] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pages: write + id-token: write + +defaults: + run: + shell: bash + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '21' + cache: 'sbt' + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + + - name: Preprocess with SBT + run: > + sbt + 'set openapi / Preprocess / target := (openapi / target).value / "public" / "openapi"' + 'openapi / Preprocess / preprocess' + + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./openapi/target/public + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/build.sbt b/build.sbt index b7ba662..8dbd15c 100644 --- a/build.sbt +++ b/build.sbt @@ -22,3 +22,15 @@ Compile / packageBin / mappings := { smithyFiles ++ defaultMappings } Compile / unmanagedSourceDirectories += sourceDirectory.value / "main" / "smithy" + +lazy val openapi = (project in file("openapi")) + .enablePlugins(PreprocessPlugin) + .settings( + Preprocess / sourceDirectory := sourceDirectory.value / "main" / "openapi", + Preprocess / preprocessRules := Seq( + ("API_URL_PLACEHOLDER".r, _ => "https://cloud.gatling.io/"), + ("VERSION_PLACEHOLDER".r, _ => version.value) + ), + Preprocess / preprocessIncludeFilter := "*.yaml", + Preprocess / target := target.value / "openapi", + ) diff --git a/openapi/src/main/openapi/common/components.yaml b/openapi/src/main/openapi/common/components.yaml new file mode 100644 index 0000000..21fdfe5 --- /dev/null +++ b/openapi/src/main/openapi/common/components.yaml @@ -0,0 +1,93 @@ +# Requests +requests: + +# Responses +responses: + + Unauthorized: + description: Unauthorized + content: + application/json: + schema: + $ref: '#/schemas/Error' + examples: + AccessUnauthorized: + value: + error: "invalid_request" + error_description: "i.g.f.a.s.UnauthorizedException$: Access unauthorized" + + Errors: + description: Error or Validation Error + content: + application/json: + schema: + $ref: '#/schemas/Errors' + examples: + Error: + $ref: '#/examples/Error' + + + Error: + description: Error + content: + application/json: + schema: + $ref: '#/schemas/Error' + examples: + Error: + $ref: '#/examples/Error' + + ConflictError: + description: Error + content: + application/json: + schema: + $ref: '#/schemas/Error' + example: + error: "invalid_request" + error_description: "i.g.f.a.s.RepositoryNameConflictException: There's already a X with the name Y" + +# Schemas +schemas: + Errors: + oneOf: + - $ref: '#/schemas/Error' + + Error: + type: object + properties: + error: + type: string + error_description: + type: string + + CustomDictionary: + type: object + additionalProperties: + type: string + example: + customProperty: "value" + +# Examples +examples: + + Error: + value: + error: "invalid_request" + error_description: "description" + +parameters: + run: + name: run + in: query + required: true + schema: + type: string + description: "run ID available using /runs API or by clicking on the clipboard icon in the runs table" + simulation: + name: simulation + in: query + required: true + schema: + type: string + description: "Simulation ID available using /simulations API or by clicking on the clipboard icon in the simulations table" diff --git a/openapi/src/main/openapi/default/path.yaml b/openapi/src/main/openapi/default/path.yaml new file mode 100644 index 0000000..cc9aabe --- /dev/null +++ b/openapi/src/main/openapi/default/path.yaml @@ -0,0 +1,16 @@ +ping: + get: + summary: Ping the server + description: | + Check that the server is responding. + + No permission, no authentication needed. + tags: + - Default + responses: + '200': + description: The server pinged back + content: + application/json: + schema: + type: object diff --git a/openapi/src/main/openapi/info/components.yaml b/openapi/src/main/openapi/info/components.yaml new file mode 100644 index 0000000..89c1627 --- /dev/null +++ b/openapi/src/main/openapi/info/components.yaml @@ -0,0 +1,26 @@ +responses: + InfoResponse: + type: object + description: Server informations + required: + - versions + properties: + versions: + type: object + description: Versions supported + required: + - java + properties: + java: + $ref: '#/responses/VersionSupported' + + VersionSupported: + type: object + description: Bound versions + properties: + min: + type: string + description: Minimum version supported + max: + type: string + description: Maximum version supported diff --git a/openapi/src/main/openapi/info/path.yaml b/openapi/src/main/openapi/info/path.yaml new file mode 100644 index 0000000..fc44533 --- /dev/null +++ b/openapi/src/main/openapi/info/path.yaml @@ -0,0 +1,11 @@ +info: + get: + summary: Get server informations + tags: + - Info + responses: + '200': + content: + application/json: + schema: + $ref: 'components.yaml#/responses/InfoResponse' diff --git a/openapi/src/main/openapi/openapi.yaml b/openapi/src/main/openapi/openapi.yaml new file mode 100644 index 0000000..a6f71db --- /dev/null +++ b/openapi/src/main/openapi/openapi.yaml @@ -0,0 +1,82 @@ +openapi: 3.0.0 +info: + title: Gatling Enterprise Cloud API + description: Documentation of the public Gatling Enterprise Cloud API. To use this API you will need to generate an API token. + version: 'VERSION_PLACEHOLDER' +servers: + - url: '{API_URL}/api/public' + variables: + API_URL: + default: API_URL_PLACEHOLDER +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: authorization +paths: + # Default + /ping: + $ref: 'default/path.yaml#/ping' + + # Simulation + /simulations: + $ref: 'simulation/path.yaml#/simulations' + /simulations/{simulationId}: + $ref: 'simulation/path.yaml#/simulations.one' + /simulations/{simulationId}/classname: + $ref: 'simulation/path.yaml#/simulations.one.classname' + /simulations/team: + $ref: 'simulation/path.yaml#/simulations.team' + /simulations/start: + $ref: 'simulation/path.yaml#/simulations.start' + /simulations/abort: + $ref: 'simulation/path.yaml#/simulations.abort' + /simulations/abortAll: + $ref: 'simulation/path.yaml#/simulations.abortAll' + /summaries/requests: + $ref: 'simulation/path.yaml#/summaries.requests' + + # Runs + /runs: + $ref: 'runs/path.yaml#/runs' + /run: + $ref: 'runs/path.yaml#/run' + /injectors: + $ref: 'runs/path.yaml#/injectors' + /remotes: + $ref: 'runs/path.yaml#/remotes' + /hostnames: + $ref: 'runs/path.yaml#/hostnames' + /scenarios: + $ref: 'runs/path.yaml#/scenarios' + /groups: + $ref: 'runs/path.yaml#/groups' + /requests: + $ref: 'runs/path.yaml#/requests' + /metrics: + $ref: 'runs/path.yaml#/metrics' + /series: + $ref: 'runs/path.yaml#/series' + + # Packages + /artifacts: + $ref: 'pkgs/path.yaml#/packages' + /artifacts/{packageId}: + $ref: 'pkgs/path.yaml#/package' + /artifacts/{packageId}/content: + $ref: 'pkgs/path.yaml#/packages.upload' + + # Teams + /teams: + $ref: 'teams/path.yaml#/teams' + + # Locations + /pools: + $ref: 'pools/path.yaml#/pools' + /search/private-locations: + $ref: 'private-locations/path.yaml#/private-locations' + + # Info + /info: + $ref: 'info/path.yaml#/info' diff --git a/openapi/src/main/openapi/pkgs/components.yaml b/openapi/src/main/openapi/pkgs/components.yaml new file mode 100644 index 0000000..3594e77 --- /dev/null +++ b/openapi/src/main/openapi/pkgs/components.yaml @@ -0,0 +1,120 @@ +parameters: + pkg: + id: + name: packageId + in: path + schema: + type: string + description: "Package ID available by clicking on the clipboard icon in the packages table" + example: "12eef26c-1078-498b-8788-5e74b5e64f46" + filename: + name: filename + in: query + schema: + type: string + description: "Package filename" + example: "maven-sample-1.0.0-shaded.jar" + +requests: + PkgUploadBodySchema: + schema: + type: string + format: binary + Package: + type: object + required: + - name + properties: + name: + type: string + description: "Package name" + example: "My Gatling package" + storageType: + type: string + description: "Package type: private or public" + example: "public" + teamId: + type: string + description: "Package team ID, omit if global team" + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + PkgUploadBody: + description: Bundled simulation shaded JAR (maximum size of 5GB) + required: true + content: + application/x-java-archive: + $ref: '#/requests/PkgUploadBodySchema' + application/x-jar: + $ref: '#/requests/PkgUploadBodySchema' + application/java-archive: + $ref: '#/requests/PkgUploadBodySchema' + application/octet-stream: + $ref: '#/requests/PkgUploadBodySchema' + +responses: + PackageFile: + type: object + description: Package file + properties: + filename: + type: string + description: Name of the uploaded file + example: "maven-sample-1.0.0-shaded.jar" + version: + type: string + description: Package gatling version + example: "3.7.3" + checksum: + type: string + description: Package checksum + example: "3y8Jb7JBQPE/UBvj3vUf2A==" + lastUpdated: + type: number + description: last update timestamp + example: 1640102835073 + + PackageIndex: + type: object + description: Package that can be used by a simulation + required: + - id + - name + - teamId + properties: + id: + type: string + description: Package ID + example: "0164293d-d15a-465f-8f40-41a2133fb35e" + name: + type: string + description: Package name + example: "maven-sample" + teamId: + type: string + description: Package team ID + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + filename: + type: string + description: Name of the uploaded file + example: "maven-sample-1.0.0-shaded.jar" + + Package: + type: object + description: Package that can be used by a simulation + required: + - id + - name + properties: + id: + type: string + description: Package ID + example: "0164293d-d15a-465f-8f40-41a2133fb35e" + name: + type: string + description: Package name + example: "maven-sample" + teamId: + type: string + description: Package team ID + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + file: + $ref: "#/responses/PackageFile" diff --git a/openapi/src/main/openapi/pkgs/path.yaml b/openapi/src/main/openapi/pkgs/path.yaml new file mode 100644 index 0000000..7591bfc --- /dev/null +++ b/openapi/src/main/openapi/pkgs/path.yaml @@ -0,0 +1,92 @@ +packages.upload: + put: + summary: Upload a Package + tags: + - Packages + description: | + Upload your package JAR, initializing or overriding the content. + Beware, server may respond before consuming all the request body for security requirement, + which is not handled properly by all HTTP clients. + + The maximum upload size is 5 GB. + + Requires at least the `Configure` role on the package's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: 'components.yaml#/parameters/pkg/id' + required: true + - $ref: 'components.yaml#/parameters/pkg/filename' + required: true + requestBody: + $ref: 'components.yaml#/requests/PkgUploadBody' + responses: + '200': + content: + application/json: + schema: + $ref: 'components.yaml#/responses/Package' + '413': + description: Uploaded package is too large + +package: + get: + summary: Get a package by ID + tags: + - Packages + security: + - ApiKeyAuth: [] + parameters: + - $ref: 'components.yaml#/parameters/pkg/id' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: 'components.yaml#/responses/Package' +packages: + get: + summary: Retrieve the list of packages + tags: + - Packages + description: | + Retrieve the list of all the packages that can be seen by the API token. + + Requires at least the `Read` role on each package's team, otherwise they are omitted from the response. + security: + - ApiKeyAuth: [] + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: 'components.yaml#/responses/PackageIndex' + post: + summary: Create a package + tags: + - Packages + description: | + Create a new package with a name and the associated teamId. + The package won't contain any file yet, you need to upload a file to the package in order to use it. + + Requires at least the `Configure` role on the package's team. + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: 'components.yaml#/requests/Package' + responses: + '200': + content: + application/json: + schema: + $ref: 'components.yaml#/responses/Package' diff --git a/openapi/src/main/openapi/pools/components.yaml b/openapi/src/main/openapi/pools/components.yaml new file mode 100644 index 0000000..c12b0ba --- /dev/null +++ b/openapi/src/main/openapi/pools/components.yaml @@ -0,0 +1,27 @@ +responses: + Pool: + type: object + description: Description of a location + required: + - id + - name + properties: + id: + type: string + description: Location ID + example: "0164293d-d15a-465f-8f40-41a2133fb35e" + name: + type: string + description: Location name + example: "US East - N. Virginia" + code: + type: number + description: | + Type of location. + + - `2`: AWS region + example: 2 + countryCode: + type: string + description: Country in which the location is located (ISO-3166 2 letters country code) + example: US diff --git a/openapi/src/main/openapi/pools/path.yaml b/openapi/src/main/openapi/pools/path.yaml new file mode 100644 index 0000000..cd19ea4 --- /dev/null +++ b/openapi/src/main/openapi/pools/path.yaml @@ -0,0 +1,22 @@ +pools: + get: + summary: Retrieve the list of locations + tags: + - Locations + description: | + Retrieve the list of all the locations enabled in this organization. + + Requires at least the `Read` role on any team. + security: + - ApiKeyAuth: [] + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: 'components.yaml#/responses/Pool' diff --git a/openapi/src/main/openapi/private-locations/components.yaml b/openapi/src/main/openapi/private-locations/components.yaml new file mode 100644 index 0000000..5087952 --- /dev/null +++ b/openapi/src/main/openapi/private-locations/components.yaml @@ -0,0 +1,24 @@ +responses: + Location: + type: object + description: Description of a private location + required: + - id + - type + properties: + id: + type: string + description: Location ID + example: "prl_my_private_location" + organizationSlug: + type: string + description: The unique slug of the organization owning this location + example: "gatling-corp" + type: + type: string + description: Type of the private location + example: "aws" + description: + type: string + description: The description of the location + example: "My first private location" diff --git a/openapi/src/main/openapi/private-locations/path.yaml b/openapi/src/main/openapi/private-locations/path.yaml new file mode 100644 index 0000000..f970312 --- /dev/null +++ b/openapi/src/main/openapi/private-locations/path.yaml @@ -0,0 +1,22 @@ +private-locations: + get: + summary: Retrieve the list of private locations + tags: + - Locations + description: | + Retrieve the list of private locations accessible from the current authentication. + + Requires at least the `Read` role on any team. + security: + - ApiKeyAuth: [] + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: 'components.yaml#/responses/Location' diff --git a/openapi/src/main/openapi/runs/components.yaml b/openapi/src/main/openapi/runs/components.yaml new file mode 100644 index 0000000..58eedb8 --- /dev/null +++ b/openapi/src/main/openapi/runs/components.yaml @@ -0,0 +1,195 @@ +# Requests +parameters: + requests: + group: + name: group + in: query + schema: + type: string + description: "group available using /groups API" + +# Responses +responses: + +# Schemas +schemas: + Injector: + type: object + properties: + pool: + type: string + description: Name of the location containing the load generator + hostname: + type: string + description: Hostname of the load generator + + Metric: + type: object + properties: + value: + type: string + description: Metric name + requirements: + type: array + description: List of requirements to fetch the metric + items: + type: string + + Runs: + type: object + properties: + id: + type: string + incrementalId: + type: integer + injectStart: + type: number + injectEnd: + type: number + + Run: + type: object + properties: + runId: + type: string + incrementalId: + type: integer + buildStart: + type: number + buildEnd: + type: number + deployStart: + type: number + deployEnd: + type: number + injectStart: + type: number + injectEnd: + type: number + status: + type: integer + enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15 ] + description: | + * `0`: Building + * `1`: Deploying + * `2`: Deployed + * `3`: Injecting + * `4`: Successful + * `5`: AssertionsSuccessful + * `6`: AutomaticallyStopped + * `7`: Stopped + * `8`: AssertionsFailed + * `9`: Timeout + * `10`: BuildFailed + * `11`: Broken + * `12`: DeploymentFailed + * `13`: InsufficientLicense + * `15`: StopRequested + error: + type: string + runSnapshot: + type: object + properties: + simulationName: + type: string + systemProperties: + $ref: '../common/components.yaml#/schemas/CustomDictionary' + environmentVariables: + $ref: '../common/components.yaml#/schemas/CustomDictionary' + simulationClass: + type: string + trigger: + oneOf: + - $ref: 'components.yaml#/schemas/TriggerByApiToken' + - $ref: 'components.yaml#/schemas/TriggerByUser' + usePoolWeights: + type: boolean + poolSnapshots: + type: array + items: + type: object + properties: + poolId: + type: string + poolName: + type: string + size: + type: integer + weight: + type: integer + dedicatedIps: + type: array + items: + type: string + artifactId: + type: string + comments: + type: object + properties: + title: + type: string + description: + type: string + assertions: + type: array + items: + type: object + properties: + message: + type: string + result: + type: boolean + actualValue: + type: number + scenario: + type: string + group: + type: string + request: + type: string + + Series: + type: object + properties: + resolution: + type: integer + enum: [1, 5, 20, 80, 320] + description: Describe how many seconds of data are represented by each value + name: + type: string + description: Label associated with the series. Mostly useful when several series are returned for a given metric (e.g. metrics which return different series per scenario). + start: + type: number + description: Timestamp corresponding to the start time of the injection + offset: + type: integer + description: Offset between the start time of the injection and the first data returned by the API + values: + type: array + items: + type: string + + TriggerByApiToken: + type: object + properties: + type: + type: string + enum: + ["apiToken"] + tokenId: + type: string + description: ID of the API Token which triggered the run + name: + type: string + description: name of the API Token which triggered the run + + TriggerByUser: + type: object + properties: + type: + type: string + enum: + ["user"] + userId: + type: string + description: ID of the user who triggered the run diff --git a/openapi/src/main/openapi/runs/path.yaml b/openapi/src/main/openapi/runs/path.yaml new file mode 100644 index 0000000..334cb17 --- /dev/null +++ b/openapi/src/main/openapi/runs/path.yaml @@ -0,0 +1,300 @@ +runs: + get: + summary: Simulation Runs + tags: + - Runs + description: | + Return the list of the runs for a given simulation. + + Requires at least the `Read` role on the simulation's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/simulation" + responses: + '200': + description: An array of runs + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/schemas/Runs' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +run: + get: + summary: Run + tags: + - Runs + description: | + Return the detailed information of a run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: The information of a run. + content: + application/json: + schema: + $ref: 'components.yaml#/schemas/Run' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +injectors: + get: + summary: Run Load Generators + tags: + - Runs + description: | + Return the list of the load generators for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: An array of load generators + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/schemas/Injector' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +remotes: + get: + summary: Run Remotes + tags: + - Runs + description: | + Return the list of the remotes for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: An array of remotes + content: + application/json: + schema: + type: array + items: + type: string + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +hostnames: + get: + summary: Run Hostnames + tags: + - Runs + description: | + Return the list of the hostnames for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: An array of hostnames + content: + application/json: + schema: + type: array + items: + type: string + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +scenarios: + get: + summary: Run Scenarios + tags: + - Runs + description: | + Return the list of the scenarios for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: An array of scenarios + content: + application/json: + schema: + type: array + items: + type: string + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +groups: + get: + summary: Run Groups + tags: + - Runs + description: | + Return the list of the groups for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: An array of groups + content: + application/json: + schema: + type: array + items: + type: string + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +requests: + get: + summary: Run Requests + tags: + - Runs + description: | + Return the list of the requests for a given run. + + Requires at least the `Read` role on the run's team. + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + - $ref: "components.yaml#/parameters/requests/group" + responses: + '200': + description: An array of requests + content: + application/json: + schema: + type: array + items: + type: string + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +metrics: + get: + summary: List of metrics available + tags: + - Runs + description: | + The Metric endpoint returns metrics information. + + Requires at least the `Read` role on the whole organization. + security: + - ApiKeyAuth: [] + responses: + '200': + description: "An array of metrics. If one of the requirement is the scope, you can prefix the metric with one of the scope options ('all.', 'ok.', or 'ko.') when querying a metric; e.g. 'all.req.mean' for the 'req.mean' metric" + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/schemas/Metric' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +series: + get: + summary: Series data of a run + description: | + Series data of a run. + + Requires at least the `Read` role on the run's team. + tags: + - Runs + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + - name: metric + in: query + required: true + schema: + type: string + description: "One of the metrics returned by the /metrics API. If the metric has the 'scope' requirement, you can prefix it with one of the scope options ('all.', 'ok.', or 'ko.'); e.g. 'all.req.mean' for the 'req.mean' metric. If no scope is prefixed, the default scope is 'all.'" + - name: from + in: query + required: false + schema: + type: number + description: "Timestamp (in milliseconds) corresponding to the start of the window you want to select, default value: injection start" + - name: to + in: query + required: false + schema: + type: number + description: "Timestamp (in milliseconds) corresponding to the end of the window you want to select, default value: injection end" + - name: scenario + in: query + required: false + schema: + type: string + description: "Name of the scenario or '*' if you want the data for every scenario, check the metrics endpoint to see if it is needed, default value: `*`" + - name: group + in: query + required: false + schema: + type: string + description: | + Name of the group. Check the metrics endpoint to see if it is needed. + - For metrics which also require the 'request' parameter, specifies which group the request is part of. Use an empty value for requests which are not part of a group. Use '\*' together with the '\*' request parameter value (or omit both parameters) for all requests. + - For metrics which don't require the 'request' parameter, specifies the group the metric applies to. + - name: request + in: query + required: false + schema: + type: string + description: | + Name of the request. Check the metrics endpoint to see if it is needed. + + The group that the request is part of must also be specified (with an empty value if there is no group); see the 'group' parameter. Use the '\*' value together with the '\*' group parameter value (or omit both parameters) for all requests. + - name: remote + in: query + required: false + schema: + type: string + description: "Hostname of the remote or '*' if you want the data for every remote, check the metrics endpoint to see if it is needed, default value: `*`" + - name: node + in: query + required: false + schema: + type: string + description: "Hostname of the load load generator or '*' if you want the data for every load generator, check the metrics endpoint to see if it is needed, default value: `*`" + responses: + '200': + description: Series data + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/schemas/Series' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' diff --git a/openapi/src/main/openapi/simulation/components.yaml b/openapi/src/main/openapi/simulation/components.yaml new file mode 100644 index 0000000..76c1dab --- /dev/null +++ b/openapi/src/main/openapi/simulation/components.yaml @@ -0,0 +1,321 @@ +# Requests +requests: + ClassName: + description: Allow to update a simulation class name + content: + application/json: + schema: + $ref: '#/schemas/ClassName' + + StartOptions: + description: Allows to merge additional Java system properties, environment variables and set custom host configuration for a run + content: + application/json: + schema: + $ref: '#/schemas/SimulationWithManagedLocations' + examples: + SimulationWithManagedLocations: + value: + extraSystemProperties: + customProperty: "value" + extraEnvironmentVariables: + customProperty: "value" + overrideHostsByPool: + "4a399023-d443-3a58-864f-3919760df78b": + size: 1 + weight: 60 + "c800b6d9-163b-3db7-928f-86c1470a9542": + size: 1 + weight: 40 + SimulationWithPrivateLocations: + value: + extraSystemProperties: + customProperty: "value" + extraEnvironmentVariables: + customProperty: "value" + + Simulation: + description: The definition of a simulation + required: true + content: + application/json: + schema: + type: object + properties: + teamId: + type: string + description: "Team ID" + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + name: + type: string + description: "Simulation name" + example: "My Gatling simulation" + className: + type: string + description: "Fully qualified class name" + example: "computerdatabase.BasicSimulation" + build: + type: object + properties: + pkgId: + type: string + description: "Id of an already created package you want to link. The package needs to have an uploaded file" + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + systemProperties: + type: object + description: "Map of key/values corresponding to the Java system properties used by this simulation" + environmentVariables: + type: object + description: "Map of key/values corresponding to the environment variables used by this simulation" + ignoreGlobalProperties: + type: boolean + description: "Set to true if you want to ignore the global JVM options and Java system properties set by your organization" + example: false + meaningfulTimeWindow: + type: object + properties: + rampUp: + type: integer + description: "The first seconds you want to exclude from the run" + rampDown: + type: integer + description: "The last seconds you want to exclude from the run" + hostsByPool: + $ref: '#/schemas/HostsByPool' + usePoolWeights: + type: boolean + description: "Set to true if you want to enable the custom weight set on your locations" + example: false + usePoolDedicatedIps: + type: boolean + description: Use dedicated IPs for your load generators + example: false + + # TODO: all requests should be defined here + +# Responses +responses: + ClassName: + $ref: '#/schemas/ClassName' + + Simulation: + type: object + properties: + id: + type: string + description: "Simulation ID" + example: "a00589b6-3014-41be-97e3-c2784965e4fe" + teamId: + type: string + description: "Team ID" + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + name: + type: string + description: "Simulation name" + example: "My Gatling simulation" + className: + type: string + description: "Fully qualified class name" + example: "computerdatabase.BasicSimulation" + build: + type: object + properties: + pkgId: + type: string + description: "Id of an already created package you want to link. The package needs to have an uploaded file" + example: "424571fe-2351-4f3f-ae6a-04b7105f7157" + systemProperties: + type: object + description: "Map of key/values corresponding to the Java system properties used by this simulation" + environmentVariables: + type: object + description: "Map of key/values corresponding to the environment variables used by this simulation" + ignoreGlobalProperties: + type: boolean + description: "Set to true if you want to ignore the global JVM options, Java system properties and environment variables set by your organization" + example: false + meaningfulTimeWindow: + type: object + properties: + rampUp: + type: integer + description: "The first seconds you want to exclude from the run" + rampDown: + type: integer + description: "The last seconds you want to exclude from the run" + hostsByPool: + type: object + description: "ID of the public location you want to use" + properties: + poolId: + type: object + properties: + size: + type: integer + weight: + type: number + hostsByLocation: + type: object + description: "ID of the location you want to use" + properties: + poolId: + type: object + properties: + size: + type: integer + weight: + type: number + usePoolWeights: + type: boolean + description: "Set to true if you want to enable the custom weight set on your locations" + example: false + usePoolDedicatedIps: + type: boolean + description: Use dedicated IPs for your load generators + example: false + + # TODO: all responses should be defined here + +# Schemas +schemas: + SimulationWithManagedLocations: + type: object + properties: + extraSystemProperties: + $ref: '../common/components.yaml#/schemas/CustomDictionary' + extraEnvironmentVariables: + $ref: '../common/components.yaml#/schemas/CustomDictionary' + overrideHostsByPool: + $ref: '#/schemas/HostsByPool' + + ClassName: + type: object + required: + - className + properties: + className: + type: string + description: Fully qualified class name of a simulation + example: computerdatabase.BasicSimulation + + + HostsByPool: + type: object + description: "Number of hosts and associated weight, for each location used. The weights must sum up to 100 if specified." + additionalProperties: + type: object + required: + - size + properties: + size: + type: integer + weight: + type: number + example: + "4a399023-d443-3a58-864f-3919760df78b": + size: 1 + weight: 60 + "c800b6d9-163b-3db7-928f-86c1470a9542": + size: 1 + weight: 40 + + RequestsSummary: + type: object + properties: + name: + type: string + responseTime: + $ref: '#/schemas/ResponseTimeRequestsSummary' + in: + $ref: '#/schemas/InRequestsSummary' + out: + $ref: '#/schemas/OutRequestsSummary' + children: + type: array + items: + $ref: '#/schemas/RequestsSummaryChild' + + RequestsSummaryChild: + type: object + properties: + name: + type: string + index: + type: integer + incrementalId: + type: integer + responseTime: + $ref: '#/schemas/ResponseTimeRequestsSummary' + in: + $ref: '#/schemas/InRequestsSummary' + out: + $ref: '#/schemas/OutRequestsSummary' + + ResponseTimeRequestsSummary: + type: object + properties: + mean: + type: number + stdDev: + type: number + percentiles: + type: array + description: "This array contains the following percentiles: min, 25%, 50%, 75%, 80%, 85%, 90%, 95%, 99%, 99.9%, 99.99%, max" + items: + type: number + + OutRequestsSummary: + type: object + properties: + counts: + type: object + properties: + total: + type: integer + description: Total number of requests sent by the load generators + rps: + type: object + properties: + total: + type: number + + InRequestsSummary: + type: object + properties: + counts: + type: object + properties: + ok: + type: integer + description: Total number of ok responses received by the load generators + ko: + type: integer + description: Total number of ko responses received by the load generators + koPercent: + type: number + total: + type: integer + description: Total number of responses received by the load generators + rps: + type: object + properties: + ok: + type: number + ko: + type: number + total: + type: number + + RunSummary: + type: object + properties: + className: + type: string + runId: + type: string + reportsPath: + type: string + description: The path to the reports page for this run + runsPath: + type: string + description: The path to the runs page for this simulation diff --git a/openapi/src/main/openapi/simulation/path.yaml b/openapi/src/main/openapi/simulation/path.yaml new file mode 100644 index 0000000..d6cee5c --- /dev/null +++ b/openapi/src/main/openapi/simulation/path.yaml @@ -0,0 +1,230 @@ +simulations: + get: + summary: Simulations + tags: + - Simulations + description: | + Return the list of all simulations belonging to the API token teams. + + Requires at least the `Read` role on each token's team, otherwise they are omitted from the response. + security: + - ApiKeyAuth: [] + responses: + '200': + description: An array containing the simulations + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/responses/Simulation' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + post: + summary: Create a simulation + tags: + - Simulations + description: | + Create a new simulation. + + Requires at least the `Configure` role on the simulation's team. + security: + - ApiKeyAuth: [] + requestBody: + $ref: 'components.yaml#/requests/Simulation' + responses: + '200': + content: + application/json: + schema: + $ref: 'components.yaml#/responses/Simulation' + +simulations.one.classname: + put: + summary: Update simulation class name + tags: + - Simulations + description: | + Update simulation class name under corresponding simulationId. + + Requires at least the `Configure` role on the simulation's team. + security: + - ApiKeyAuth: [ ] + parameters: + - in: path + name: simulationId + schema: + type: string + required: true + description: UUID of the simulation + requestBody: + $ref: 'components.yaml#/requests/ClassName' + responses: + '200': + description: The simulation + content: + application/json: + schema: + $ref: 'components.yaml#/responses/ClassName' + +simulations.one: + get: + summary: Retrieve one simulation + tags: + - Simulations + description: | + Returns the simulation with the corresponding simulationId. + + Requires at least the `Read` role on the simulation's team. + security: + - ApiKeyAuth: [] + parameters: + - in: path + name: simulationId + schema: + type: string + required: true + description: UUID of the simulation + responses: + '200': + description: The simulation + content: + application/json: + schema: + $ref: 'components.yaml#/responses/Simulation' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +simulations.team: + get: + summary: Simulations by Team + tags: + - Simulations + description: | + Return the list of the simulations on the given team. + + Requires at least the `Read` role on the given team. + security: + - ApiKeyAuth: [] + parameters: + - name: team + in: query + required: true + schema: + type: string + description: "Team ID available using /simulations API or by clicking on the clipboard icon in the teams table" + responses: + '200': + description: An array of simulations + content: + application/json: + schema: + type: array + items: + $ref: 'components.yaml#/responses/Simulation' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +simulations.start: + post: + summary: Start a simulation + description: | + Start a simulation. + + Requires at least the `Start` role on the simulation's team. + tags: + - Simulations + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/simulation" + requestBody: + $ref: 'components.yaml#/requests/StartOptions' + responses: + '200': + description: Start run information + content: + application/json: + schema: + $ref: 'components.yaml#/schemas/RunSummary' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +simulations.abort: + post: + summary: Stop a run + description: | + Abort a running simulation. + + Requires at least the `Start` role on the simulation's team. + tags: + - Simulations + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + responses: + '200': + description: Run stopped + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +simulations.abortAll: + post: + summary: Stop all ongoing runs + description: | + Abort all ongoing runs in the organization. + + Requires at least the `Start` role on the whole organization. + tags: + - Simulations + security: + - ApiKeyAuth: [] + responses: + '200': + description: All runs stopped + '500': + description: Error when aborting one or more runs + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' + +summaries.requests: + get: + summary: Summaries requests data + description: + Summaries requests data. + + Requires at least the `Read` role on the run's team. + tags: + - Summary + security: + - ApiKeyAuth: [] + parameters: + - $ref: "../common/components.yaml#/parameters/run" + - name: from + in: query + required: false + schema: + type: number + description: "Timestamp corresponding to the start of the time window you want to select, default value: injection start" + - name: to + in: query + required: false + schema: + type: number + description: "Timestamp corresponding to the end of the time window you want to select, default value: injection end" + - name: scenario + in: query + required: false + schema: + type: string + description: "Name of the scenario or '*' if you want the stats for every scenario, default value: `*`" + responses: + '200': + description: Summary data, the children can contain others children if you use groups + content: + application/json: + schema: + $ref: 'components.yaml#/schemas/RequestsSummary' + '401': + $ref: '../common/components.yaml#/responses/Unauthorized' diff --git a/openapi/src/main/openapi/teams/components.yaml b/openapi/src/main/openapi/teams/components.yaml new file mode 100644 index 0000000..954d90c --- /dev/null +++ b/openapi/src/main/openapi/teams/components.yaml @@ -0,0 +1,16 @@ +responses: + Team: + type: object + description: Description of a team + required: + - id + - name + properties: + id: + type: string + description: Team ID + example: "0164293d-d15a-465f-8f40-41a2133fb35e" + name: + type: string + description: Team name + example: "Default team" diff --git a/openapi/src/main/openapi/teams/path.yaml b/openapi/src/main/openapi/teams/path.yaml new file mode 100644 index 0000000..f2ee8d3 --- /dev/null +++ b/openapi/src/main/openapi/teams/path.yaml @@ -0,0 +1,22 @@ +teams: + get: + summary: Retrieve the list of teams + tags: + - Teams + description: | + Retrieve the list of all the teams that can be seen by the API token. + + Requires at least the `Read` role on each team, otherwise they are omitted from the response. + security: + - ApiKeyAuth: [] + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: 'components.yaml#/responses/Team' diff --git a/project/plugins.sbt b/project/plugins.sbt index b4b94a1..ae1f33c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +1,2 @@ -addSbtPlugin("io.gatling" % "gatling-build-plugin" % "5.2.1") +addSbtPlugin("com.github.sbt" % "sbt-site-paradox" % "1.5.0") +addSbtPlugin("io.gatling" % "gatling-build-plugin" % "5.2.1")