From 21f10d752dd172c04cca55c3c667b84cd4c23c16 Mon Sep 17 00:00:00 2001 From: Fu Chen Date: Fri, 24 Dec 2021 19:29:14 +0800 Subject: [PATCH] [KYUUBI #1614] Fix hardcoded version in OpenAPIDefinition ### _Why are the changes needed?_ close #1614 curl http://0.0.0.0:10099/openapi.json ```json { "openapi" : "3.0.1", "info" : { "title" : "Apache Kyuubi REST API Documentation", "description" : "Apache Kyuubi REST API Documentation", "contact" : { "name" : "Apache Kyuubi Community", "url" : "https://kyuubi.apache.org/issue_tracking.html", "email" : "devkyuubi.apache.org" }, "license" : { "name" : "Apache 2.0", "url" : "https://www.apache.org/licenses/LICENSE-2.0.html" }, "version" : "1.5.0-SNAPSHOT" }, "tags" : [ { "name" : "Session" }, { "name" : "Operation" } ], "paths" : { "/api/v1/operations/{operationHandle}" : { "put" : { "tags" : [ "Operation" ], "operationId" : "applyOpAction", "parameters" : [ { "name" : "operationHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/OpActionRequest" } } } }, "responses" : { "200" : { "description" : "apply an action for an operation", "content" : { "application/json" : { } } } } } }, "/api/v1/operations/{operationHandle}/event" : { "get" : { "tags" : [ "Operation" ], "operationId" : "getOperationEvent", "parameters" : [ { "name" : "operationHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Get an operation event", "content" : { "application/json" : { } } } } } }, "/api/v1/operations/{operationHandle}/resultsetmetadata" : { "get" : { "tags" : [ "Operation" ], "operationId" : "getResultSetMetadata", "parameters" : [ { "name" : "operationHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "get result set metadata", "content" : { "application/json" : { } } } } } }, "/api/v1/ping" : { "get" : { "operationId" : "ping", "responses" : { "default" : { "description" : "default response", "content" : { "text/plain" : { "schema" : { "type" : "string" } } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/{operationHandle}" : { "delete" : { "tags" : [ "Session" ], "operationId" : "closeOperation", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } }, { "name" : "operationHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Close an operation", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}" : { "get" : { "tags" : [ "Session" ], "operationId" : "sessionInfo", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "get a session event via session handle identifier", "content" : { "application/json" : { } } } } }, "delete" : { "tags" : [ "Session" ], "operationId" : "closeSession", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Close a session", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/execPool/statistic" : { "get" : { "tags" : [ "Session" ], "operationId" : "execPoolStatistic", "responses" : { "200" : { "description" : "Get statistic info of background executors", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/statement" : { "post" : { "tags" : [ "Session" ], "operationId" : "executeStatement", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/StatementRequest" } } } }, "responses" : { "200" : { "description" : "Create an operation with EXECUTE_STATEMENT type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/catalogs" : { "post" : { "tags" : [ "Session" ], "operationId" : "getCatalogs", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Create an operation with GET_CATALOGS type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/columns" : { "post" : { "tags" : [ "Session" ], "operationId" : "getColumns", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/GetColumnsRequest" } } } }, "responses" : { "200" : { "description" : "Create an operation with GET_COLUMNS type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/functions" : { "post" : { "tags" : [ "Session" ], "operationId" : "getFunctions", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/GetFunctionsRequest" } } } }, "responses" : { "200" : { "description" : "Create an operation with GET_FUNCTIONS type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/info/{infoType}" : { "get" : { "tags" : [ "Session" ], "operationId" : "getInfo", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } }, { "name" : "infoType", "in" : "path", "required" : true, "schema" : { "type" : "integer", "format" : "int32" } } ], "responses" : { "200" : { "description" : "get a information detail via session handle identifier and a specific information type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/schemas" : { "post" : { "tags" : [ "Session" ], "operationId" : "getSchemas", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/GetSchemasRequest" } } } }, "responses" : { "200" : { "description" : "Create an operation with GET_SCHEMAS type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/tableTypes" : { "post" : { "tags" : [ "Session" ], "operationId" : "getTableTypes", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Create an operation with GET_TABLE_TYPES type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/tables" : { "post" : { "tags" : [ "Session" ], "operationId" : "getTables", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "requestBody" : { "content" : { "*/*" : { "schema" : { "$ref" : "#/components/schemas/GetTablesRequest" } } } }, "responses" : { "200" : { "description" : "Create an operation with GET_TABLES type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/{sessionHandle}/operations/typeInfo" : { "post" : { "tags" : [ "Session" ], "operationId" : "getTypeInfo", "parameters" : [ { "name" : "sessionHandle", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "200" : { "description" : "Create an operation with GET_TYPE_INFO type", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions" : { "get" : { "tags" : [ "Session" ], "operationId" : "sessionInfoList", "responses" : { "200" : { "description" : "get all the session list hosted in SessionManager", "content" : { "application/json" : { } } } } }, "post" : { "tags" : [ "Session" ], "operationId" : "openSession", "requestBody" : { "content" : { "application/json" : { "schema" : { "$ref" : "#/components/schemas/SessionOpenRequest" } } } }, "responses" : { "200" : { "description" : "Open(create) a session", "content" : { "application/json" : { } } } } } }, "/api/v1/sessions/count" : { "get" : { "tags" : [ "Session" ], "operationId" : "sessionCount", "responses" : { "200" : { "description" : "Get the current open session count", "content" : { "application/json" : { } } } } } }, "/api/v1/swagger-ui" : { "get" : { "operationId" : "swaggerUi", "responses" : { "default" : { "description" : "default response", "content" : { "text/html" : { } } } } } }, "/api/v1/exception" : { "get" : { "operationId" : "test", "responses" : { "default" : { "description" : "default response", "content" : { "text/plain" : { } } } } } }, "/application.wadl/{path}" : { "get" : { "operationId" : "getExternalGrammar", "parameters" : [ { "name" : "path", "in" : "path", "required" : true, "schema" : { "type" : "string" } } ], "responses" : { "default" : { "description" : "default response", "content" : { "application/xml" : { } } } } } }, "/application.wadl" : { "get" : { "operationId" : "getWadl", "responses" : { "default" : { "description" : "default response", "content" : { "application/vnd.sun.wadl+xml" : { }, "application/xml" : { } } } } } } }, "components" : { "schemas" : { "OpActionRequest" : { "required" : [ "action" ], "type" : "object", "properties" : { "action" : { "type" : "string" } } }, "KyuubiOperationEvent" : { "required" : [ "eventTime", "shouldRunAsync", "statementId" ], "type" : "object", "properties" : { "statementId" : { "type" : "string" }, "remoteId" : { "type" : "string" }, "statement" : { "type" : "string" }, "shouldRunAsync" : { "type" : "boolean" }, "state" : { "type" : "string" }, "eventTime" : { "type" : "integer", "format" : "int64" }, "createTime" : { "type" : "integer", "format" : "int64" }, "startTime" : { "type" : "integer", "format" : "int64" }, "completeTime" : { "type" : "integer", "format" : "int64" }, "exception" : { "type" : "object", "properties" : { "cause" : { "required" : [ "stackTrace", "suppressed" ], "type" : "object", "properties" : { "stackTrace" : { "type" : "array", "items" : { "required" : [ "lineNumber" ], "type" : "object", "properties" : { "methodName" : { "type" : "string" }, "fileName" : { "type" : "string" }, "lineNumber" : { "type" : "integer", "format" : "int32" }, "className" : { "type" : "string" }, "nativeMethod" : { "type" : "boolean" } } } }, "message" : { "type" : "string" }, "localizedMessage" : { "type" : "string" }, "suppressed" : { "type" : "array", "items" : { "type" : "object", "properties" : { "stackTrace" : { "type" : "array", "items" : { "required" : [ "lineNumber" ], "type" : "object", "properties" : { "methodName" : { "type" : "string" }, "fileName" : { "type" : "string" }, "lineNumber" : { "type" : "integer", "format" : "int32" }, "className" : { "type" : "string" }, "nativeMethod" : { "type" : "boolean" } } } }, "message" : { "type" : "string" }, "localizedMessage" : { "type" : "string" } } } } } }, "stackTrace" : { "type" : "array", "items" : { "required" : [ "lineNumber" ], "type" : "object", "properties" : { "methodName" : { "type" : "string" }, "fileName" : { "type" : "string" }, "lineNumber" : { "type" : "integer", "format" : "int32" }, "className" : { "type" : "string" }, "nativeMethod" : { "type" : "boolean" } } } }, "message" : { "type" : "string" }, "localizedMessage" : { "type" : "string" }, "suppressed" : { "type" : "array", "items" : { "type" : "object", "properties" : { "stackTrace" : { "type" : "array", "items" : { "required" : [ "lineNumber" ], "type" : "object", "properties" : { "methodName" : { "type" : "string" }, "fileName" : { "type" : "string" }, "lineNumber" : { "type" : "integer", "format" : "int32" }, "className" : { "type" : "string" }, "nativeMethod" : { "type" : "boolean" } } } }, "message" : { "type" : "string" }, "localizedMessage" : { "type" : "string" } } } } } }, "sessionId" : { "type" : "string" }, "sessionUser" : { "type" : "string" }, "eventType" : { "type" : "string" } } }, "ColumnDesc" : { "required" : [ "columnIndex", "columnName" ], "type" : "object", "properties" : { "columnName" : { "type" : "string" }, "dataType" : { "type" : "string" }, "columnIndex" : { "type" : "integer", "format" : "int32" }, "precision" : { "type" : "integer", "format" : "int32" }, "scale" : { "type" : "integer", "format" : "int32" }, "comment" : { "type" : "string" } } }, "ResultSetMetaData" : { "required" : [ "columns" ], "type" : "object", "properties" : { "columns" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ColumnDesc" } } } }, "SeqColumnDesc" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/ColumnDesc" } }, "HandleIdentifier" : { "required" : [ "publicId" ], "type" : "object", "properties" : { "publicId" : { "type" : "string", "format" : "uuid" }, "secretId" : { "type" : "string", "format" : "uuid" } } }, "OperationHandle" : { "required" : [ "hasResultSet", "identifier", "protocol", "typ" ], "type" : "object", "properties" : { "identifier" : { "$ref" : "#/components/schemas/HandleIdentifier" }, "typ" : { "$ref" : "#/components/schemas/Value" }, "protocol" : { "type" : "string", "enum" : [ "HIVE_CLI_SERVICE_PROTOCOL_V1", "HIVE_CLI_SERVICE_PROTOCOL_V2", "HIVE_CLI_SERVICE_PROTOCOL_V3", "HIVE_CLI_SERVICE_PROTOCOL_V4", "HIVE_CLI_SERVICE_PROTOCOL_V5", "HIVE_CLI_SERVICE_PROTOCOL_V6", "HIVE_CLI_SERVICE_PROTOCOL_V7", "HIVE_CLI_SERVICE_PROTOCOL_V8", "HIVE_CLI_SERVICE_PROTOCOL_V9", "HIVE_CLI_SERVICE_PROTOCOL_V10" ] }, "hasResultSet" : { "type" : "boolean", "writeOnly" : true } } }, "Value" : { "type" : "object" }, "ExecPoolStatistic" : { "required" : [ "execPoolSize" ], "type" : "object", "properties" : { "execPoolSize" : { "type" : "integer", "format" : "int32" }, "execPoolActiveCount" : { "type" : "integer", "format" : "int32" } } }, "StatementRequest" : { "required" : [ "queryTimeout", "runAsync", "statement" ], "type" : "object", "properties" : { "statement" : { "type" : "string" }, "runAsync" : { "type" : "boolean" }, "queryTimeout" : { "type" : "integer", "format" : "int64" } } }, "GetColumnsRequest" : { "required" : [ "catalogName" ], "type" : "object", "properties" : { "catalogName" : { "type" : "string" }, "schemaName" : { "type" : "string" }, "tableName" : { "type" : "string" }, "columnName" : { "type" : "string" } } }, "GetFunctionsRequest" : { "required" : [ "catalogName" ], "type" : "object", "properties" : { "catalogName" : { "type" : "string" }, "schemaName" : { "type" : "string" }, "functionName" : { "type" : "string" } } }, "InfoDetail" : { "required" : [ "infoType" ], "type" : "object", "properties" : { "infoType" : { "type" : "string" }, "infoValue" : { "type" : "string" } } }, "GetSchemasRequest" : { "required" : [ "catalogName" ], "type" : "object", "properties" : { "catalogName" : { "type" : "string" }, "schemaName" : { "type" : "string" } } }, "GetTablesRequest" : { "required" : [ "catalogName", "tableTypes" ], "type" : "object", "properties" : { "catalogName" : { "type" : "string" }, "schemaName" : { "type" : "string" }, "tableName" : { "type" : "string" }, "tableTypes" : { "type" : "array", "items" : { "type" : "string" } } } }, "SessionHandle" : { "required" : [ "identifier", "protocol" ], "type" : "object", "properties" : { "identifier" : { "$ref" : "#/components/schemas/HandleIdentifier" }, "protocol" : { "type" : "string", "enum" : [ "HIVE_CLI_SERVICE_PROTOCOL_V1", "HIVE_CLI_SERVICE_PROTOCOL_V2", "HIVE_CLI_SERVICE_PROTOCOL_V3", "HIVE_CLI_SERVICE_PROTOCOL_V4", "HIVE_CLI_SERVICE_PROTOCOL_V5", "HIVE_CLI_SERVICE_PROTOCOL_V6", "HIVE_CLI_SERVICE_PROTOCOL_V7", "HIVE_CLI_SERVICE_PROTOCOL_V8", "HIVE_CLI_SERVICE_PROTOCOL_V9", "HIVE_CLI_SERVICE_PROTOCOL_V10" ] } } }, "MapStringString" : { "type" : "object", "additionalProperties" : { "type" : "string" } }, "SessionOpenRequest" : { "required" : [ "configs", "protocolVersion", "user" ], "type" : "object", "properties" : { "protocolVersion" : { "type" : "integer", "format" : "int32" }, "user" : { "type" : "string" }, "password" : { "type" : "string" }, "ipAddr" : { "type" : "string" }, "configs" : { "type" : "object", "additionalProperties" : { "type" : "string" } } } }, "SessionOpenCount" : { "required" : [ "openSessionCount" ], "type" : "object", "properties" : { "openSessionCount" : { "type" : "integer", "format" : "int32" } } }, "KyuubiSessionEvent" : { "required" : [ "clientVersion", "conf", "sessionName", "startTime" ], "type" : "object", "properties" : { "sessionName" : { "type" : "string" }, "user" : { "type" : "string" }, "clientIP" : { "type" : "string" }, "serverIP" : { "type" : "string" }, "conf" : { "type" : "object", "additionalProperties" : { "type" : "string" } }, "startTime" : { "type" : "integer", "format" : "int64" }, "sessionId" : { "type" : "string" }, "remoteSessionId" : { "type" : "string" }, "clientVersion" : { "type" : "integer", "format" : "int32" }, "openedTime" : { "type" : "integer", "format" : "int64" }, "endTime" : { "type" : "integer", "format" : "int64" }, "totalOperations" : { "type" : "integer", "format" : "int32" }, "eventType" : { "type" : "string" } } }, "SeqSessionOverview" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/SessionOverview" } }, "SessionList" : { "required" : [ "sessionList" ], "type" : "object", "properties" : { "sessionList" : { "type" : "array", "items" : { "$ref" : "#/components/schemas/SessionOverview" } } } }, "SessionOverview" : { "required" : [ "createTime", "user" ], "type" : "object", "properties" : { "user" : { "type" : "string" }, "ipAddr" : { "type" : "string" }, "createTime" : { "type" : "integer", "format" : "int64" }, "sessionHandle" : { "$ref" : "#/components/schemas/SessionHandle" } } } } } } ``` curl http://0.0.0.0:10099/openapi.yaml ```yaml openapi: 3.0.1 info: title: Apache Kyuubi REST API Documentation description: Apache Kyuubi REST API Documentation contact: name: Apache Kyuubi Community url: https://kyuubi.apache.org/issue_tracking.html email: devkyuubi.apache.org license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html version: 1.5.0-SNAPSHOT tags: - name: Session - name: Operation paths: /api/v1/operations/{operationHandle}: put: tags: - Operation operationId: applyOpAction parameters: - name: operationHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/OpActionRequest' responses: "200": description: apply an action for an operation content: application/json: {} /api/v1/operations/{operationHandle}/event: get: tags: - Operation operationId: getOperationEvent parameters: - name: operationHandle in: path required: true schema: type: string responses: "200": description: Get an operation event content: application/json: {} /api/v1/operations/{operationHandle}/resultsetmetadata: get: tags: - Operation operationId: getResultSetMetadata parameters: - name: operationHandle in: path required: true schema: type: string responses: "200": description: get result set metadata content: application/json: {} /api/v1/ping: get: operationId: ping responses: default: description: default response content: text/plain: schema: type: string /api/v1/sessions/{sessionHandle}/operations/{operationHandle}: delete: tags: - Session operationId: closeOperation parameters: - name: sessionHandle in: path required: true schema: type: string - name: operationHandle in: path required: true schema: type: string responses: "200": description: Close an operation content: application/json: {} /api/v1/sessions/{sessionHandle}: get: tags: - Session operationId: sessionInfo parameters: - name: sessionHandle in: path required: true schema: type: string responses: "200": description: get a session event via session handle identifier content: application/json: {} delete: tags: - Session operationId: closeSession parameters: - name: sessionHandle in: path required: true schema: type: string responses: "200": description: Close a session content: application/json: {} /api/v1/sessions/execPool/statistic: get: tags: - Session operationId: execPoolStatistic responses: "200": description: Get statistic info of background executors content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/statement: post: tags: - Session operationId: executeStatement parameters: - name: sessionHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/StatementRequest' responses: "200": description: Create an operation with EXECUTE_STATEMENT type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/catalogs: post: tags: - Session operationId: getCatalogs parameters: - name: sessionHandle in: path required: true schema: type: string responses: "200": description: Create an operation with GET_CATALOGS type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/columns: post: tags: - Session operationId: getColumns parameters: - name: sessionHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/GetColumnsRequest' responses: "200": description: Create an operation with GET_COLUMNS type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/functions: post: tags: - Session operationId: getFunctions parameters: - name: sessionHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/GetFunctionsRequest' responses: "200": description: Create an operation with GET_FUNCTIONS type content: application/json: {} /api/v1/sessions/{sessionHandle}/info/{infoType}: get: tags: - Session operationId: getInfo parameters: - name: sessionHandle in: path required: true schema: type: string - name: infoType in: path required: true schema: type: integer format: int32 responses: "200": description: get a information detail via session handle identifier and a specific information type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/schemas: post: tags: - Session operationId: getSchemas parameters: - name: sessionHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/GetSchemasRequest' responses: "200": description: Create an operation with GET_SCHEMAS type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/tableTypes: post: tags: - Session operationId: getTableTypes parameters: - name: sessionHandle in: path required: true schema: type: string responses: "200": description: Create an operation with GET_TABLE_TYPES type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/tables: post: tags: - Session operationId: getTables parameters: - name: sessionHandle in: path required: true schema: type: string requestBody: content: '*/*': schema: $ref: '#/components/schemas/GetTablesRequest' responses: "200": description: Create an operation with GET_TABLES type content: application/json: {} /api/v1/sessions/{sessionHandle}/operations/typeInfo: post: tags: - Session operationId: getTypeInfo parameters: - name: sessionHandle in: path required: true schema: type: string responses: "200": description: Create an operation with GET_TYPE_INFO type content: application/json: {} /api/v1/sessions: get: tags: - Session operationId: sessionInfoList responses: "200": description: get all the session list hosted in SessionManager content: application/json: {} post: tags: - Session operationId: openSession requestBody: content: application/json: schema: $ref: '#/components/schemas/SessionOpenRequest' responses: "200": description: Open(create) a session content: application/json: {} /api/v1/sessions/count: get: tags: - Session operationId: sessionCount responses: "200": description: Get the current open session count content: application/json: {} /api/v1/swagger-ui: get: operationId: swaggerUi responses: default: description: default response content: text/html: {} /api/v1/exception: get: operationId: test responses: default: description: default response content: text/plain: {} /application.wadl/{path}: get: operationId: getExternalGrammar parameters: - name: path in: path required: true schema: type: string responses: default: description: default response content: application/xml: {} /application.wadl: get: operationId: getWadl responses: default: description: default response content: application/vnd.sun.wadl+xml: {} application/xml: {} components: schemas: OpActionRequest: required: - action type: object properties: action: type: string KyuubiOperationEvent: required: - eventTime - shouldRunAsync - statementId type: object properties: statementId: type: string remoteId: type: string statement: type: string shouldRunAsync: type: boolean state: type: string eventTime: type: integer format: int64 createTime: type: integer format: int64 startTime: type: integer format: int64 completeTime: type: integer format: int64 exception: type: object properties: cause: required: - stackTrace - suppressed type: object properties: stackTrace: type: array items: required: - lineNumber type: object properties: methodName: type: string fileName: type: string lineNumber: type: integer format: int32 className: type: string nativeMethod: type: boolean message: type: string localizedMessage: type: string suppressed: type: array items: type: object properties: stackTrace: type: array items: required: - lineNumber type: object properties: methodName: type: string fileName: type: string lineNumber: type: integer format: int32 className: type: string nativeMethod: type: boolean message: type: string localizedMessage: type: string stackTrace: type: array items: required: - lineNumber type: object properties: methodName: type: string fileName: type: string lineNumber: type: integer format: int32 className: type: string nativeMethod: type: boolean message: type: string localizedMessage: type: string suppressed: type: array items: type: object properties: stackTrace: type: array items: required: - lineNumber type: object properties: methodName: type: string fileName: type: string lineNumber: type: integer format: int32 className: type: string nativeMethod: type: boolean message: type: string localizedMessage: type: string sessionId: type: string sessionUser: type: string eventType: type: string ColumnDesc: required: - columnIndex - columnName type: object properties: columnName: type: string dataType: type: string columnIndex: type: integer format: int32 precision: type: integer format: int32 scale: type: integer format: int32 comment: type: string ResultSetMetaData: required: - columns type: object properties: columns: type: array items: $ref: '#/components/schemas/ColumnDesc' SeqColumnDesc: type: array items: $ref: '#/components/schemas/ColumnDesc' HandleIdentifier: required: - publicId type: object properties: publicId: type: string format: uuid secretId: type: string format: uuid OperationHandle: required: - hasResultSet - identifier - protocol - typ type: object properties: identifier: $ref: '#/components/schemas/HandleIdentifier' typ: $ref: '#/components/schemas/Value' protocol: type: string enum: - HIVE_CLI_SERVICE_PROTOCOL_V1 - HIVE_CLI_SERVICE_PROTOCOL_V2 - HIVE_CLI_SERVICE_PROTOCOL_V3 - HIVE_CLI_SERVICE_PROTOCOL_V4 - HIVE_CLI_SERVICE_PROTOCOL_V5 - HIVE_CLI_SERVICE_PROTOCOL_V6 - HIVE_CLI_SERVICE_PROTOCOL_V7 - HIVE_CLI_SERVICE_PROTOCOL_V8 - HIVE_CLI_SERVICE_PROTOCOL_V9 - HIVE_CLI_SERVICE_PROTOCOL_V10 hasResultSet: type: boolean writeOnly: true Value: type: object ExecPoolStatistic: required: - execPoolSize type: object properties: execPoolSize: type: integer format: int32 execPoolActiveCount: type: integer format: int32 StatementRequest: required: - queryTimeout - runAsync - statement type: object properties: statement: type: string runAsync: type: boolean queryTimeout: type: integer format: int64 GetColumnsRequest: required: - catalogName type: object properties: catalogName: type: string schemaName: type: string tableName: type: string columnName: type: string GetFunctionsRequest: required: - catalogName type: object properties: catalogName: type: string schemaName: type: string functionName: type: string InfoDetail: required: - infoType type: object properties: infoType: type: string infoValue: type: string GetSchemasRequest: required: - catalogName type: object properties: catalogName: type: string schemaName: type: string GetTablesRequest: required: - catalogName - tableTypes type: object properties: catalogName: type: string schemaName: type: string tableName: type: string tableTypes: type: array items: type: string SessionHandle: required: - identifier - protocol type: object properties: identifier: $ref: '#/components/schemas/HandleIdentifier' protocol: type: string enum: - HIVE_CLI_SERVICE_PROTOCOL_V1 - HIVE_CLI_SERVICE_PROTOCOL_V2 - HIVE_CLI_SERVICE_PROTOCOL_V3 - HIVE_CLI_SERVICE_PROTOCOL_V4 - HIVE_CLI_SERVICE_PROTOCOL_V5 - HIVE_CLI_SERVICE_PROTOCOL_V6 - HIVE_CLI_SERVICE_PROTOCOL_V7 - HIVE_CLI_SERVICE_PROTOCOL_V8 - HIVE_CLI_SERVICE_PROTOCOL_V9 - HIVE_CLI_SERVICE_PROTOCOL_V10 MapStringString: type: object additionalProperties: type: string SessionOpenRequest: required: - configs - protocolVersion - user type: object properties: protocolVersion: type: integer format: int32 user: type: string password: type: string ipAddr: type: string configs: type: object additionalProperties: type: string SessionOpenCount: required: - openSessionCount type: object properties: openSessionCount: type: integer format: int32 KyuubiSessionEvent: required: - clientVersion - conf - sessionName - startTime type: object properties: sessionName: type: string user: type: string clientIP: type: string serverIP: type: string conf: type: object additionalProperties: type: string startTime: type: integer format: int64 sessionId: type: string remoteSessionId: type: string clientVersion: type: integer format: int32 openedTime: type: integer format: int64 endTime: type: integer format: int64 totalOperations: type: integer format: int32 eventType: type: string SeqSessionOverview: type: array items: $ref: '#/components/schemas/SessionOverview' SessionList: required: - sessionList type: object properties: sessionList: type: array items: $ref: '#/components/schemas/SessionOverview' SessionOverview: required: - createTime - user type: object properties: user: type: string ipAddr: type: string createTime: type: integer format: int64 sessionHandle: $ref: '#/components/schemas/SessionHandle' ``` ### _How was this patch tested?_ - [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible - [ ] Add screenshots for manual tests if appropriate - [ ] [Run test](https://kyuubi.readthedocs.io/en/latest/develop_tools/testing.html#running-tests) locally before make a pull request Closes #1628 from cfmcgrady/kyuubi-1614. Closes #1614 9310f5a0 [Fu Chen] address comment ef3cb812 [Fu Chen] fix hardcoded version in OpenAPIDefinition Authored-by: Fu Chen Signed-off-by: Kent Yao --- .../kyuubi/server/api/OpenAPIConfig.scala | 21 +--- .../server/api/v1/KyuubiOpenApiResource.scala | 100 ++++++++++++++++++ 2 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala index b9b1988ef..d519ab518 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala @@ -17,27 +17,12 @@ package org.apache.kyuubi.server.api -import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource -import io.swagger.v3.oas.annotations.OpenAPIDefinition -import io.swagger.v3.oas.annotations.info.{Contact, Info, License} -import io.swagger.v3.oas.annotations.tags.Tag import org.glassfish.jersey.server.ResourceConfig -@OpenAPIDefinition( - info = new Info( - title = "Apache Kyuubi REST API Documentation", - version = "1.4.0", - description = "Apache Kyuubi REST API Documentation", - contact = new Contact( - name = "Apache Kyuubi Community", - url = "https://kyuubi.apache.org/issue_tracking.html", - email = "dev@kyuubi.apache.org"), - license = new License( - name = "Apache 2.0", - url = "https://www.apache.org/licenses/LICENSE-2.0.html")), - tags = Array(new Tag(name = "Session"))) +import org.apache.kyuubi.server.api.v1.KyuubiOpenApiResource + class OpenAPIConfig extends ResourceConfig { packages("org.apache.kyuubi.server.api.v1") - register(classOf[OpenApiResource]); + register(classOf[KyuubiOpenApiResource]) register(classOf[KyuubiScalaObjectMapper]) } diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala new file mode 100644 index 000000000..d3e191596 --- /dev/null +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.kyuubi.server.api.v1 + +import javax.servlet.ServletConfig +import javax.ws.rs.{GET, Path, PathParam, Produces} +import javax.ws.rs.core.{Application, Context, HttpHeaders, MediaType, Response, UriInfo} + +import scala.collection.JavaConverters._ + +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter +import io.swagger.v3.jaxrs2.integration.JaxrsOpenApiContextBuilder +import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.integration.api.OpenApiContext +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.{Contact, Info, License} +import io.swagger.v3.oas.models.tags.Tag +import org.apache.commons.lang3.StringUtils + +@Path("/openapi.{type:json|yaml}") +class KyuubiOpenApiResource extends BaseOpenApiResource { + @Context + protected var config: ServletConfig = _ + + @Context + protected var app: Application = _ + + @GET + @Produces(Array(MediaType.APPLICATION_JSON, "application/yaml")) + @Operation(hidden = true) + def getOpenApi( + @Context headers: HttpHeaders, + @Context uriInfo: UriInfo, + @PathParam("type") tpe: String): Response = { + + val ctxId = getContextId(config) + val ctx: OpenApiContext = new KyuubiJaxrsOpenApiContextBuilder() + .servletConfig(config) + .application(app) + .resourcePackages(resourcePackages) + .configLocation(configLocation) + .openApiConfiguration(openApiConfiguration) + .ctxId(ctxId) + .buildContext(true) + + val openApi = setKyuubiOpenAPIDefinition(ctx.read()) + + if (StringUtils.isNotBlank(tpe) && tpe.trim().equalsIgnoreCase("yaml")) { + Response.status(Response.Status.OK) + .entity( + ctx.getOutputYamlMapper() + .writer(new DefaultPrettyPrinter()) + .writeValueAsString(openApi)) + .`type`("application/yaml") + .build() + } else { + Response.status(Response.Status.OK) + .entity( + ctx.getOutputJsonMapper + .writer(new DefaultPrettyPrinter()) + .writeValueAsString(openApi)) + .`type`(MediaType.APPLICATION_JSON_TYPE) + .build() + } + } + + private def setKyuubiOpenAPIDefinition(openApi: OpenAPI): OpenAPI = { + openApi.info( + new Info().title("Apache Kyuubi (Incubating) REST API Documentation") + .version(org.apache.kyuubi.KYUUBI_VERSION) + .description("Apache Kyuubi (Incubating) REST API Documentation") + .contact( + new Contact().name("Apache Kyuubi Community") + .url("https://kyuubi.apache.org/issue_tracking.html") + .email("dev@kyuubi.apache.org")) + .license( + new License().name("Apache License 2.0") + .url("https://www.apache.org/licenses/LICENSE-2.0.txt"))) + .tags(List(new Tag().name("Session"), new Tag().name("Operation")).asJava) + } +} + +class KyuubiJaxrsOpenApiContextBuilder + extends JaxrsOpenApiContextBuilder[KyuubiJaxrsOpenApiContextBuilder]