From 465ff68059d652c0ab740209d7796622da363763 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 20 Mar 2024 13:25:07 -0400 Subject: [PATCH] ci(schema): check for OpenAPI and GraphQL schema changes (#334) --- .github/workflows/pr-ci.yaml | 107 + schema/openapi.yaml | 2255 +++++++++++++++++++++ schema/update.bash | 27 + src/main/resources/application.properties | 2 +- 4 files changed, 2390 insertions(+), 1 deletion(-) create mode 100644 schema/openapi.yaml create mode 100755 schema/update.bash diff --git a/.github/workflows/pr-ci.yaml b/.github/workflows/pr-ci.yaml index a0e6f9984..1c573f57e 100644 --- a/.github/workflows/pr-ci.yaml +++ b/.github/workflows/pr-ci.yaml @@ -183,3 +183,110 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} status: ${{ job.status }} + update-schemas: + needs: [checkout-branch] + runs-on: ubuntu-latest + outputs: + OPENAPI_STATUS: ${{ steps.schema-update.outputs.openapi_status }} + OPENAPI_DIFF_FILE: ${{ steps.schema-update.outputs.openapi_diff_file }} + # GRAPHQL_STATUS: ${{ steps.schema-update.outputs.graphql_status }} + # GRAPHQL_DIFF_FILE: ${{ steps.schema-update.outputs.graphql_diff_file }} + steps: + - uses: actions/checkout@v3 + with: + repository: ${{ needs.checkout-branch.outputs.PR_repo }} + ref: ${{ needs.checkout-branch.outputs.PR_head_ref }} + submodules: true + fetch-depth: 0 + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: 'maven' + - run: git submodule init && git submodule update + - name: Cache yarn packages + uses: actions/cache@v3 + with: + path: "./src/main/webui/.yarn/cache" + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Initialize web assets + run: | + cd src/main/webui + yarn install && yarn yarn:frzinstall + cd - + - name: Update schemas + id: schema-update + run: | + set -x + mkdir "${HOME}/bin" + wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O "${HOME}/bin/yq" + chmod +x "${HOME}/bin/yq" + export PATH="${HOME}/bin:${PATH}" + bash /home/runner/work/cryostat3/cryostat3/schema/update.bash 90 15 + set +e + git diff -U10 --exit-code /home/runner/work/cryostat3/cryostat3/schema/openapi.yaml > /home/runner/work/openapi.diff + echo "openapi_status=$?" >> "$GITHUB_OUTPUT" + echo "openapi_diff_file=openapi.diff" >> "$GITHUB_OUTPUT" + # git diff -U10 --exit-code /home/runner/work/cryostat3/cryostat3/schema/schema.graphql > /home/runner/work/graphql.diff + # echo "graphql_status=$?" >> "$GITHUB_OUTPUT" + # echo "graphql_diff_file=graphql.diff" >> "$GITHUB_OUTPUT" + - uses: actions/upload-artifact@v3 + with: + name: openapi-diff + path: /home/runner/work/openapi.diff + - uses: actions/upload-artifact@v3 + with: + name: graphql-diff + path: /home/runner/work/graphql.diff + + compare-openapi-schema: + needs: [update-schemas] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + name: openapi-diff + - name: Comment schema check result + uses: actions/github-script@v6 + with: + script: | + const diffFmt = s => { + return "```diff\n" + s + "\n```"; + }; + const commentBody = ${{ needs.update-schemas.outputs.OPENAPI_STATUS }} == '0' + ? `No OpenAPI schema changes detected.` + : `OpenAPI schema change detected:\n\n${diffFmt(require('fs').readFileSync('${{ needs.update-schemas.outputs.OPENAPI_DIFF_FILE }}'))}`; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); + + # compare-graphql-schema: + # needs: [update-schemas] + # runs-on: ubuntu-latest + # steps: + # - uses: actions/download-artifact@v3 + # with: + # name: graphql-diff + # - name: Comment schema check result + # uses: actions/github-script@v6 + # with: + # script: | + # const diffFmt = s => { + # return "```diff\n" + s + "\n```"; + # }; + # const commentBody = ${{ needs.update-schemas.outputs.GRAPHQL_STATUS }} == '0' + # ? `No GraphQL schema changes detected.` + # : `GraphQL schema change detected:\n\n${diffFmt(require('fs').readFileSync('${{ needs.update-schemas.outputs.GRAPHQL_DIFF_FILE }}'))}`; + # github.rest.issues.createComment({ + # issue_number: context.issue.number, + # owner: context.repo.owner, + # repo: context.repo.repo, + # body: commentBody + # }); diff --git a/schema/openapi.yaml b/schema/openapi.yaml new file mode 100644 index 000000000..ad82e1d2e --- /dev/null +++ b/schema/openapi.yaml @@ -0,0 +1,2255 @@ +--- +components: + schemas: + AnalysisResult: + properties: + evaluation: + $ref: '#/components/schemas/Evaluation' + name: + type: string + score: + format: double + type: number + topic: + type: string + type: object + Annotations: + properties: + cryostat: + additionalProperties: + type: string + type: object + platform: + additionalProperties: + type: string + type: object + type: object + ArchivedRecording: + properties: + archivedTime: + format: int64 + type: integer + downloadUrl: + type: string + metadata: + $ref: '#/components/schemas/Metadata' + name: + type: string + reportUrl: + type: string + size: + format: int64 + type: integer + type: object + ArchivedRecordingDirectory: + properties: + connectUrl: + type: string + jvmId: + type: string + recordings: + items: + $ref: '#/components/schemas/ArchivedRecording' + type: array + type: object + Data: + type: object + DiscoveryNode: + properties: + children: + items: + $ref: '#/components/schemas/DiscoveryNode' + type: array + id: + format: int64 + type: integer + labels: + additionalProperties: + type: string + type: object + name: + pattern: \S + type: string + nodeType: + pattern: \S + type: string + target: + $ref: '#/components/schemas/Target' + required: + - name + - nodeType + - labels + type: object + DiscoveryPlugin: + properties: + builtin: + type: boolean + callback: + format: uri + type: string + id: + $ref: '#/components/schemas/UUID' + realm: + $ref: '#/components/schemas/DiscoveryNode' + required: + - id + - realm + type: object + Evaluation: + properties: + explanation: + type: string + solution: + type: string + suggestions: + items: + $ref: '#/components/schemas/Suggestion' + type: array + summary: + type: string + type: object + FileUpload: + type: object + Instant: + example: 2022-03-10T16:15:50Z + format: date-time + type: string + JsonObject: + items: + properties: + key: + type: string + value: {} + type: object + type: array + LinkedRecordingDescriptor: + properties: + continuous: + type: boolean + downloadUrl: + type: string + duration: + format: int64 + type: integer + id: + format: int64 + type: integer + maxAge: + format: int64 + type: integer + maxSize: + format: int64 + type: integer + metadata: + $ref: '#/components/schemas/Metadata' + name: + type: string + remoteId: + format: int64 + type: integer + reportUrl: + type: string + startTime: + format: int64 + type: integer + state: + $ref: '#/components/schemas/RecordingState' + toDisk: + type: boolean + type: object + MatchExpression: + properties: + id: + format: int64 + type: integer + script: + pattern: \S + type: string + required: + - script + type: object + MatchedExpression: + properties: + expression: + type: string + id: + format: int64 + type: integer + targets: + items: + $ref: '#/components/schemas/Target' + type: array + type: object + Meta: + properties: + status: + type: string + type: + type: string + type: object + Metadata: + properties: + expiry: + $ref: '#/components/schemas/Instant' + labels: + additionalProperties: + type: string + type: object + type: object + RecordingState: + enum: + - NEW + - DELAYED + - RUNNING + - STOPPED + - CLOSED + type: string + RequestData: + properties: + matchExpression: + type: string + targets: + items: + $ref: '#/components/schemas/Target' + type: array + type: object + Rule: + properties: + archivalPeriodSeconds: + format: int32 + minimum: 0 + type: integer + description: + type: string + enabled: + type: boolean + eventSpecifier: + pattern: \S + type: string + id: + format: int64 + type: integer + initialDelaySeconds: + format: int32 + minimum: 0 + type: integer + matchExpression: + $ref: '#/components/schemas/MatchExpression' + maxAgeSeconds: + format: int32 + minimum: -1 + type: integer + maxSizeBytes: + format: int32 + minimum: -1 + type: integer + name: + pattern: \S + type: string + preservedArchives: + format: int32 + minimum: 0 + type: integer + required: + - name + - description + - matchExpression + - eventSpecifier + type: object + SerializableEventTypeInfo: + properties: + category: + items: + type: string + type: array + description: + type: string + name: + type: string + options: + additionalProperties: + $ref: '#/components/schemas/SerializableOptionDescriptor' + type: object + typeId: + type: string + type: object + SerializableOptionDescriptor: + properties: + defaultValue: + type: string + description: + type: string + name: + type: string + type: object + Suggestion: + properties: + name: + type: string + setting: + type: string + value: + type: string + type: object + Target: + properties: + agent: + type: boolean + alias: + pattern: \S + type: string + annotations: + $ref: '#/components/schemas/Annotations' + connectUrl: + format: uri + type: string + id: + format: int64 + type: integer + jvmId: + type: string + labels: + additionalProperties: + type: string + type: object + required: + - connectUrl + - alias + - labels + - annotations + type: object + Template: + properties: + description: + type: string + name: + type: string + provider: + type: string + type: + $ref: '#/components/schemas/TemplateType' + type: object + TemplateType: + enum: + - TARGET + - CUSTOM + type: string + UUID: + format: uuid + pattern: '[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}' + type: string + V2Response: + properties: + data: + $ref: '#/components/schemas/Data' + meta: + $ref: '#/components/schemas/Meta' + type: object + securitySchemes: + SecurityScheme: + description: Authentication + scheme: basic + type: http +info: + contact: + email: cryostat-development@googlegroups.com + name: Cryostat Community + url: https://cryostat.io + description: Cloud-Native JDK Flight Recorder + license: + name: Apache 2.0 + url: https://github.com/cryostatio/cryostat3/blob/main/LICENSE + title: Cryostat API + version: 3.0.0-snapshot +openapi: 3.0.3 +paths: + /api/beta/fs/recordings: + get: + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ArchivedRecordingDirectory' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/beta/fs/recordings/{jvmId}: + get: + parameters: + - in: path + name: jvmId + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ArchivedRecordingDirectory' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/beta/fs/recordings/{jvmId}/{filename}: + delete: + parameters: + - in: path + name: filename + required: true + schema: + type: string + - in: path + name: jvmId + required: true + schema: + type: string + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/beta/fs/recordings/{jvmId}/{filename}/upload: + post: + parameters: + - in: path + name: filename + required: true + schema: + type: string + - in: path + name: jvmId + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/beta/matchExpressions: + get: + responses: + "200": + content: + application/json: + schema: + items: + additionalProperties: {} + type: object + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Match Expressions + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RequestData' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Match Expressions + /api/beta/matchExpressions/{id}: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/MatchedExpression' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Match Expressions + /api/beta/recordings/{connectUrl}/{filename}: + delete: + parameters: + - in: path + name: connectUrl + required: true + schema: + type: string + - in: path + name: filename + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/beta/recordings/{jvmId}: + get: + parameters: + - in: path + name: jvmId + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ArchivedRecording' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + post: + parameters: + - in: path + name: jvmId + required: true + schema: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + labels: + $ref: '#/components/schemas/JsonObject' + maxFiles: + format: int32 + type: integer + recording: + $ref: '#/components/schemas/FileUpload' + type: object + responses: + "201": + description: Created + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/grafana_dashboard_url: + get: + responses: + "200": + description: OK + tags: + - Health + /api/v1/grafana_datasource_url: + get: + responses: + "200": + description: OK + tags: + - Health + /api/v1/recordings: + get: + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ArchivedRecording' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + post: + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + labels: + $ref: '#/components/schemas/JsonObject' + recording: + $ref: '#/components/schemas/FileUpload' + type: object + responses: + "200": + content: + application/json: + schema: + additionalProperties: {} + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/recordings/{filename}: + delete: + parameters: + - in: path + name: filename + required: true + schema: + type: string + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/reports/{recordingName}: + get: + deprecated: true + parameters: + - in: path + name: recordingName + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Reports + /api/v1/targets: + get: + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Targets + /api/v1/targets/{connectUrl}/events: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: query + name: q + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Events + /api/v1/targets/{connectUrl}/recordingOptions: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + patch: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/targets/{connectUrl}/recordings: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + post: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/targets/{connectUrl}/recordings/{recordingName}: + delete: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: path + name: recordingName + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + patch: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: path + name: recordingName + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/targets/{connectUrl}/recordings/{recordingName}/upload: + post: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: path + name: recordingName + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/targets/{connectUrl}/snapshot: + post: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + content: + application/json: {} + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v1/targets/{connectUrl}/templates: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v1/targets/{connectUrl}/templates/{templateName}/type/{templateType}: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: path + name: templateName + required: true + schema: + type: string + - in: path + name: templateType + required: true + schema: + $ref: '#/components/schemas/TemplateType' + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v1/targets/{targetId}/reports/{recordingName}: + get: + deprecated: true + parameters: + - in: path + name: recordingName + required: true + schema: + type: string + - in: path + name: targetId + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Reports + /api/v1/templates: + post: + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + template: + $ref: '#/components/schemas/FileUpload' + type: object + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v1/templates/{templateName}: + delete: + parameters: + - in: path + name: templateName + required: true + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v2.1/auth: + post: + responses: + "200": + description: OK + tags: + - Auth + /api/v2.1/discovery: + get: + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + /api/v2.1/logout: + post: + responses: + "200": + description: OK + tags: + - Auth + /api/v2.1/targets/{connectUrl}/templates/{templateName}/type/{templateType}: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: path + name: templateName + required: true + schema: + type: string + - in: path + name: templateType + required: true + schema: + $ref: '#/components/schemas/TemplateType' + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v2.2/credentials: + get: + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Credentials + post: + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + matchExpression: + type: string + password: + type: string + username: + type: string + type: object + responses: + "201": + description: Created + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Credentials + /api/v2.2/credentials/{id}: + delete: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Credentials + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Credentials + /api/v2.2/discovery: + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + responses: + "200": + content: + application/json: + schema: + additionalProperties: {} + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + /api/v2.2/discovery/{id}: + delete: + parameters: + - in: path + name: id + required: true + schema: + $ref: '#/components/schemas/UUID' + - in: query + name: token + schema: + type: string + responses: + "200": + content: + application/json: + schema: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + description: OK + tags: + - Discovery + get: + parameters: + - in: path + name: id + required: true + schema: + $ref: '#/components/schemas/UUID' + - in: query + name: token + schema: + type: string + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + post: + parameters: + - in: path + name: id + required: true + schema: + $ref: '#/components/schemas/UUID' + - in: query + name: token + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/DiscoveryNode' + type: array + responses: + "200": + content: + application/json: + schema: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + description: OK + tags: + - Discovery + /api/v2.2/graphql: + get: + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Graph QL + post: + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Graph QL + /api/v2/rules: + get: + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Rules + post: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + application/x-www-form-urlencoded: + schema: + properties: + archivalPeriodSeconds: + format: int32 + type: integer + description: + type: string + enabled: + type: boolean + eventSpecifier: + type: string + initialDelaySeconds: + format: int32 + type: integer + matchExpression: + type: string + maxAgeSeconds: + format: int32 + type: integer + maxSizeBytes: + format: int32 + type: integer + name: + type: string + preservedArchives: + format: int32 + type: integer + type: object + multipart/form-data: + schema: + properties: + archivalPeriodSeconds: + format: int32 + type: integer + description: + type: string + enabled: + type: boolean + eventSpecifier: + type: string + initialDelaySeconds: + format: int32 + type: integer + matchExpression: + type: string + maxAgeSeconds: + format: int32 + type: integer + maxSizeBytes: + format: int32 + type: integer + name: + type: string + preservedArchives: + format: int32 + type: integer + type: object + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Rules + /api/v2/rules/{name}: + delete: + parameters: + - in: path + name: name + required: true + schema: + type: string + - in: query + name: clean + schema: + type: boolean + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Rules + get: + parameters: + - in: path + name: name + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Rules + patch: + parameters: + - in: path + name: name + required: true + schema: + type: string + - in: query + name: clean + schema: + type: boolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Rules + /api/v2/targets: + post: + parameters: + - in: query + name: dryrun + schema: + type: boolean + - in: query + name: storeCredentials + schema: + type: boolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Target' + application/x-www-form-urlencoded: + schema: + properties: + alias: + type: string + connectUrl: + format: uri + type: string + password: + type: string + username: + type: string + type: object + multipart/form-data: + schema: + properties: + alias: + type: string + connectUrl: + format: uri + type: string + password: + type: string + username: + type: string + type: object + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Custom Discovery + /api/v2/targets/{connectUrl}: + delete: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Custom Discovery + /api/v2/targets/{connectUrl}/events: + get: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + - in: query + name: q + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/V2Response' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Events + /api/v2/targets/{connectUrl}/snapshot: + post: + parameters: + - in: path + name: connectUrl + required: true + schema: + format: uri + type: string + responses: + "200": + content: + application/json: {} + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/activedownload/{id}: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/discovery: + get: + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/DiscoveryNode' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + /api/v3/discovery_plugins: + get: + parameters: + - in: query + name: realm + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + /api/v3/discovery_plugins/{id}: + get: + parameters: + - in: path + name: id + required: true + schema: + $ref: '#/components/schemas/UUID' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/DiscoveryPlugin' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Discovery + /api/v3/download/{encodedKey}: + get: + parameters: + - in: path + name: encodedKey + required: true + schema: + type: string + - in: query + name: f + schema: + type: string + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/event_templates: + get: + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/Template' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + post: + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + template: + $ref: '#/components/schemas/FileUpload' + type: object + responses: + "201": + description: Created + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v3/event_templates/{templateName}: + delete: + parameters: + - in: path + name: templateName + required: true + schema: + type: string + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v3/grafana/{encodedKey}: + post: + parameters: + - in: path + name: encodedKey + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + type: string + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/reports/{encodedKey}: + get: + parameters: + - in: path + name: encodedKey + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + additionalProperties: + $ref: '#/components/schemas/AnalysisResult' + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Reports + /api/v3/targets: + get: + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/Target' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Targets + /api/v3/targets/{id}: + delete: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Custom Discovery + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Target' + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Targets + /api/v3/targets/{id}/event_templates: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/Template' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v3/targets/{id}/event_templates/{templateType}/{templateName}: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + - in: path + name: templateName + required: true + schema: + type: string + - in: path + name: templateType + required: true + schema: + $ref: '#/components/schemas/TemplateType' + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Event Templates + /api/v3/targets/{id}/events: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + - in: query + name: q + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/SerializableEventTypeInfo' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Events + /api/v3/targets/{id}/recordingOptions: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + additionalProperties: {} + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + patch: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + maxAge: + type: string + maxSize: + type: string + toDisk: + type: string + type: object + responses: + "200": + content: + application/json: + schema: + additionalProperties: {} + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/targets/{id}/recordings: + get: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/LinkedRecordingDescriptor' + type: array + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + post: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + archiveOnStop: + nullable: true + type: boolean + duration: + format: int64 + nullable: true + type: integer + events: + type: string + maxAge: + format: int64 + nullable: true + type: integer + maxSize: + format: int64 + nullable: true + type: integer + metadata: + nullable: true + type: string + recordingName: + type: string + replace: + nullable: true + type: string + restart: + nullable: true + type: boolean + toDisk: + nullable: true + type: boolean + type: object + responses: + "200": + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/targets/{id}/snapshot: + post: + parameters: + - in: path + name: id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: {} + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/targets/{targetId}/recordings/{remoteId}: + delete: + parameters: + - in: path + name: remoteId + required: true + schema: + format: int64 + type: integer + - in: path + name: targetId + required: true + schema: + format: int64 + type: integer + responses: + "204": + description: No Content + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + patch: + parameters: + - in: path + name: remoteId + required: true + schema: + format: int64 + type: integer + - in: path + name: targetId + required: true + schema: + format: int64 + type: integer + requestBody: + content: + application/json: + schema: + type: string + responses: + "200": + content: + application/json: + schema: + type: string + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/targets/{targetId}/recordings/{remoteId}/upload: + post: + parameters: + - in: path + name: remoteId + required: true + schema: + format: int64 + type: integer + - in: path + name: targetId + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + type: string + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Recordings + /api/v3/targets/{targetId}/reports/{recordingId}: + get: + deprecated: true + parameters: + - in: path + name: recordingId + required: true + schema: + format: int64 + type: integer + - in: path + name: targetId + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + schema: + additionalProperties: + $ref: '#/components/schemas/AnalysisResult' + type: object + description: OK + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] + tags: + - Reports + /health: + get: + responses: + "200": + description: OK + tags: + - Health + /health/liveness: + get: + responses: + "204": + description: No Content + tags: + - Health diff --git a/schema/update.bash b/schema/update.bash new file mode 100755 index 000000000..07d109017 --- /dev/null +++ b/schema/update.bash @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +DIR="$(dirname "$(readlink -f "$0")")" + +"${DIR}"/../mvnw -f "${DIR}/../pom.xml" -B -U clean compile test-compile +"${DIR}"/../mvnw -f "${DIR}/../pom.xml" -B -U -DskipTests -Dspotless.check.skip -Dquarkus.smallrye-openapi.info-title="Cryostat API" clean quarkus:dev & +pid="$!" +function cleanup() { + kill $pid +} +trap cleanup EXIT +set +e +sleep "${1:-30}" +counter=0 +while true; do + if [ "${counter}" -gt 10 ]; then + exit 1 + fi + if wget --spider http://localhost:8181/health; then + break + else + counter=$((counter + 1)) + sleep "${2:-10}" + fi +done +wget http://localhost:8181/api -O - | yq -P 'sort_keys(..)' > "${DIR}/openapi.yaml" +# wget http://localhost:8181/api/v3/graphql/schema.graphql -O "${DIR}/schema.graphql" diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2d03d8f40..9589478fa 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -30,7 +30,7 @@ quarkus.http.limits.max-form-attribute-size=1G quarkus.http.limits.max-body-size=1G quarkus.vertx.prefer-native-transport=true -quarkus.smallrye-openapi.path=/api/v3 +quarkus.smallrye-openapi.path=/api quarkus.smallrye-openapi.info-title=Cryostat API quarkus.smallrye-openapi.info-version=${quarkus.application.version} quarkus.smallrye-openapi.info-description=Cloud-Native JDK Flight Recorder