diff --git a/api/ks-openapi-spec/swagger.json b/api/ks-openapi-spec/swagger.json index b89b2b6c2..1466e5c5d 100644 --- a/api/ks-openapi-spec/swagger.json +++ b/api/ks-openapi-spec/swagger.json @@ -12,7 +12,7 @@ "name": "Apache", "url": "http://www.apache.org/licenses/" }, - "version": "2.0.2", + "version": "v0.0.0", "x-taggroups": [ { "name": "IAM", @@ -76,8 +76,7 @@ { "name": "Logging", "tags": [ - "Log Query", - "Fluent Bit Setting" + "Log Query" ] } ] @@ -112,88 +111,6 @@ } } }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project" - ], - "summary": "Get the specified DevOps Project", - "operationId": "GetDevOpsProjectHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - } - }, - "patch": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project" - ], - "summary": "Update the specified DevOps Project", - "operationId": "UpdateProjectHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - } - } - }, "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/checkCron": { "post": { "consumes": [ @@ -248,7 +165,7 @@ } } }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/credentials": { + "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/credentials/{credential}/usage": { "get": { "consumes": [ "application/json" @@ -259,178 +176,8 @@ "tags": [ "DevOps Project Credential" ], - "summary": "Get all credentials of the specified DevOps project", - "operationId": "GetDevOpsProjectCredentialsHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Credential" - ], - "summary": "Create a credential in the specified DevOps project", - "operationId": "CreateDevOpsProjectCredentialHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/credentials/{credential}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Credential" - ], - "summary": "Get the specified credential of the DevOps project", - "operationId": "GetDevOpsProjectCredentialHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "credential's ID, e.g. dockerhub-id", - "name": "credential", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "\nGet extra credential content if this query parameter is set. \nSpecifically, there are three types of info in a credential. One is the basic info that must be returned for each query such as name, id, etc.\nThe second one is non-encrypted info such as the username of the username-password type of credential, which returns when the \"content\" parameter is set to non-empty.\nThe last one is encrypted info, such as the password of the username-password type of credential, which never returns.\n", - "name": "content", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Credential" - ], - "summary": "Update the specified credential of the DevOps project", - "operationId": "UpdateDevOpsProjectCredentialHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "credential's ID, e.g. dockerhub-id", - "name": "credential", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.JenkinsCredential" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Credential" - ], - "summary": "Delete the specified credential of the DevOps project", - "operationId": "DeleteDevOpsProjectCredentialHandler", + "summary": "Get the specified credential usage of the DevOps project", + "operationId": "GetProjectCredentialUsage", "parameters": [ { "type": "string", @@ -447,331 +194,17 @@ "required": true } ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/defaultroles": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Get the build-in roles info of the specified DevOps project", - "operationId": "GetDevOpsProjectDefaultRoles", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - } - ], "responses": { "200": { "description": "ok", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.Role" - } + "$ref": "#/definitions/devops.Credential" } }, "default": { "description": "ok", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.Role" - } - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/members": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Get the members of the specified DevOps project", - "operationId": "GetDevOpsProjectMembersHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "format": "limit=%d,page=%d", - "default": "limit=10,page=1", - "description": "page", - "name": "paging", - "in": "query" - }, - { - "type": "string", - "format": "key=%s,key~%s", - "description": "query conditions, support using key-value pairs separated by comma to search, like 'conditions:somekey=somevalue,anotherkey=anothervalue'", - "name": "conditions", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Add a member to the specified DevOps project", - "operationId": "AddDevOpsProjectMemberHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/members/{member}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Get the specified member of the DevOps project", - "operationId": "GetDevOpsProjectMemberHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "member's username, e.g. admin", - "name": "member", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Delete the specified member of the DevOps project", - "operationId": "DeleteDevOpsProjectMemberHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "member's username, e.g. admin", - "name": "member", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "patch": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Project Member" - ], - "summary": "Update the specified member of the DevOps project", - "operationId": "UpdateDevOpsProjectMemberHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "member's username, e.g. admin", - "name": "member", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.DevOpsProjectMembership" - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Create a DevOps project pipeline", - "operationId": "CreateDevOpsProjectPipelineHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" + "$ref": "#/definitions/devops.Credential" } } } @@ -820,82 +253,6 @@ } } } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Update the specified pipeline of the DevOps project", - "operationId": "UpdateDevOpsProjectPipelineHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of pipeline, e.g. sample-pipeline", - "name": "pipeline", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Delete the specified pipeline of the DevOps project", - "operationId": "DeleteDevOpsProjectPipelineHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of pipeline, e.g. sample-pipeline", - "name": "pipeline", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK" - } - } } }, "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines/{pipeline}/branches": { @@ -910,7 +267,7 @@ "DevOps Pipeline" ], "summary": "(MultiBranchesPipeline) Get all branches in the specified pipeline.", - "operationId": "GetPipeBranch", + "operationId": "GetPipelineBranch", "parameters": [ { "type": "string", @@ -956,7 +313,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/devops.PipeBranch" + "$ref": "#/definitions/devops.PipelineBranch" } } }, @@ -965,7 +322,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/devops.PipeBranch" + "$ref": "#/definitions/devops.PipelineBranch" } } } @@ -983,7 +340,7 @@ "tags": [ "DevOps Pipeline" ], - "summary": "(MultiBranchesPipeline) Get all activities in the specified pipeline.", + "summary": "(MultiBranchesPipeline) Get the specified branch pipeline of the DevOps project", "operationId": "GetBranchPipeline", "parameters": [ { @@ -1072,13 +429,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.QueuedBlueRun" + "$ref": "#/definitions/devops.RunPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.QueuedBlueRun" + "$ref": "#/definitions/devops.RunPipeline" } } } @@ -1095,7 +452,7 @@ "tags": [ "DevOps Pipeline" ], - "summary": "(MultiBranchesPipeline) Get all runs in the specified branch", + "summary": "(MultiBranchesPipeline) Get details in the specified pipeline activity.", "operationId": "GetBranchPipelineRun", "parameters": [ { @@ -1131,13 +488,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.BranchPipelineRun" + "$ref": "#/definitions/devops.PipelineRun" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.BranchPipelineRun" + "$ref": "#/definitions/devops.PipelineRun" } } } @@ -1292,7 +649,7 @@ "DevOps Pipeline" ], "summary": "(MultiBranchesPipeline) Get run nodes.", - "operationId": "GetPipelineRunNodesbyBranch", + "operationId": "GetBranchPipelineRunNodes", "parameters": [ { "type": "string", @@ -1681,13 +1038,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.ReplayPipe" + "$ref": "#/definitions/devops.ReplayPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.ReplayPipe" + "$ref": "#/definitions/devops.ReplayPipeline" } } } @@ -1756,71 +1113,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.StopPipe" + "$ref": "#/definitions/devops.StopPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.StopPipe" - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines/{pipeline}/branches/{branch}/sonarstatus": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Get the sonar quality check information for the specified pipeline branch of the DevOps project. More info: https://docs.sonarqube.org/7.4/user-guide/metric-definitions/", - "operationId": "GetMultiBranchesPipelineSonarStatusHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of pipeline, e.g. sample-pipeline", - "name": "pipeline", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "branch name, e.g. master", - "name": "branch", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.SonarStatus" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.SonarStatus" - } + "$ref": "#/definitions/devops.StopPipeline" } } } @@ -1881,51 +1180,6 @@ } } }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines/{pipeline}/config": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Get the configuration information of the specified pipeline of the DevOps Project", - "operationId": "GetDevOpsProjectPipelineHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of pipeline, e.g. sample-pipeline", - "name": "pipeline", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/devops.ProjectPipeline" - } - } - } - } - }, "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines/{pipeline}/consolelog": { "get": { "consumes": [ @@ -1974,7 +1228,7 @@ "DevOps Pipeline" ], "summary": "Get all runs of the specified pipeline", - "operationId": "SearchPipelineRuns", + "operationId": "ListPipelineRuns", "parameters": [ { "type": "string", @@ -2016,13 +1270,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/struct%20%7B%20Items%20%7C%7Cdevops.BranchPipelineRun%20%22json:%5C%22items%5C%22%22;%20Total%20int%20%22json:%5C%22total_count%5C%22%22%20%7D" + "$ref": "#/definitions/devops.PipelineRunList" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/struct%20%7B%20Items%20%7C%7Cdevops.BranchPipelineRun%20%22json:%5C%22items%5C%22%22;%20Total%20int%20%22json:%5C%22total_count%5C%22%22%20%7D" + "$ref": "#/definitions/devops.PipelineRunList" } } } @@ -2067,13 +1321,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.QueuedBlueRun" + "$ref": "#/definitions/devops.RunPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.QueuedBlueRun" + "$ref": "#/definitions/devops.RunPipeline" } } } @@ -2090,7 +1344,7 @@ "tags": [ "DevOps Pipeline" ], - "summary": "Get all activities in the specified pipeline.", + "summary": "Get details in the specified pipeline activity.", "operationId": "GetPipelineRun", "parameters": [ { @@ -2612,13 +1866,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.ReplayPipe" + "$ref": "#/definitions/devops.ReplayPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.ReplayPipe" + "$ref": "#/definitions/devops.ReplayPipeline" } } } @@ -2680,13 +1934,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.StopPipe" + "$ref": "#/definitions/devops.StopPipeline" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/devops.StopPipe" + "$ref": "#/definitions/devops.StopPipeline" } } } @@ -2735,154 +1989,6 @@ } } }, - "/kapis/devops.kubesphere.io/v1alpha2/devops/{devops}/pipelines/{pipeline}/sonarstatus": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "DevOps Pipeline" - ], - "summary": "Get the sonar quality information for the specified pipeline of the DevOps project. More info: https://docs.sonarqube.org/7.4/user-guide/metric-definitions/", - "operationId": "GetPipelineSonarStatusHandler", - "parameters": [ - { - "type": "string", - "description": "DevOps project's ID, e.g. project-RRRRAzLBlLEm", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of pipeline, e.g. sample-pipeline", - "name": "pipeline", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.SonarStatus" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.SonarStatus" - } - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/namespaces/{namespace}/s2ibinaries/{s2ibinary}/file": { - "put": { - "consumes": [ - "multipart/form-data" - ], - "produces": [ - "application/json" - ], - "summary": "Upload S2iBinary file", - "operationId": "UploadS2iBinary", - "parameters": [ - { - "type": "string", - "description": "the name of namespaces", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of s2ibinary", - "name": "s2ibinary", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "file to upload", - "name": "s2ibinary", - "in": "formData" - }, - { - "type": "string", - "description": "md5 of file", - "name": "md5", - "in": "formData" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha1.S2iBinary" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha1.S2iBinary" - } - } - } - } - }, - "/kapis/devops.kubesphere.io/v1alpha2/namespaces/{namespace}/s2ibinaries/{s2ibinary}/file/{file}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/octet-stream" - ], - "summary": "Download S2iBinary file", - "operationId": "DownloadS2iBinary", - "parameters": [ - { - "type": "string", - "description": "the name of namespaces", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of s2ibinary", - "name": "s2ibinary", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of binary file", - "name": "file", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok" - }, - "default": { - "description": "ok" - } - } - } - }, "/kapis/devops.kubesphere.io/v1alpha2/scms/{scm}/organizations": { "get": { "consumes": [ @@ -3148,7 +2254,7 @@ "DevOps Pipeline" ], "summary": "Search DevOps resource. More info: https://github.com/jenkinsci/blueocean-plugin/tree/master/blueocean-rest#get-pipelines-across-organization", - "operationId": "SearchPipelines", + "operationId": "ListPipelines", "parameters": [ { "type": "string", @@ -3184,13 +2290,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/struct%20%7B%20Items%20%7C%7Cdevops.Pipeline%20%22json:%5C%22items%5C%22%22;%20Total%20int%20%22json:%5C%22total_count%5C%22%22%20%7D" + "$ref": "#/definitions/devops.PipelineList" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/struct%20%7B%20Items%20%7C%7Cdevops.Pipeline%20%22json:%5C%22items%5C%22%22;%20Total%20int%20%22json:%5C%22total_count%5C%22%22%20%7D" + "$ref": "#/definitions/devops.PipelineList" } } } @@ -3337,6 +2443,7 @@ "/kapis/devops.kubesphere.io/v1alpha2/webhook/github": { "post": { "consumes": [ + "application/x-www-form-urlencoded", "application/json" ], "produces": [ @@ -3354,45 +2461,6 @@ } } }, - "/kapis/iam.kubesphere.io/v1alpha2/authenticate": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "TokenReview attempts to authenticate a token to a known user. Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver.", - "operationId": "TokenReviewHandler", - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/iam.TokenReview" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/iam.TokenReview" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/iam.TokenReview" - } - } - } - } - }, "/kapis/iam.kubesphere.io/v1alpha2/clusterroles": { "get": { "consumes": [ @@ -3410,57 +2478,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.ClusterRoleList" + "$ref": "#/definitions/models.PageableResponse" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.ClusterRoleList" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/clusterroles/{clusterrole}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "List all policy rules of the specified cluster role.", - "operationId": "ListClusterRoleRules", - "parameters": [ - { - "type": "string", - "description": "cluster role name", - "name": "clusterrole", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } + "$ref": "#/definitions/models.PageableResponse" } } } @@ -3490,106 +2514,7 @@ ], "responses": { "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/devops/{devops}/roles/{role}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "List all policy rules of the specified role in the given devops project.", - "operationId": "ListDevopsRoleRules", - "parameters": [ - { - "type": "string", - "description": "devops project ID", - "name": "devops", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "devops role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/login": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "KubeSphere APIs support token-based authentication via the Authtoken request header. The POST Login API is used to retrieve the authentication token. After the authentication token is obtained, it must be inserted into the Authtoken header for all requests.", - "operationId": "Login", - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/iam.LoginRequest" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.Token" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.Token" - } + "description": "OK" } } } @@ -3620,115 +2545,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.RoleList" + "$ref": "#/definitions/models.PageableResponse" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.RoleList" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/namespaces/{namespace}/roles/{role}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "List all policy rules of the specified role in the given namespace.", - "operationId": "ListRoleRules", - "parameters": [ - { - "type": "string", - "description": "kubernetes namespace", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/namespaces/{namespace}/roles/{role}/users": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "Retrieve the users that are bound to the role in the specified namespace.", - "operationId": "ListRoleUsers", - "parameters": [ - { - "type": "string", - "description": "kubernetes namespace", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.NamespacedUser" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.NamespacedUser" - } + "$ref": "#/definitions/models.PageableResponse" } } } @@ -3758,158 +2581,7 @@ ], "responses": { "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.NamespacedUser" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.NamespacedUser" - } - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/rulesmapping/clusterroles": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "Get the mapping relationships between cluster roles and policy rules.", - "operationId": "ClusterRulesMapping", - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Rule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Rule" - } - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/rulesmapping/roles": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "Get the mapping relationships between namespaced roles and policy rules.", - "operationId": "RulesMapping", - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Rule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Rule" - } - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/users": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "List all users.", - "operationId": "ListUsers", - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "Create a user account.", - "operationId": "CreateUser", - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1alpha2.CreateUserRequest" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } + "description": "OK" } } } @@ -3923,9 +2595,9 @@ "application/json" ], "tags": [ - "Identity Management" + "Access Management" ], - "summary": "Describe the specified user.", + "summary": "Retrieve user details.", "operationId": "DescribeUser", "parameters": [ { @@ -3940,137 +2612,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/models.User" + "$ref": "#/definitions/v1alpha2.UserDetail" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/models.User" - } - } - } - }, - "put": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "Update information about the specified user.", - "operationId": "UpdateUser", - "parameters": [ - { - "type": "string", - "description": "username", - "name": "user", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1alpha2.UserUpdateRequest" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "Delete the specified user.", - "operationId": "DeleteUser", - "parameters": [ - { - "type": "string", - "description": "username", - "name": "user", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" + "$ref": "#/definitions/v1alpha2.UserDetail" } } } } }, - "/kapis/iam.kubesphere.io/v1alpha2/users/{user}/logs": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Identity Management" - ], - "summary": "Retrieve the \"login logs\" for the specified user.", - "operationId": "UserLoginLogs", - "parameters": [ - { - "type": "string", - "description": "username", - "name": "user", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.LoginLog" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.LoginLog" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/users/{user}/roles": { + "/kapis/iam.kubesphere.io/v1alpha2/users/{user}/clusterroles": { "get": { "consumes": [ "application/json" @@ -4081,8 +2635,8 @@ "tags": [ "Access Management" ], - "summary": "Retrieve all the roles that are assigned to the specified user.", - "operationId": "ListUserRoles", + "summary": "Retrieve user roles in clusters.", + "operationId": "ListRolesOfUser", "parameters": [ { "type": "string", @@ -4096,13 +2650,89 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/iam.RoleList" + "$ref": "#/definitions/v1alpha2.RoleList" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/iam.RoleList" + "$ref": "#/definitions/v1alpha2.RoleList" + } + } + } + } + }, + "/kapis/iam.kubesphere.io/v1alpha2/users/{user}/namespaceroles": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Access Management" + ], + "summary": "Retrieve user roles in namespaces.", + "operationId": "ListRolesOfUser", + "parameters": [ + { + "type": "string", + "description": "username", + "name": "user", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/v1alpha2.RoleList" + } + }, + "default": { + "description": "ok", + "schema": { + "$ref": "#/definitions/v1alpha2.RoleList" + } + } + } + } + }, + "/kapis/iam.kubesphere.io/v1alpha2/users/{user}/workspaceroles": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Access Management" + ], + "summary": "Retrieve user roles in workspaces.", + "operationId": "ListRolesOfUser", + "parameters": [ + { + "type": "string", + "description": "username", + "name": "user", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/v1alpha2.RoleList" + } + }, + "default": { + "description": "ok", + "schema": { + "$ref": "#/definitions/v1alpha2.RoleList" } } } @@ -4132,16 +2762,7 @@ ], "responses": { "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.UserList" - } + "description": "OK" } } }, @@ -4164,76 +2785,16 @@ "name": "workspace", "in": "path", "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1alpha2.InviteUserRequest" - } } ], "responses": { "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } + "description": "OK" } } } }, "/kapis/iam.kubesphere.io/v1alpha2/workspaces/{workspace}/members/{member}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "Describe the specified user in the given workspace.", - "operationId": "DescribeWorkspaceUser", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "username", - "name": "member", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DescribeWorkspaceUserResponse" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DescribeWorkspaceUserResponse" - } - } - } - }, "delete": { "consumes": [ "application/json" @@ -4302,112 +2863,7 @@ ], "responses": { "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.ClusterRoleList" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.ClusterRoleList" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/workspaces/{workspace}/roles/{role}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "Describe the workspace role.", - "operationId": "DescribeWorkspaceRole", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "workspace role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1.ClusterRole" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1.ClusterRole" - } - } - } - } - }, - "/kapis/iam.kubesphere.io/v1alpha2/workspaces/{workspace}/roles/{role}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Access Management" - ], - "summary": "List all policy rules of the specified workspace role.", - "operationId": "ListWorkspaceRoleRules", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "workspace role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SimpleRule" - } - } + "description": "OK" } } } @@ -4424,7 +2880,7 @@ "Log Query" ], "summary": "Query logs against the cluster.", - "operationId": "LoggingQueryCluster", + "operationId": "handleClusterQuery", "parameters": [ { "type": "string", @@ -4544,405 +3000,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" + "$ref": "#/definitions/v1alpha2.APIResponse" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/fluentbit/outputs": { - "get": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json", - "application/octet-stream" - ], - "tags": [ - "Fluent Bit Setting" - ], - "summary": "List all Fluent bit output plugins.", - "operationId": "LoggingQueryFluentbitOutputs", - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - } - } - }, - "post": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Fluent Bit Setting" - ], - "summary": "Add a new Fluent bit output plugin.", - "operationId": "LoggingInsertFluentbitOutput", - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/fluentbitclient.OutputPlugin" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/fluentbit/outputs/{output}": { - "put": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Fluent Bit Setting" - ], - "summary": "Update the specific Fluent bit output plugin.", - "operationId": "LoggingUpdateFluentbitOutput", - "parameters": [ - { - "type": "string", - "description": "ID of the output.", - "name": "output", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/fluentbitclient.OutputPlugin" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - } - } - }, - "delete": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Fluent Bit Setting" - ], - "summary": "Delete the specific Fluent bit output plugin.", - "operationId": "LoggingDeleteFluentbitOutput", - "parameters": [ - { - "type": "string", - "description": "ID of the output.", - "name": "output", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/log.FluentbitOutputsResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/namespaces/{namespace}": { - "get": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Log Query" - ], - "summary": "Query logs against the specific namespace.", - "operationId": "LoggingQueryNamespace", - "parameters": [ - { - "type": "string", - "description": "The name of the namespace.", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "query", - "description": "Query type. This can be one of three types: query (for querying logs), statistics (for retrieving statistical data), and histogram (for displaying log count by time interval). Defaults to query.", - "name": "operation", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of workloads. This field restricts the query to specified workloads. For example, the following filter matches the workload my-wl and demo-wl: `my-wl,demo-wl`", - "name": "workloads", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **workloads**, this field performs fuzzy matching on workloads. For example, the following value limits the query to workloads whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "workload_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of pods. This field restricts the query to specified pods. For example, the following filter matches the pod my-po and demo-po: `my-po,demo-po`", - "name": "pods", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **pods**, this field performs fuzzy matching on pods. For example, the following value limits the query to pods whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "pod_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of containers. This field restricts the query to specified containers. For example, the following filter matches the container my-cont and demo-cont: `my-cont,demo-cont`", - "name": "containers", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **containers**, this field performs fuzzy matching on containers. For example, the following value limits the query to containers whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "container_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. The query returns logs which contain at least one keyword. Case-insensitive matching. For example, if the field is set to `err,INFO`, the query returns any log containing err(ERR,Err,...) *OR* INFO(info,InFo,...).", - "name": "log_query", - "in": "query" - }, - { - "type": "string", - "default": "15m", - "description": "Time interval. It requires **operation** is set to histogram. The format is [0-9]+[smhdwMqy]. Defaults to 15m (i.e. 15 min).", - "name": "interval", - "in": "query" - }, - { - "type": "string", - "description": "Start time of query. Default to 0. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "End time of query. Default to now. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "end_time", - "in": "query" - }, - { - "type": "string", - "default": "desc", - "description": "Sort order. One of acs, desc. This field sorts logs by timestamp.", - "name": "sort", - "in": "query" - }, - { - "type": "integer", - "default": 0, - "description": "The offset from the result set. This field returns query results from the specified offset. It requires **operation** is set to query. Defaults to 0 (i.e. from the beginning of the result set).", - "name": "from", - "in": "query" - }, - { - "type": "integer", - "default": 10, - "description": "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/namespaces/{namespace}/pods/{pod}": { - "get": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Log Query" - ], - "summary": "Query logs against the specific pod.", - "operationId": "LoggingQueryPod", - "parameters": [ - { - "type": "string", - "description": "The name of the namespace.", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Pod name.", - "name": "pod", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "query", - "description": "Query type. This can be one of three types: query (for querying logs), statistics (for retrieving statistical data), and histogram (for displaying log count by time interval). Defaults to query.", - "name": "operation", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of containers. This field restricts the query to specified containers. For example, the following filter matches the container my-cont and demo-cont: `my-cont,demo-cont`", - "name": "containers", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **containers**, this field performs fuzzy matching on containers. For example, the following value limits the query to containers whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "container_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. The query returns logs which contain at least one keyword. Case-insensitive matching. For example, if the field is set to `err,INFO`, the query returns any log containing err(ERR,Err,...) *OR* INFO(info,InFo,...).", - "name": "log_query", - "in": "query" - }, - { - "type": "string", - "default": "15m", - "description": "Time interval. It requires **operation** is set to histogram. The format is [0-9]+[smhdwMqy]. Defaults to 15m (i.e. 15 min).", - "name": "interval", - "in": "query" - }, - { - "type": "string", - "description": "Start time of query. Default to 0. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "End time of query. Default to now. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "end_time", - "in": "query" - }, - { - "type": "string", - "default": "desc", - "description": "Sort order. One of acs, desc. This field sorts logs by timestamp.", - "name": "sort", - "in": "query" - }, - { - "type": "integer", - "default": 0, - "description": "The offset from the result set. This field returns query results from the specified offset. It requires **operation** is set to query. Defaults to 0 (i.e. from the beginning of the result set).", - "name": "from", - "in": "query" - }, - { - "type": "integer", - "default": 10, - "description": "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" + "$ref": "#/definitions/v1alpha2.APIResponse" } } } @@ -4955,13 +3019,14 @@ "application/xml" ], "produces": [ - "application/json" + "application/json", + "text/plain" ], "tags": [ "Log Query" ], "summary": "Query logs against the specific container.", - "operationId": "LoggingQueryContainer", + "operationId": "handleContainerQuery", "parameters": [ { "type": "string", @@ -5042,277 +3107,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" + "$ref": "#/definitions/v1alpha2.APIResponse" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/namespaces/{namespace}/workloads/{workload}": { - "get": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Log Query" - ], - "summary": "Query logs against the specific workload.", - "operationId": "LoggingQueryWorkload", - "parameters": [ - { - "type": "string", - "description": "The name of the namespace.", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "The name of the workload.", - "name": "workload", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "query", - "description": "Query type. This can be one of three types: query (for querying logs), statistics (for retrieving statistical data), and histogram (for displaying log count by time interval). Defaults to query.", - "name": "operation", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of pods. This field restricts the query to specified pods. For example, the following filter matches the pod my-po and demo-po: `my-po,demo-po`", - "name": "pods", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **pods**, this field performs fuzzy matching on pods. For example, the following value limits the query to pods whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "pod_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of containers. This field restricts the query to specified containers. For example, the following filter matches the container my-cont and demo-cont: `my-cont,demo-cont`", - "name": "containers", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **containers**, this field performs fuzzy matching on containers. For example, the following value limits the query to containers whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "container_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. The query returns logs which contain at least one keyword. Case-insensitive matching. For example, if the field is set to `err,INFO`, the query returns any log containing err(ERR,Err,...) *OR* INFO(info,InFo,...).", - "name": "log_query", - "in": "query" - }, - { - "type": "string", - "default": "15m", - "description": "Time interval. It requires **operation** is set to histogram. The format is [0-9]+[smhdwMqy]. Defaults to 15m (i.e. 15 min).", - "name": "interval", - "in": "query" - }, - { - "type": "string", - "description": "Start time of query. Default to 0. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "End time of query. Default to now. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "end_time", - "in": "query" - }, - { - "type": "string", - "default": "desc", - "description": "Sort order. One of acs, desc. This field sorts logs by timestamp.", - "name": "sort", - "in": "query" - }, - { - "type": "integer", - "default": 0, - "description": "The offset from the result set. This field returns query results from the specified offset. It requires **operation** is set to query. Defaults to 0 (i.e. from the beginning of the result set).", - "name": "from", - "in": "query" - }, - { - "type": "integer", - "default": 10, - "description": "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - } - } - } - }, - "/kapis/logging.kubesphere.io/v1alpha2/workspaces/{workspace}": { - "get": { - "consumes": [ - "application/json", - "application/xml" - ], - "produces": [ - "application/json", - "application/octet-stream" - ], - "tags": [ - "Log Query" - ], - "summary": "Query logs against the specific workspace.", - "operationId": "LoggingQueryWorkspace", - "parameters": [ - { - "type": "string", - "description": "The name of the workspace.", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "query", - "description": "Query type. This can be one of three types: query (for querying logs), statistics (for retrieving statistical data), and histogram (for displaying log count by time interval). Defaults to query.", - "name": "operation", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of namespaces. This field restricts the query to specified namespaces. For example, the following filter matches the namespace my-ns and demo-ns: `my-ns,demo-ns`", - "name": "namespaces", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **namespaces**, this field performs fuzzy matching on namespaces. For example, the following value limits the query to namespaces whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "namespace_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of workloads. This field restricts the query to specified workloads. For example, the following filter matches the workload my-wl and demo-wl: `my-wl,demo-wl`", - "name": "workloads", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **workloads**, this field performs fuzzy matching on workloads. For example, the following value limits the query to workloads whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "workload_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of pods. This field restricts the query to specified pods. For example, the following filter matches the pod my-po and demo-po: `my-po,demo-po`", - "name": "pods", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **pods**, this field performs fuzzy matching on pods. For example, the following value limits the query to pods whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "pod_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of containers. This field restricts the query to specified containers. For example, the following filter matches the container my-cont and demo-cont: `my-cont,demo-cont`", - "name": "containers", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **containers**, this field performs fuzzy matching on containers. For example, the following value limits the query to containers whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "container_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. The query returns logs which contain at least one keyword. Case-insensitive matching. For example, if the field is set to `err,INFO`, the query returns any log containing err(ERR,Err,...) *OR* INFO(info,InFo,...).", - "name": "log_query", - "in": "query" - }, - { - "type": "string", - "default": "15m", - "description": "Time interval. It requires **operation** is set to histogram. The format is [0-9]+[smhdwMqy]. Defaults to 15m (i.e. 15 min).", - "name": "interval", - "in": "query" - }, - { - "type": "string", - "description": "Start time of query. Default to 0. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "End time of query. Default to now. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "end_time", - "in": "query" - }, - { - "type": "string", - "default": "desc", - "description": "Sort order. One of acs, desc. This field sorts logs by timestamp.", - "name": "sort", - "in": "query" - }, - { - "type": "integer", - "default": 0, - "description": "The offset from the result set. This field returns query results from the specified offset. It requires **operation** is set to query. Defaults to 0 (i.e. from the beginning of the result set).", - "name": "from", - "in": "query" - }, - { - "type": "integer", - "default": 10, - "description": "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.QueryResult" + "$ref": "#/definitions/v1alpha2.APIResponse" } } } @@ -5330,7 +3131,7 @@ "Cluster Metrics" ], "summary": "Get cluster-level metric data.", - "operationId": "MonitorCluster", + "operationId": "handleClusterMetricsQuery", "parameters": [ { "type": "string", @@ -5362,25 +3163,19 @@ "description": "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.", "name": "time", "in": "query" - }, - { - "type": "string", - "description": "Additional operations. Currently available types is statistics. It retrieves the total number of workspaces, devops projects, namespaces, accounts in the cluster at the moment.", - "name": "type", - "in": "query" } ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5389,8 +3184,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/components/{component}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5399,7 +3193,7 @@ "Component Metrics" ], "summary": "Get component-level metric data of the specific system component.", - "operationId": "MonitorComponent", + "operationId": "handleComponentMetricsQuery", "parameters": [ { "type": "string", @@ -5444,13 +3238,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5459,8 +3253,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5469,7 +3262,7 @@ "Namespace Metrics" ], "summary": "Get namespace-level metric data of all namespaces.", - "operationId": "MonitorNamespace", + "operationId": "handleNamespaceMetricsQuery", "parameters": [ { "type": "string", @@ -5539,13 +3332,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5554,8 +3347,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5564,7 +3356,7 @@ "Namespace Metrics" ], "summary": "Get namespace-level metric data of the specific namespace.", - "operationId": "MonitorNamespace", + "operationId": "handleNamespaceMetricsQuery", "parameters": [ { "type": "string", @@ -5609,13 +3401,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5624,8 +3416,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/persistentvolumeclaims": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5634,7 +3425,7 @@ "PVC Metrics" ], "summary": "Get PVC-level metric data of the specific namespace's PVCs.", - "operationId": "MonitorPVC", + "operationId": "handlePVCMetricsQuery", "parameters": [ { "type": "string", @@ -5711,13 +3502,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5726,8 +3517,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/persistentvolumeclaims/{pvc}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5736,7 +3526,7 @@ "PVC Metrics" ], "summary": "Get PVC-level metric data of a specific PVC. Navigate to the PVC by the PVC's namespace.", - "operationId": "MonitorPVC", + "operationId": "handlePVCMetricsQuery", "parameters": [ { "type": "string", @@ -5788,13 +3578,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5803,8 +3593,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/pods": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5813,7 +3602,7 @@ "Pod Metrics" ], "summary": "Get pod-level metric data of the specific namespace's pods.", - "operationId": "MonitorPod", + "operationId": "handlePodMetricsQuery", "parameters": [ { "type": "string", @@ -5890,13 +3679,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5905,8 +3694,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/pods/{pod}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5915,7 +3703,7 @@ "Pod Metrics" ], "summary": "Get pod-level metric data of a specific pod. Navigate to the pod by the pod's namespace.", - "operationId": "MonitorPod", + "operationId": "handlePodMetricsQuery", "parameters": [ { "type": "string", @@ -5967,13 +3755,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -5982,8 +3770,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/pods/{pod}/containers": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -5992,7 +3779,7 @@ "Container Metrics" ], "summary": "Get container-level metric data of a specific pod's containers. Navigate to the pod by the pod's namespace.", - "operationId": "MonitorContainer", + "operationId": "handleContainerMetricsQuery", "parameters": [ { "type": "string", @@ -6076,13 +3863,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6091,8 +3878,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/pods/{pod}/containers/{container}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6101,7 +3887,7 @@ "Container Metrics" ], "summary": "Get container-level metric data of a specific container. Navigate to the container by the pod name and the namespace.", - "operationId": "MonitorContainer", + "operationId": "handleContainerMetricsQuery", "parameters": [ { "type": "string", @@ -6160,13 +3946,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6175,8 +3961,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/workloads": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6185,7 +3970,7 @@ "Workload Metrics" ], "summary": "Get workload-level metric data of a specific namespace's workloads.", - "operationId": "MonitorWorkload", + "operationId": "handleWorkloadMetricsQuery", "parameters": [ { "type": "string", @@ -6262,13 +4047,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6277,8 +4062,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/workloads/{kind}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6287,7 +4071,7 @@ "Workload Metrics" ], "summary": "Get workload-level metric data of all workloads which belongs to a specific kind.", - "operationId": "MonitorWorkload", + "operationId": "handleWorkloadMetricsQuery", "parameters": [ { "type": "string", @@ -6371,13 +4155,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6386,8 +4170,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/namespaces/{namespace}/workloads/{kind}/{workload}/pods": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6396,7 +4179,7 @@ "Pod Metrics" ], "summary": "Get pod-level metric data of a specific workload's pods. Navigate to the workload by the namespace.", - "operationId": "MonitorPod", + "operationId": "handlePodMetricsQuery", "parameters": [ { "type": "string", @@ -6487,13 +4270,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6502,8 +4285,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/nodes": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6512,7 +4294,7 @@ "Node Metrics" ], "summary": "Get node-level metric data of all nodes.", - "operationId": "MonitorNode", + "operationId": "handleNodeMetricsQuery", "parameters": [ { "type": "string", @@ -6582,13 +4364,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6597,8 +4379,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/nodes/{node}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6607,7 +4388,7 @@ "Node Metrics" ], "summary": "Get node-level metric data of the specific node.", - "operationId": "MonitorNode", + "operationId": "handleNodeMetricsQuery", "parameters": [ { "type": "string", @@ -6652,13 +4433,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6667,8 +4448,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/nodes/{node}/pods": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6677,7 +4457,7 @@ "Pod Metrics" ], "summary": "Get pod-level metric data of all pods on a specific node.", - "operationId": "MonitorPod", + "operationId": "handlePodMetricsQuery", "parameters": [ { "type": "string", @@ -6754,13 +4534,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6769,8 +4549,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/nodes/{node}/pods/{pod}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6779,7 +4558,7 @@ "Pod Metrics" ], "summary": "Get pod-level metric data of a specific pod. Navigate to the pod by the node where it is scheduled.", - "operationId": "MonitorPod", + "operationId": "handlePodMetricsQuery", "parameters": [ { "type": "string", @@ -6831,13 +4610,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6846,8 +4625,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/storageclasses/{storageclass}/persistentvolumeclaims": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6856,7 +4634,7 @@ "PVC Metrics" ], "summary": "Get PVC-level metric data of the specific storageclass's PVCs.", - "operationId": "MonitorPVC", + "operationId": "handlePVCMetricsQuery", "parameters": [ { "type": "string", @@ -6933,13 +4711,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -6948,8 +4726,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/workspaces": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -6958,7 +4735,7 @@ "Workspace Metrics" ], "summary": "Get workspace-level metric data of all workspaces.", - "operationId": "MonitorWorkspace", + "operationId": "handleWorkspaceMetricsQuery", "parameters": [ { "type": "string", @@ -7028,13 +4805,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -7043,8 +4820,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/workspaces/{workspace}": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -7053,7 +4829,7 @@ "Workspace Metrics" ], "summary": "Get workspace-level metric data of a specific workspace.", - "operationId": "MonitorWorkspace", + "operationId": "handleWorkspaceMetricsQuery", "parameters": [ { "type": "string", @@ -7092,25 +4868,19 @@ "description": "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.", "name": "time", "in": "query" - }, - { - "type": "string", - "description": "Additional operations. Currently available types is statistics. It retrieves the total number of namespaces, devops projects, members and roles in this workspace at the moment.", - "name": "type", - "in": "query" } ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -7119,8 +4889,7 @@ "/kapis/monitoring.kubesphere.io/v1alpha2/workspaces/{workspace}/namespaces": { "get": { "consumes": [ - "application/json", - "application/xml" + "application/json" ], "produces": [ "application/json" @@ -7129,7 +4898,7 @@ "Namespace Metrics" ], "summary": "Get namespace-level metric data of a specific workspace.", - "operationId": "MonitorNamespace", + "operationId": "handleNamespaceMetricsQuery", "parameters": [ { "type": "string", @@ -7206,13 +4975,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/metrics.Response" + "$ref": "#/definitions/monitoring.Metrics" } } } @@ -8828,7 +6597,7 @@ "application/json" ], "summary": "Rerun job whether the job is complete or not", - "operationId": "RerunJob", + "operationId": "handleJobReRun", "deprecated": true, "parameters": [ { @@ -8850,41 +6619,12 @@ "description": "action must be \"rerun\"", "name": "action", "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - } - } - } - }, - "/kapis/operations.kubesphere.io/v1alpha2/nodes/{node}/drainage": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "summary": "remove a node from service, safely evict all of your pods from a node and you can power down the node. More info: https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/", - "operationId": "DrainNode", - "deprecated": true, - "parameters": [ { "type": "string", - "description": "node name", - "name": "node", - "in": "path", + "description": "version of job, rerun when the version matches", + "name": "resourceVersion", + "in": "query", "required": true } ], @@ -8916,18 +6656,18 @@ "Cluster Resources" ], "summary": "get abnormal workloads' count of whole cluster", - "operationId": "GetClusterAbnormalWorkloads", + "operationId": "handleGetNamespacedAbnormalWorkloads", "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/status.WorkLoadStatus" + "$ref": "#/definitions/api.Workloads" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/status.WorkLoadStatus" + "$ref": "#/definitions/api.Workloads" } } } @@ -8945,18 +6685,18 @@ "Component Status" ], "summary": "Get the health status of system components.", - "operationId": "GetSystemHealthStatus", + "operationId": "handleGetSystemHealthStatus", "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/models.HealthStatus" + "$ref": "#/definitions/v1alpha2.HealthStatus" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/models.HealthStatus" + "$ref": "#/definitions/v1alpha2.HealthStatus" } } } @@ -8974,14 +6714,14 @@ "Component Status" ], "summary": "List the system components.", - "operationId": "GetComponents", + "operationId": "handleGetComponents", "responses": { "200": { "description": "ok", "schema": { "type": "array", "items": { - "$ref": "#/definitions/models.ComponentStatus" + "$ref": "#/definitions/v1alpha2.ComponentStatus" } } }, @@ -8990,7 +6730,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/models.ComponentStatus" + "$ref": "#/definitions/v1alpha2.ComponentStatus" } } } @@ -9009,7 +6749,7 @@ "Component Status" ], "summary": "Describe the specified system component.", - "operationId": "GetComponentStatus", + "operationId": "handleGetComponentStatus", "parameters": [ { "type": "string", @@ -9023,13 +6763,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ComponentStatus" + "$ref": "#/definitions/v1alpha2.ComponentStatus" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ComponentStatus" + "$ref": "#/definitions/v1alpha2.ComponentStatus" } } } @@ -9047,7 +6787,7 @@ "Verification" ], "summary": "Verify if the kubernetes secret has read access to the git repository", - "operationId": "GitReadVerify", + "operationId": "handleVerifyGitCredential", "parameters": [ { "name": "body", @@ -9086,7 +6826,7 @@ "Namespace Resources" ], "summary": "get abnormal workloads' count of specified namespace", - "operationId": "GetNamespacedAbnormalWorkloads", + "operationId": "handleGetNamespacedAbnormalWorkloads", "parameters": [ { "type": "string", @@ -9100,13 +6840,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/status.WorkLoadStatus" + "$ref": "#/definitions/api.Workloads" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/status.WorkLoadStatus" + "$ref": "#/definitions/api.Workloads" } } } @@ -9124,7 +6864,7 @@ "Namespace Resources" ], "summary": "Get the specified daemonset revision", - "operationId": "GetDaemonSetRevision", + "operationId": "handleGetDaemonSetRevision", "parameters": [ { "type": "string", @@ -9176,7 +6916,7 @@ "Namespace Resources" ], "summary": "Get the specified deployment revision", - "operationId": "GetDeployRevision", + "operationId": "handleGetDeploymentRevision", "parameters": [ { "type": "string", @@ -9216,57 +6956,6 @@ } } }, - "/kapis/resources.kubesphere.io/v1alpha2/namespaces/{namespace}/jobs/{job}": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Namespace Resources" - ], - "summary": "Rerun job whether the job is complete or not", - "operationId": "RerunJob", - "parameters": [ - { - "type": "string", - "description": "job name", - "name": "job", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of the namespace where the job runs in", - "name": "namespace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "action must be \"rerun\"", - "name": "action", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - } - } - } - }, "/kapis/resources.kubesphere.io/v1alpha2/namespaces/{namespace}/quotas": { "get": { "consumes": [ @@ -9279,7 +6968,7 @@ "Namespace Resources" ], "summary": "get specified namespace's resource quota and usage", - "operationId": "GetNamespaceQuotas", + "operationId": "handleGetNamespaceQuotas", "parameters": [ { "type": "string", @@ -9293,13 +6982,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ResourceQuota" + "$ref": "#/definitions/api.ResourceQuota" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ResourceQuota" + "$ref": "#/definitions/api.ResourceQuota" } } } @@ -9317,7 +7006,7 @@ "Namespace Resources" ], "summary": "List router of a specified project", - "operationId": "GetRouter", + "operationId": "handleGetRouter", "parameters": [ { "type": "string", @@ -9353,7 +7042,7 @@ "Namespace Resources" ], "summary": "Update a router for a specified project", - "operationId": "UpdateRouter", + "operationId": "handleUpdateRouter", "parameters": [ { "type": "string", @@ -9389,7 +7078,7 @@ "Namespace Resources" ], "summary": "Create a router for a specified project", - "operationId": "CreateRouter", + "operationId": "handleCreateRouter", "parameters": [ { "type": "string", @@ -9425,7 +7114,7 @@ "Namespace Resources" ], "summary": "List router of a specified project", - "operationId": "DeleteRouter", + "operationId": "handleDeleteRouter", "parameters": [ { "type": "string", @@ -9463,7 +7152,7 @@ "Namespace Resources" ], "summary": "Get the specified statefulset revision", - "operationId": "GetStatefulSetRevision", + "operationId": "handleGetStatefulSetRevision", "parameters": [ { "type": "string", @@ -9515,7 +7204,8 @@ "Namespace Resources" ], "summary": "Namespace level resource query", - "operationId": "ListNamespacedResources", + "operationId": "handleListNamespaceResources", + "deprecated": true, "parameters": [ { "type": "string", @@ -9575,44 +7265,6 @@ } } }, - "/kapis/resources.kubesphere.io/v1alpha2/nodes/{node}/drainage": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Cluster Resources" - ], - "summary": "remove a node from service, safely evict all of your pods from a node and you can power down the node. More info: https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/", - "operationId": "DrainNode", - "parameters": [ - { - "type": "string", - "description": "node name", - "name": "node", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - } - } - } - }, "/kapis/resources.kubesphere.io/v1alpha2/quotas": { "get": { "consumes": [ @@ -9625,18 +7277,18 @@ "Cluster Resources" ], "summary": "get whole cluster's resource usage", - "operationId": "GetClusterQuotas", + "operationId": "handleGetClusterQuotas", "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ResourceQuota" + "$ref": "#/definitions/api.ResourceQuota" } }, "default": { "description": "ok", "schema": { - "$ref": "#/definitions/models.ResourceQuota" + "$ref": "#/definitions/api.ResourceQuota" } } } @@ -9654,7 +7306,7 @@ "Docker Registry" ], "summary": "Retrieve the blob from the registry identified", - "operationId": "RegistryImageBlob", + "operationId": "handleGetRegistryEntry", "parameters": [ { "type": "string", @@ -9707,14 +7359,14 @@ "Verification" ], "summary": "verify if a user has access to the docker registry", - "operationId": "RegistryVerify", + "operationId": "handleVerifyRegistryCredential", "parameters": [ { "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/registries.AuthInfo" + "$ref": "#/definitions/api.RegistryCredential" } } ], @@ -9734,35 +7386,6 @@ } } }, - "/kapis/resources.kubesphere.io/v1alpha2/routers": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Cluster Resources" - ], - "summary": "List all routers of all projects", - "operationId": "GetAllRouters", - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1.ServiceList" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1.ServiceList" - } - } - } - } - }, "/kapis/resources.kubesphere.io/v1alpha2/users/{user}/kubeconfig": { "get": { "consumes": [ @@ -9814,7 +7437,7 @@ "User Resources" ], "summary": "get user's kubectl pod", - "operationId": "GetKubectl", + "operationId": "GetKubectlPod", "parameters": [ { "type": "string", @@ -9851,8 +7474,9 @@ "tags": [ "Cluster Resources" ], - "summary": "Cluster level resource query", - "operationId": "ListResources", + "summary": "Cluster level resources", + "operationId": "handleListNamespaceResources", + "deprecated": true, "parameters": [ { "type": "string", @@ -9905,6 +7529,257 @@ } } }, + "/kapis/resources.kubesphere.io/v1alpha3/componenthealth": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Component Status" + ], + "summary": "Get the health status of system components.", + "operationId": "handleGetSystemHealthStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha2.HealthStatus" + } + }, + "default": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha2.HealthStatus" + } + } + } + } + }, + "/kapis/resources.kubesphere.io/v1alpha3/components": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Component Status" + ], + "summary": "List the system components.", + "operationId": "handleGetComponents", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha2.ComponentStatus" + } + } + }, + "default": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha2.ComponentStatus" + } + } + } + } + } + }, + "/kapis/resources.kubesphere.io/v1alpha3/components/{component}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Component Status" + ], + "summary": "Describe the specified system component.", + "operationId": "handleGetComponentStatus", + "parameters": [ + { + "type": "string", + "description": "component name", + "name": "component", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha2.ComponentStatus" + } + }, + "default": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1alpha2.ComponentStatus" + } + } + } + } + }, + "/kapis/resources.kubesphere.io/v1alpha3/namespaces/{namespace}/{resources}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Namespaced Resource" + ], + "summary": "Namespace level resource query", + "operationId": "handleListResources", + "parameters": [ + { + "type": "string", + "description": "the name of the project", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "namespace level resource type, e.g. pods,jobs,configmaps,services.", + "name": "resources", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name used to do filtering", + "name": "name", + "in": "query" + }, + { + "type": "string", + "format": "page=%d", + "default": "page=1", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "ascending=false", + "description": "sort parameters, e.g. reverse=true", + "name": "ascending", + "in": "query" + }, + { + "type": "string", + "description": "sort parameters, e.g. orderBy=createTime", + "name": "sortBy", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ListResult" + } + }, + "default": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ListResult" + } + } + } + } + }, + "/kapis/resources.kubesphere.io/v1alpha3/{resources}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Namespaced Resource" + ], + "summary": "Cluster level resources", + "operationId": "handleListResources", + "parameters": [ + { + "type": "string", + "description": "cluster level resource type, e.g. pods,jobs,configmaps,services.", + "name": "resources", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name used to do filtering", + "name": "name", + "in": "query" + }, + { + "type": "string", + "format": "page=%d", + "default": "page=1", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "string", + "description": "limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "ascending=false", + "description": "sort parameters, e.g. reverse=true", + "name": "ascending", + "in": "query" + }, + { + "type": "string", + "description": "sort parameters, e.g. orderBy=createTime", + "name": "sortBy", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ListResult" + } + }, + "default": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.ListResult" + } + } + } + } + }, "/kapis/servicemesh.kubesphere.io/v1alpha2/namespaces/graph": { "get": { "consumes": [ @@ -9917,7 +7792,7 @@ "ServiceMesh" ], "summary": "Get graph from all namespaces", - "operationId": "GetNamespacesGraph", + "operationId": "getNamespacesGraph", "parameters": [ { "type": "string", @@ -9994,7 +7869,7 @@ "ServiceMesh" ], "summary": "Get app health", - "operationId": "GetAppHealth", + "operationId": "getAppHealth", "parameters": [ { "type": "string", @@ -10053,7 +7928,7 @@ "ServiceMesh" ], "summary": "Get app metrics from a specific namespace", - "operationId": "GetAppMetrics", + "operationId": "getAppMetrics", "parameters": [ { "type": "string", @@ -10167,7 +8042,7 @@ "ServiceMesh" ], "summary": "Get service graph for a specific namespace", - "operationId": "GetNamespaceGraph", + "operationId": "getNamespaceGraph", "parameters": [ { "type": "string", @@ -10251,7 +8126,7 @@ "ServiceMesh" ], "summary": "Get app/service/workload health of a namespace", - "operationId": "GetNamespaceHealth", + "operationId": "getNamespaceHealth", "parameters": [ { "type": "string", @@ -10323,7 +8198,7 @@ "ServiceMesh" ], "summary": "Get metrics from a specific namespace", - "operationId": "GetNamespaceMetrics", + "operationId": "getNamespaceMetrics", "parameters": [ { "type": "string", @@ -10437,7 +8312,7 @@ "ServiceMesh" ], "summary": "Get service health", - "operationId": "GetServiceHealth", + "operationId": "getServiceHealth", "parameters": [ { "type": "string", @@ -10496,7 +8371,7 @@ "ServiceMesh" ], "summary": "Get service metrics from a specific namespace", - "operationId": "GetServiceMetrics", + "operationId": "getServiceMetrics", "parameters": [ { "type": "string", @@ -10610,7 +8485,7 @@ "ServiceMesh" ], "summary": "Get tracing of a service, should have servicemesh enabled first", - "operationId": "GetServiceTracing", + "operationId": "getServiceTracing", "parameters": [ { "type": "string", @@ -10683,7 +8558,7 @@ "ServiceMesh" ], "summary": "Get workload health", - "operationId": "GetWorkloadHealth", + "operationId": "getWorkloadHealth", "parameters": [ { "type": "string", @@ -10742,7 +8617,7 @@ "ServiceMesh" ], "summary": "Get workload metrics from a specific namespace", - "operationId": "GetWorkloadMetrics", + "operationId": "getWorkloadMetrics", "parameters": [ { "type": "string", @@ -10851,255 +8726,6 @@ } } }, - "/kapis/tenant.kubesphere.io/v1alpha2/devops/{devops}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List the rules of the specified DevOps project for the current user", - "operationId": "ListDevopsRules", - "parameters": [ - { - "type": "string", - "description": "devops project ID", - "name": "devops", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/devopscount": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Get the devops projects count for the member", - "operationId": "GetDevOpsProjectsCount", - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/struct%20%7B%20Count%20uint32%20%22json:%5C%22count%5C%22%22%20%7D" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/struct%20%7B%20Count%20uint32%20%22json:%5C%22count%5C%22%22%20%7D" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/logs": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Query cluster-level logs in a multi-tenants environment", - "operationId": "LogQuery", - "parameters": [ - { - "type": "string", - "default": "query", - "description": "Operation type. This can be one of four types: query (for querying logs), statistics (for retrieving statistical data), histogram (for displaying log count by time interval) and export (for exporting logs). Defaults to query.", - "name": "operation", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of workspaces. This field restricts the query to specified workspaces. For example, the following filter matches the workspace my-ws and demo-ws: `my-ws,demo-ws`", - "name": "workspaces", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **workspaces**, this field performs fuzzy matching on workspaces. For example, the following value limits the query to workspaces whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "workspace_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of namespaces. This field restricts the query to specified namespaces. For example, the following filter matches the namespace my-ns and demo-ns: `my-ns,demo-ns`", - "name": "namespaces", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **namespaces**, this field performs fuzzy matching on namespaces. For example, the following value limits the query to namespaces whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "namespace_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of workloads. This field restricts the query to specified workloads. For example, the following filter matches the workload my-wl and demo-wl: `my-wl,demo-wl`", - "name": "workloads", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **workloads**, this field performs fuzzy matching on workloads. For example, the following value limits the query to workloads whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "workload_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of pods. This field restricts the query to specified pods. For example, the following filter matches the pod my-po and demo-po: `my-po,demo-po`", - "name": "pods", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **pods**, this field performs fuzzy matching on pods. For example, the following value limits the query to pods whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "pod_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of containers. This field restricts the query to specified containers. For example, the following filter matches the container my-cont and demo-cont: `my-cont,demo-cont`", - "name": "containers", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. Differing from **containers**, this field performs fuzzy matching on containers. For example, the following value limits the query to containers whose name contains the word my(My,MY,...) *OR* demo(Demo,DemO,...): `my,demo`.", - "name": "container_query", - "in": "query" - }, - { - "type": "string", - "description": "A comma-separated list of keywords. The query returns logs which contain at least one keyword. Case-insensitive matching. For example, if the field is set to `err,INFO`, the query returns any log containing err(ERR,Err,...) *OR* INFO(info,InFo,...).", - "name": "log_query", - "in": "query" - }, - { - "type": "string", - "default": "15m", - "description": "Time interval. It requires **operation** is set to histogram. The format is [0-9]+[smhdwMqy]. Defaults to 15m (i.e. 15 min).", - "name": "interval", - "in": "query" - }, - { - "type": "string", - "description": "Start time of query. Default to 0. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "End time of query. Default to now. The format is a string representing milliseconds since the epoch, eg. 1559664000000.", - "name": "end_time", - "in": "query" - }, - { - "type": "string", - "default": "desc", - "description": "Sort order. One of acs, desc. This field sorts logs by timestamp.", - "name": "sort", - "in": "query" - }, - { - "type": "integer", - "default": 0, - "description": "The offset from the result set. This field returns query results from the specified offset. It requires **operation** is set to query. Defaults to 0 (i.e. from the beginning of the result set).", - "name": "from", - "in": "query" - }, - { - "type": "integer", - "default": 10, - "description": "Size of result to return. It requires **operation** is set to query. Defaults to 10 (i.e. 10 log records).", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.Response" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.Response" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/namespaces/{namespace}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List the rules of the specified namespace for the current user", - "operationId": "ListNamespaceRules", - "parameters": [ - { - "type": "string", - "description": "the name of the namespace", - "name": "namespace", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - } - } - } - }, "/kapis/tenant.kubesphere.io/v1alpha2/workspaces": { "get": { "consumes": [ @@ -11129,288 +8755,6 @@ } } }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Describe the specified workspace", - "operationId": "DescribeWorkspace", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha1.Workspace" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha1.Workspace" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/devops": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List devops projects for the current user", - "operationId": "ListDevopsProjects", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "format": "limit=%d,page=%d", - "default": "limit=10,page=1", - "description": "page", - "name": "paging", - "in": "query" - }, - { - "type": "string", - "format": "key=%s,key~%s", - "description": "query conditions", - "name": "conditions", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Create a devops project in the specified workspace", - "operationId": "CreateDevopsProject", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/devops/{devops}": { - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Delete the specified devops project from the workspace", - "operationId": "DeleteDevopsProject", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "devops project ID", - "name": "devops", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/v1alpha2.DevOpsProject" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/members/{member}/devops": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List the devops projects for the workspace member", - "operationId": "ListDevopsProjectsByUsername", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "workspace member's username", - "name": "member", - "in": "path", - "required": true - }, - { - "type": "string", - "format": "limit=%d,page=%d", - "default": "limit=10,page=1", - "description": "page", - "name": "paging", - "in": "query" - }, - { - "type": "string", - "format": "key=%s,key~%s", - "description": "query conditions", - "name": "conditions", - "in": "query" - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.PageableResponse" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.PageableResponse" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/members/{member}/namespaces": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List the namespaces for the workspace member", - "operationId": "ListNamespacesByUsername", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "workspace member's username", - "name": "member", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.Namespace" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.Namespace" - } - } - } - } - } - }, "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/namespaces": { "get": { "consumes": [ @@ -11453,131 +8797,6 @@ } } } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Create a namespace in the specified workspace", - "operationId": "CreateNamespace", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.Namespace" - } - } - }, - "default": { - "description": "ok", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.Namespace" - } - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/namespaces/{namespace}": { - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "Delete the specified namespace from the workspace", - "operationId": "DeleteNamespace", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "the name of the namespace", - "name": "namespace", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/errors.Error" - } - } - } - } - }, - "/kapis/tenant.kubesphere.io/v1alpha2/workspaces/{workspace}/rules": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Tenant Resources" - ], - "summary": "List the rules of the specified workspace for the current user", - "operationId": "ListWorkspaceRules", - "parameters": [ - { - "type": "string", - "description": "workspace name", - "name": "workspace", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - }, - "default": { - "description": "ok", - "schema": { - "$ref": "#/definitions/models.SimpleRule" - } - } - } } }, "/kapis/terminal.kubesphere.io/v1alpha2/namespaces/{namespace}/pods/{pod}": { @@ -11592,7 +8811,7 @@ "Terminal" ], "summary": "create terminal session", - "operationId": "CreateTerminalSession", + "operationId": "handleTerminalSession", "responses": { "200": { "description": "OK" @@ -11793,7 +9012,7 @@ "type": "string" }, "replayable": { - "description": "replayable or not", + "description": "Replayable or not", "type": "boolean" }, "result": { @@ -11805,7 +9024,7 @@ "type": "string" }, "startTime": { - "description": "start run", + "description": "the time of start", "type": "string" }, "state": { @@ -11829,6 +9048,14 @@ "shortDescription": { "description": "short description", "type": "string" + }, + "userId": { + "description": "user id", + "type": "string" + }, + "userName": { + "description": "user name", + "type": "string" } } }, @@ -12018,6 +9245,85 @@ } } }, + "api.ListResult": { + "required": [ + "items", + "totalItems" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/api.ListResult.items" + } + }, + "totalItems": { + "type": "integer", + "format": "int32" + } + } + }, + "api.ListResult.items": {}, + "api.RegistryCredential": { + "required": [ + "username", + "password", + "serverhost" + ], + "properties": { + "password": { + "description": "password", + "type": "string" + }, + "serverhost": { + "description": "registry server host", + "type": "string" + }, + "username": { + "description": "username", + "type": "string" + } + } + }, + "api.ResourceQuota": { + "required": [ + "namespace", + "data" + ], + "properties": { + "data": { + "description": "resource quota status", + "$ref": "#/definitions/v1.ResourceQuotaStatus" + }, + "namespace": { + "description": "namespace", + "type": "string" + } + } + }, + "api.Workloads": { + "required": [ + "namespace", + "data" + ], + "properties": { + "data": { + "description": "the number of unhealthy workloads", + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "items": { + "description": "unhealthy workloads", + "type": "object" + }, + "namespace": { + "description": "the name of the namespace", + "type": "string" + } + } + }, "big.Int": { "required": [ "neg", @@ -12238,52 +9544,6 @@ } } }, - "devops.BitbucketServerSource": { - "properties": { - "api_uri": { - "description": "The api url can specify the location of the github apiserver.For private cloud configuration", - "type": "string" - }, - "credential_id": { - "description": "credential id to access github source", - "type": "string" - }, - "discover_branches": { - "description": "Discover branch configuration", - "type": "integer", - "format": "int32" - }, - "discover_pr_from_forks": { - "description": "Discover fork PR configuration", - "$ref": "#/definitions/devops.DiscoverPRFromForks" - }, - "discover_pr_from_origin": { - "description": "Discover origin PR configuration", - "type": "integer", - "format": "int32" - }, - "git_clone_option": { - "description": "advavced git clone options", - "$ref": "#/definitions/devops.GitCloneOption" - }, - "owner": { - "description": "owner of github repo", - "type": "string" - }, - "regex_filter": { - "description": "Regex used to match the name of the branch that needs to be run", - "type": "string" - }, - "repo": { - "description": "repo name of github repo", - "type": "string" - }, - "scm_id": { - "description": "uid of scm", - "type": "string" - } - } - }, "devops.BranchPipeline": { "properties": { "_class": { @@ -12376,151 +9636,6 @@ } } }, - "devops.BranchPipelineRun": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "_links": { - "description": "references the reachable path to this resource", - "$ref": "#/definitions/._links" - }, - "actions": { - "description": "the list of all actions", - "type": "array", - "items": { - "$ref": "#/definitions/devops.BranchPipelineRun.actions" - } - }, - "artifactsZipFile": { - "description": "the artifacts zip file", - "$ref": "#/definitions/devops.BranchPipelineRun.artifactsZipFile" - }, - "branch": { - "$ref": "#/definitions/.branch" - }, - "causeOfBlockage": { - "description": "the cause of blockage", - "$ref": "#/definitions/devops.BranchPipelineRun.causeOfBlockage" - }, - "causes": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.BranchPipelineRun.causes" - } - }, - "changeSet": { - "description": "changeset information", - "type": "array", - "items": { - "$ref": "#/definitions/devops.BranchPipelineRun.changeSet" - } - }, - "commitId": { - "description": "commit id", - "type": "string" - }, - "commitUrl": { - "description": "commit url ", - "$ref": "#/definitions/devops.BranchPipelineRun.commitUrl" - }, - "description": { - "description": "description of resource", - "$ref": "#/definitions/devops.BranchPipelineRun.description" - }, - "durationInMillis": { - "description": "duration time in millis", - "type": "integer", - "format": "int32" - }, - "enQueueTime": { - "description": "the time of enter the queue", - "type": "string" - }, - "endTime": { - "description": "the time of end", - "type": "string" - }, - "estimatedDurationInMillis": { - "description": "estimated duration time, unit is millis", - "type": "integer", - "format": "int32" - }, - "id": { - "description": "id", - "type": "string" - }, - "name": { - "description": "name", - "$ref": "#/definitions/devops.BranchPipelineRun.name" - }, - "organization": { - "description": "the name of organization", - "type": "string" - }, - "pipeline": { - "description": "pipeline name", - "type": "string" - }, - "pullRequest": { - "description": "pull request", - "$ref": "#/definitions/devops.BranchPipelineRun.pullRequest" - }, - "replayable": { - "description": "replayable or not", - "type": "boolean" - }, - "result": { - "description": "the result of pipeline run. e.g. SUCCESS", - "type": "string" - }, - "runSummary": { - "description": "pipeline run summary", - "type": "string" - }, - "startTime": { - "description": "the time of start", - "type": "string" - }, - "state": { - "description": "run state. e.g. RUNNING", - "type": "string" - }, - "type": { - "description": "source type, such as \"WorkflowRun\"", - "type": "string" - } - } - }, - "devops.BranchPipelineRun.actions": {}, - "devops.BranchPipelineRun.artifactsZipFile": {}, - "devops.BranchPipelineRun.causeOfBlockage": {}, - "devops.BranchPipelineRun.causes": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "shortDescription": { - "description": "short description", - "type": "string" - }, - "userId": { - "description": "user id", - "type": "string" - }, - "userName": { - "description": "user name", - "type": "string" - } - } - }, - "devops.BranchPipelineRun.changeSet": {}, - "devops.BranchPipelineRun.commitUrl": {}, - "devops.BranchPipelineRun.description": {}, - "devops.BranchPipelineRun.name": {}, - "devops.BranchPipelineRun.pullRequest": {}, "devops.BranchPipelineRunNodes": { "properties": { "_class": { @@ -12736,10 +9851,11 @@ }, "value": { "description": "value", - "type": "string" + "$ref": "#/definitions/devops.CheckPlayloadParameters.value" } } }, + "devops.CheckPlayloadParameters.value": {}, "devops.CheckScript": { "properties": { "column": { @@ -12774,6 +9890,69 @@ } } }, + "devops.Credential": { + "required": [ + "id", + "type" + ], + "properties": { + "description": { + "description": "Credential's description'", + "type": "string" + }, + "display_name": { + "description": "Credential's display name", + "type": "string" + }, + "domain": { + "description": "Credential's domain,In ks we only use the default domain, default '_''", + "type": "string" + }, + "fingerprint": { + "description": "usage of the Credential", + "$ref": "#/definitions/devops.Credential.fingerprint" + }, + "id": { + "description": "Id of Credential, e.g. dockerhub-id", + "type": "string" + }, + "type": { + "description": "Type of Credential, e.g. ssh/kubeconfig", + "type": "string" + } + } + }, + "devops.Credential.fingerprint": { + "properties": { + "file_name": { + "description": "Credential's display name and description", + "type": "string" + }, + "hash": { + "description": "Credential's hash", + "type": "string" + }, + "usage": { + "description": "all usage of Credential", + "type": "array", + "items": { + "$ref": "#/definitions/devops.Credential.fingerprint.usage" + } + } + } + }, + "devops.Credential.fingerprint.usage": { + "properties": { + "name": { + "description": "pipeline full name", + "type": "string" + }, + "ranges": { + "description": "The build number of all pipelines that use this credential", + "$ref": "#/definitions/.ranges" + } + } + }, "devops.CronData": { "required": [ "cron" @@ -12805,154 +9984,6 @@ } } }, - "devops.DevOpsProjectMembership": { - "required": [ - "username", - "project_id", - "role", - "status" - ], - "properties": { - "grand_by": { - "description": "Username of the user who assigned the role", - "type": "string" - }, - "project_id": { - "description": "the DevOps Projects which project membership belongs to", - "type": "string" - }, - "role": { - "description": "DevOps Project membership's role type. e.g. owner '", - "type": "string" - }, - "status": { - "description": "Deprecated, Status of project membership. e.g. active ", - "type": "string" - }, - "username": { - "description": "Member's username,username can uniquely identify a user", - "type": "string" - } - } - }, - "devops.DiscarderProperty": { - "properties": { - "days_to_keep": { - "description": "days to keep pipeline", - "type": "string" - }, - "num_to_keep": { - "description": "nums to keep pipeline", - "type": "string" - } - } - }, - "devops.DiscoverPRFromForks": { - "properties": { - "strategy": { - "description": "github discover startegy", - "type": "integer", - "format": "int32" - }, - "trust": { - "description": "trust user type", - "type": "integer", - "format": "int32" - } - } - }, - "devops.GitCloneOption": { - "properties": { - "depth": { - "description": "git clone depth", - "type": "integer", - "format": "int32" - }, - "shallow": { - "description": "Whether to use git shallow clone", - "type": "boolean" - }, - "timeout": { - "description": "git clone timeout mins", - "type": "integer", - "format": "int32" - } - } - }, - "devops.GitSource": { - "properties": { - "credential_id": { - "description": "credential id to access git source", - "type": "string" - }, - "discover_branches": { - "description": "Whether to discover a branch", - "type": "boolean" - }, - "git_clone_option": { - "description": "advavced git clone options", - "$ref": "#/definitions/devops.GitCloneOption" - }, - "regex_filter": { - "description": "Regex used to match the name of the branch that needs to be run", - "type": "string" - }, - "scm_id": { - "description": "uid of scm", - "type": "string" - }, - "url": { - "description": "url of git source", - "type": "string" - } - } - }, - "devops.GithubSource": { - "properties": { - "api_uri": { - "description": "The api url can specify the location of the github apiserver.For private cloud configuration", - "type": "string" - }, - "credential_id": { - "description": "credential id to access github source", - "type": "string" - }, - "discover_branches": { - "description": "Discover branch configuration", - "type": "integer", - "format": "int32" - }, - "discover_pr_from_forks": { - "description": "Discover fork PR configuration", - "$ref": "#/definitions/devops.DiscoverPRFromForks" - }, - "discover_pr_from_origin": { - "description": "Discover origin PR configuration", - "type": "integer", - "format": "int32" - }, - "git_clone_option": { - "description": "advavced git clone options", - "$ref": "#/definitions/devops.GitCloneOption" - }, - "owner": { - "description": "owner of github repo", - "type": "string" - }, - "regex_filter": { - "description": "Regex used to match the name of the branch that needs to be run", - "type": "string" - }, - "repo": { - "description": "repo name of github repo", - "type": "string" - }, - "scm_id": { - "description": "uid of scm", - "type": "string" - } - } - }, "devops.Input": { "properties": { "_class": { @@ -12961,7 +9992,7 @@ }, "_links": { "description": "references the reachable path to this resource", - "$ref": "#/definitions/._links" + "$ref": "#/definitions/devops.Input._links" }, "id": { "description": "the id of check action", @@ -12988,215 +10019,25 @@ } } }, + "devops.Input._links": { + "properties": { + "self": { + "$ref": "#/definitions/devops.Input._links.self" + } + } + }, + "devops.Input._links.self": { + "properties": { + "_class": { + "type": "string" + }, + "href": { + "type": "string" + } + } + }, "devops.Input.parameters": {}, "devops.Input.submitter": {}, - "devops.JenkinsCredential": { - "required": [ - "id", - "type" - ], - "properties": { - "create_time": { - "description": "Credential's create_time'", - "type": "string", - "format": "date-time" - }, - "creator": { - "description": "Creator's username", - "type": "string" - }, - "description": { - "description": "Credential's description'", - "type": "string" - }, - "display_name": { - "description": "Credential's display name", - "type": "string" - }, - "domain": { - "description": "Credential's domain,In ks we only use the default domain, default '_''", - "type": "string" - }, - "fingerprint": { - "description": "usage of the Credential", - "$ref": "#/definitions/devops.JenkinsCredential.fingerprint" - }, - "id": { - "description": "Id of Credential, e.g. dockerhub-id", - "type": "string" - }, - "kubeconfig": { - "description": "kubeconfig Credential struct", - "$ref": "#/definitions/devops.KubeconfigCredential" - }, - "secret_text": { - "description": "secret_text Credential struct", - "$ref": "#/definitions/devops.SecretTextCredential" - }, - "ssh": { - "description": "ssh Credential struct", - "$ref": "#/definitions/devops.SshCredential" - }, - "type": { - "description": "Type of Credential, e.g. ssh/kubeconfig", - "type": "string" - }, - "username_password": { - "description": "username password Credential struct", - "$ref": "#/definitions/devops.UsernamePasswordCredential" - } - } - }, - "devops.JenkinsCredential.fingerprint": { - "properties": { - "file_name": { - "description": "Credential's display name and description", - "type": "string" - }, - "hash": { - "description": "Credential's hash", - "type": "string" - }, - "usage": { - "description": "all usage of Credential", - "type": "array", - "items": { - "$ref": "#/definitions/devops.JenkinsCredential.fingerprint.usage" - } - } - } - }, - "devops.JenkinsCredential.fingerprint.usage": { - "properties": { - "name": { - "description": "Jenkins pipeline full name", - "type": "string" - }, - "ranges": { - "description": "The build number of all pipelines that use this credential", - "$ref": "#/definitions/.ranges" - } - } - }, - "devops.KubeconfigCredential": { - "properties": { - "content": { - "description": "content of kubeconfig", - "type": "string" - } - } - }, - "devops.MultiBranchJobTrigger": { - "properties": { - "create_action_job_to_trigger": { - "description": "pipeline name to trigger", - "type": "string" - }, - "delete_action_job_to_trigger": { - "description": "pipeline name to trigger", - "type": "string" - } - } - }, - "devops.MultiBranchPipeline": { - "required": [ - "name", - "source_type", - "script_path" - ], - "properties": { - "bitbucket_server_source": { - "description": "bitbucket server scm defile", - "$ref": "#/definitions/devops.BitbucketServerSource" - }, - "descriptio": { - "description": "description of pipeline", - "type": "string" - }, - "discarder": { - "description": "Discarder of pipeline, managing when to drop a pipeline", - "$ref": "#/definitions/devops.DiscarderProperty" - }, - "git_source": { - "description": "git scm define", - "$ref": "#/definitions/devops.GitSource" - }, - "github_source": { - "description": "github scm define", - "$ref": "#/definitions/devops.GithubSource" - }, - "multibranch_job_trigger": { - "description": "Pipeline tasks that need to be triggered when branch creation/deletion", - "$ref": "#/definitions/devops.MultiBranchJobTrigger" - }, - "name": { - "description": "name of pipeline", - "type": "string" - }, - "script_path": { - "description": "script path in scm", - "type": "string" - }, - "single_svn_source": { - "description": "single branch svn scm define", - "$ref": "#/definitions/devops.SingleSvnSource" - }, - "source_type": { - "description": "type of scm, such as github/git/svn", - "type": "string" - }, - "svn_source": { - "description": "multi branch svn scm define", - "$ref": "#/definitions/devops.SvnSource" - }, - "timer_trigger": { - "description": "Timer to trigger pipeline run", - "$ref": "#/definitions/devops.TimerTrigger" - } - } - }, - "devops.NoScmPipeline": { - "required": [ - "name" - ], - "properties": { - "descriptio": { - "description": "description of pipeline", - "type": "string" - }, - "disable_concurrent": { - "description": "Whether to prohibit the pipeline from running in parallel", - "type": "boolean" - }, - "discarder": { - "description": "Discarder of pipeline, managing when to drop a pipeline", - "$ref": "#/definitions/devops.DiscarderProperty" - }, - "jenkinsfile": { - "description": "Jenkinsfile's content'", - "type": "string" - }, - "name": { - "description": "name of pipeline", - "type": "string" - }, - "parameters": { - "description": "Parameters define of pipeline,user could pass param when run pipeline", - "type": "array", - "items": { - "$ref": "#/definitions/devops.Parameter" - } - }, - "remote_trigger": { - "description": "Remote api define to trigger pipeline run", - "$ref": "#/definitions/devops.RemoteTrigger" - }, - "timer_trigger": { - "description": "Timer to trigger pipeline run", - "$ref": "#/definitions/devops.TimerTrigger" - } - } - }, "devops.NodeSteps": { "properties": { "_class": { @@ -13298,11 +10139,12 @@ "type": "string" }, "durationInMillis": { - "description": "duration time in millis", + "description": "duration time in mullis", "type": "integer", "format": "int32" }, "edges": { + "description": "edges", "type": "array", "items": { "$ref": "#/definitions/devops.NodesDetail.edges" @@ -13333,7 +10175,7 @@ "type": "string" }, "state": { - "description": "run state. e.g. SKIPPED", + "description": "run state. e.g. FINISHED", "type": "string" }, "steps": { @@ -13352,22 +10194,7 @@ "devops.NodesDetail.actions": {}, "devops.NodesDetail.causeOfBlockage": {}, "devops.NodesDetail.displayDescription": {}, - "devops.NodesDetail.edges": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "id": { - "description": "id", - "type": "string" - }, - "type": { - "description": "type", - "type": "string" - } - } - }, + "devops.NodesDetail.edges": {}, "devops.NodesDetail.firstParent": {}, "devops.OrgRepo": { "properties": { @@ -13384,122 +10211,6 @@ } } }, - "devops.Parameter": { - "required": [ - "name", - "type" - ], - "properties": { - "default_value": { - "description": "default value of param", - "type": "string" - }, - "description": { - "description": "description of pipeline", - "type": "string" - }, - "name": { - "description": "name of param", - "type": "string" - }, - "type": { - "description": "type of param", - "type": "string" - } - } - }, - "devops.PipeBranch": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "_links": { - "description": "references the reachable path to this resource", - "$ref": "#/definitions/._links" - }, - "actions": { - "description": "the list of all actions.", - "type": "array", - "items": { - "$ref": "#/definitions/devops.PipeBranch.actions" - } - }, - "branch": { - "$ref": "#/definitions/.branch" - }, - "disabled": { - "description": "disable or not, if disabled, can not do any action", - "type": "boolean" - }, - "displayName": { - "description": "display name", - "type": "string" - }, - "estimatedDurationInMillis": { - "description": "estimated duration time, unit is millis", - "type": "integer", - "format": "int32" - }, - "fullDisplayName": { - "description": "full display name", - "type": "string" - }, - "fullName": { - "description": "full name", - "type": "string" - }, - "latestRun": { - "$ref": "#/definitions/.latestRun" - }, - "name": { - "description": "name", - "type": "string" - }, - "organization": { - "description": "the name of organization", - "type": "string" - }, - "parameters": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.PipeBranch.parameters" - } - }, - "permissions": { - "$ref": "#/definitions/.permissions" - }, - "weatherScore": { - "description": "the score to description the result of pipeline", - "type": "integer", - "format": "int32" - } - } - }, - "devops.PipeBranch.actions": {}, - "devops.PipeBranch.parameters": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "defaultParameterValue": { - "$ref": "#/definitions/.defaultParameterValue" - }, - "description": { - "description": "description", - "type": "string" - }, - "name": { - "description": "name", - "type": "string" - }, - "type": { - "description": "type", - "type": "string" - } - } - }, "devops.Pipeline": { "properties": { "_class": { @@ -13622,6 +10333,116 @@ "devops.Pipeline.disabled": {}, "devops.Pipeline.parameters": {}, "devops.Pipeline.pipelineFolderNames": {}, + "devops.PipelineBranch": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "_links": { + "description": "references the reachable path to this resource", + "$ref": "#/definitions/._links" + }, + "actions": { + "description": "the list of all actions.", + "type": "array", + "items": { + "$ref": "#/definitions/devops.PipelineBranch.actions" + } + }, + "branch": { + "$ref": "#/definitions/.branch" + }, + "disabled": { + "description": "disable or not, if disabled, can not do any action", + "type": "boolean" + }, + "displayName": { + "description": "display name", + "type": "string" + }, + "estimatedDurationInMillis": { + "description": "estimated duration time, unit is millis", + "type": "integer", + "format": "int32" + }, + "fullDisplayName": { + "description": "full display name", + "type": "string" + }, + "fullName": { + "description": "full name", + "type": "string" + }, + "latestRun": { + "$ref": "#/definitions/.latestRun" + }, + "name": { + "description": "name", + "type": "string" + }, + "organization": { + "description": "the name of organization", + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/devops.PipelineBranch.parameters" + } + }, + "permissions": { + "$ref": "#/definitions/.permissions" + }, + "weatherScore": { + "description": "the score to description the result of pipeline", + "type": "integer", + "format": "int32" + } + } + }, + "devops.PipelineBranch.actions": {}, + "devops.PipelineBranch.parameters": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "defaultParameterValue": { + "$ref": "#/definitions/.defaultParameterValue" + }, + "description": { + "description": "description", + "type": "string" + }, + "name": { + "description": "name", + "type": "string" + }, + "type": { + "description": "type", + "type": "string" + } + } + }, + "devops.PipelineList": { + "required": [ + "items", + "total_count" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/devops.Pipeline" + } + }, + "total_count": { + "type": "integer", + "format": "int32" + } + } + }, "devops.PipelineRun": { "properties": { "_class": { @@ -13770,6 +10591,151 @@ "devops.PipelineRun.description": {}, "devops.PipelineRun.name": {}, "devops.PipelineRun.pullRequest": {}, + "devops.PipelineRunList": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "_links": { + "description": "references the reachable path to this resource", + "$ref": "#/definitions/._links" + }, + "actions": { + "description": "the list of all actions", + "type": "array", + "items": { + "$ref": "#/definitions/devops.PipelineRunList.actions" + } + }, + "artifactsZipFile": { + "description": "the artifacts zip file", + "$ref": "#/definitions/devops.PipelineRunList.artifactsZipFile" + }, + "branch": { + "$ref": "#/definitions/.branch" + }, + "causeOfBlockage": { + "description": "the cause of blockage", + "$ref": "#/definitions/devops.PipelineRunList.causeOfBlockage" + }, + "causes": { + "type": "array", + "items": { + "$ref": "#/definitions/devops.PipelineRunList.causes" + } + }, + "changeSet": { + "description": "changeset information", + "type": "array", + "items": { + "$ref": "#/definitions/devops.PipelineRunList.changeSet" + } + }, + "commitId": { + "description": "commit id", + "type": "string" + }, + "commitUrl": { + "description": "commit url ", + "$ref": "#/definitions/devops.PipelineRunList.commitUrl" + }, + "description": { + "description": "description of resource", + "$ref": "#/definitions/devops.PipelineRunList.description" + }, + "durationInMillis": { + "description": "duration time in millis", + "type": "integer", + "format": "int32" + }, + "enQueueTime": { + "description": "the time of enter the queue", + "type": "string" + }, + "endTime": { + "description": "the time of end", + "type": "string" + }, + "estimatedDurationInMillis": { + "description": "estimated duration time, unit is millis", + "type": "integer", + "format": "int32" + }, + "id": { + "description": "id", + "type": "string" + }, + "name": { + "description": "name", + "$ref": "#/definitions/devops.PipelineRunList.name" + }, + "organization": { + "description": "the name of organization", + "type": "string" + }, + "pipeline": { + "description": "pipeline name", + "type": "string" + }, + "pullRequest": { + "description": "pull request", + "$ref": "#/definitions/devops.PipelineRunList.pullRequest" + }, + "replayable": { + "description": "replayable or not", + "type": "boolean" + }, + "result": { + "description": "the result of pipeline run. e.g. SUCCESS", + "type": "string" + }, + "runSummary": { + "description": "pipeline run summary", + "type": "string" + }, + "startTime": { + "description": "the time of start", + "type": "string" + }, + "state": { + "description": "run state. e.g. RUNNING", + "type": "string" + }, + "type": { + "description": "source type, such as \"WorkflowRun\"", + "type": "string" + } + } + }, + "devops.PipelineRunList.actions": {}, + "devops.PipelineRunList.artifactsZipFile": {}, + "devops.PipelineRunList.causeOfBlockage": {}, + "devops.PipelineRunList.causes": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "shortDescription": { + "description": "short description", + "type": "string" + }, + "userId": { + "description": "user id", + "type": "string" + }, + "userName": { + "description": "user name", + "type": "string" + } + } + }, + "devops.PipelineRunList.changeSet": {}, + "devops.PipelineRunList.commitUrl": {}, + "devops.PipelineRunList.description": {}, + "devops.PipelineRunList.name": {}, + "devops.PipelineRunList.pullRequest": {}, "devops.PipelineRunNodes": { "properties": { "_class": { @@ -13850,169 +10816,7 @@ "devops.PipelineRunNodes.displayDescription": {}, "devops.PipelineRunNodes.edges": {}, "devops.PipelineRunNodes.firstParent": {}, - "devops.ProjectPipeline": { - "required": [ - "type" - ], - "properties": { - "multi_branch_pipeline": { - "description": "in scm pipeline structs", - "$ref": "#/definitions/devops.MultiBranchPipeline" - }, - "pipeline": { - "description": "no scm pipeline structs", - "$ref": "#/definitions/devops.NoScmPipeline" - }, - "type": { - "description": "type of devops pipeline, in scm or no scm", - "type": "string" - } - } - }, - "devops.QueuedBlueRun": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "_links": { - "description": "references the reachable path to this resource", - "$ref": "#/definitions/._links" - }, - "actions": { - "description": "the list of all actions", - "type": "array", - "items": { - "$ref": "#/definitions/devops.QueuedBlueRun.actions" - } - }, - "artifactsZipFile": { - "description": "the artifacts zip file", - "$ref": "#/definitions/devops.QueuedBlueRun.artifactsZipFile" - }, - "causeOfBlockage": { - "description": "the cause of blockage", - "type": "string" - }, - "causes": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.QueuedBlueRun.causes" - } - }, - "changeSet": { - "description": "changeset information", - "type": "array", - "items": { - "$ref": "#/definitions/devops.QueuedBlueRun.changeSet" - } - }, - "description": { - "description": "description", - "$ref": "#/definitions/devops.QueuedBlueRun.description" - }, - "durationInMillis": { - "description": "duration time in millis", - "$ref": "#/definitions/devops.QueuedBlueRun.durationInMillis" - }, - "enQueueTime": { - "description": "the time of enter the queue", - "$ref": "#/definitions/devops.QueuedBlueRun.enQueueTime" - }, - "endTime": { - "description": "the time of end", - "$ref": "#/definitions/devops.QueuedBlueRun.endTime" - }, - "estimatedDurationInMillis": { - "description": "estimated duration time in millis", - "$ref": "#/definitions/devops.QueuedBlueRun.estimatedDurationInMillis" - }, - "id": { - "description": "id", - "type": "string" - }, - "name": { - "description": "name", - "$ref": "#/definitions/devops.QueuedBlueRun.name" - }, - "organization": { - "description": "the name of organization", - "type": "string" - }, - "pipeline": { - "description": "pipeline", - "type": "string" - }, - "queueId": { - "description": "queue id", - "type": "string" - }, - "replayable": { - "description": "replayable or not", - "type": "boolean" - }, - "result": { - "description": "the result of pipeline run. e.g. SUCCESS", - "type": "string" - }, - "runSummary": { - "description": "pipeline run summary", - "$ref": "#/definitions/devops.QueuedBlueRun.runSummary" - }, - "startTime": { - "description": "the time of start", - "$ref": "#/definitions/devops.QueuedBlueRun.startTime" - }, - "state": { - "description": "run state. e.g. RUNNING", - "type": "string" - }, - "type": { - "description": "type", - "type": "string" - } - } - }, - "devops.QueuedBlueRun.actions": {}, - "devops.QueuedBlueRun.artifactsZipFile": {}, - "devops.QueuedBlueRun.causes": { - "properties": { - "_class": { - "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", - "type": "string" - }, - "shortDescription": { - "description": "short description", - "type": "string" - }, - "userId": { - "description": "user id", - "type": "string" - }, - "userName": { - "description": "user name", - "type": "string" - } - } - }, - "devops.QueuedBlueRun.changeSet": {}, - "devops.QueuedBlueRun.description": {}, - "devops.QueuedBlueRun.durationInMillis": {}, - "devops.QueuedBlueRun.enQueueTime": {}, - "devops.QueuedBlueRun.endTime": {}, - "devops.QueuedBlueRun.estimatedDurationInMillis": {}, - "devops.QueuedBlueRun.name": {}, - "devops.QueuedBlueRun.runSummary": {}, - "devops.QueuedBlueRun.startTime": {}, - "devops.RemoteTrigger": { - "properties": { - "token": { - "description": "remote trigger token", - "type": "string" - } - } - }, - "devops.ReplayPipe": { + "devops.ReplayPipeline": { "properties": { "_class": { "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", @@ -14026,12 +10830,12 @@ "description": "the list of all actions.", "type": "array", "items": { - "$ref": "#/definitions/devops.ReplayPipe.actions" + "$ref": "#/definitions/devops.ReplayPipeline.actions" } }, "artifactsZipFile": { "description": "the artifacts zip file", - "$ref": "#/definitions/devops.ReplayPipe.artifactsZipFile" + "$ref": "#/definitions/devops.ReplayPipeline.artifactsZipFile" }, "causeOfBlockage": { "description": "the cause of blockage", @@ -14040,35 +10844,35 @@ "causes": { "type": "array", "items": { - "$ref": "#/definitions/devops.ReplayPipe.causes" + "$ref": "#/definitions/devops.ReplayPipeline.causes" } }, "changeSet": { "description": "changeset information", "type": "array", "items": { - "$ref": "#/definitions/devops.ReplayPipe.changeSet" + "$ref": "#/definitions/devops.ReplayPipeline.changeSet" } }, "description": { "description": "description", - "$ref": "#/definitions/devops.ReplayPipe.description" + "$ref": "#/definitions/devops.ReplayPipeline.description" }, "durationInMillis": { "description": "duration time in millis", - "$ref": "#/definitions/devops.ReplayPipe.durationInMillis" + "$ref": "#/definitions/devops.ReplayPipeline.durationInMillis" }, "enQueueTime": { "description": "the time of enter the queue", - "$ref": "#/definitions/devops.ReplayPipe.enQueueTime" + "$ref": "#/definitions/devops.ReplayPipeline.enQueueTime" }, "endTime": { "description": "the time of end", - "$ref": "#/definitions/devops.ReplayPipe.endTime" + "$ref": "#/definitions/devops.ReplayPipeline.endTime" }, "estimatedDurationInMillis": { "description": "estimated duration time, unit is millis", - "$ref": "#/definitions/devops.ReplayPipe.estimatedDurationInMillis" + "$ref": "#/definitions/devops.ReplayPipeline.estimatedDurationInMillis" }, "id": { "description": "id", @@ -14076,7 +10880,7 @@ }, "name": { "description": "name", - "$ref": "#/definitions/devops.ReplayPipe.name" + "$ref": "#/definitions/devops.ReplayPipeline.name" }, "organization": { "description": "the name of organization", @@ -14100,11 +10904,11 @@ }, "runSummary": { "description": "pipeline run summary", - "$ref": "#/definitions/devops.ReplayPipe.runSummary" + "$ref": "#/definitions/devops.ReplayPipeline.runSummary" }, "startTime": { "description": "the time of start", - "$ref": "#/definitions/devops.ReplayPipe.startTime" + "$ref": "#/definitions/devops.ReplayPipeline.startTime" }, "state": { "description": "run state. e.g. RUNNING", @@ -14116,9 +10920,9 @@ } } }, - "devops.ReplayPipe.actions": {}, - "devops.ReplayPipe.artifactsZipFile": {}, - "devops.ReplayPipe.causes": { + "devops.ReplayPipeline.actions": {}, + "devops.ReplayPipeline.artifactsZipFile": {}, + "devops.ReplayPipeline.causes": { "properties": { "_class": { "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", @@ -14138,15 +10942,15 @@ } } }, - "devops.ReplayPipe.changeSet": {}, - "devops.ReplayPipe.description": {}, - "devops.ReplayPipe.durationInMillis": {}, - "devops.ReplayPipe.enQueueTime": {}, - "devops.ReplayPipe.endTime": {}, - "devops.ReplayPipe.estimatedDurationInMillis": {}, - "devops.ReplayPipe.name": {}, - "devops.ReplayPipe.runSummary": {}, - "devops.ReplayPipe.startTime": {}, + "devops.ReplayPipeline.changeSet": {}, + "devops.ReplayPipeline.description": {}, + "devops.ReplayPipeline.durationInMillis": {}, + "devops.ReplayPipeline.enQueueTime": {}, + "devops.ReplayPipeline.endTime": {}, + "devops.ReplayPipeline.estimatedDurationInMillis": {}, + "devops.ReplayPipeline.name": {}, + "devops.ReplayPipeline.runSummary": {}, + "devops.ReplayPipeline.startTime": {}, "devops.ReqJenkinsfile": { "properties": { "jenkinsfile": { @@ -14193,22 +10997,6 @@ } } }, - "devops.Role": { - "required": [ - "name", - "description" - ], - "properties": { - "description": { - "description": "role 's description'", - "type": "string" - }, - "name": { - "description": "role's name e.g. owner'", - "type": "string" - } - } - }, "devops.RunPayload": { "properties": { "parameters": { @@ -14231,6 +11019,141 @@ } } }, + "devops.RunPipeline": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "_links": { + "description": "references the reachable path to this resource", + "$ref": "#/definitions/._links" + }, + "actions": { + "description": "the list of all actions", + "type": "array", + "items": { + "$ref": "#/definitions/devops.RunPipeline.actions" + } + }, + "artifactsZipFile": { + "description": "the artifacts zip file", + "$ref": "#/definitions/devops.RunPipeline.artifactsZipFile" + }, + "causeOfBlockage": { + "description": "the cause of blockage", + "type": "string" + }, + "causes": { + "type": "array", + "items": { + "$ref": "#/definitions/devops.RunPipeline.causes" + } + }, + "changeSet": { + "description": "changeset information", + "type": "array", + "items": { + "$ref": "#/definitions/devops.RunPipeline.changeSet" + } + }, + "description": { + "description": "description", + "$ref": "#/definitions/devops.RunPipeline.description" + }, + "durationInMillis": { + "description": "duration time in millis", + "$ref": "#/definitions/devops.RunPipeline.durationInMillis" + }, + "enQueueTime": { + "description": "the time of enter the queue", + "$ref": "#/definitions/devops.RunPipeline.enQueueTime" + }, + "endTime": { + "description": "the time of end", + "$ref": "#/definitions/devops.RunPipeline.endTime" + }, + "estimatedDurationInMillis": { + "description": "estimated duration time in millis", + "$ref": "#/definitions/devops.RunPipeline.estimatedDurationInMillis" + }, + "id": { + "description": "id", + "type": "string" + }, + "name": { + "description": "name", + "$ref": "#/definitions/devops.RunPipeline.name" + }, + "organization": { + "description": "the name of organization", + "type": "string" + }, + "pipeline": { + "description": "pipeline", + "type": "string" + }, + "queueId": { + "description": "queue id", + "type": "string" + }, + "replayable": { + "description": "replayable or not", + "type": "boolean" + }, + "result": { + "description": "the result of pipeline run. e.g. SUCCESS", + "type": "string" + }, + "runSummary": { + "description": "pipeline run summary", + "$ref": "#/definitions/devops.RunPipeline.runSummary" + }, + "startTime": { + "description": "the time of start", + "$ref": "#/definitions/devops.RunPipeline.startTime" + }, + "state": { + "description": "run state. e.g. RUNNING", + "type": "string" + }, + "type": { + "description": "type", + "type": "string" + } + } + }, + "devops.RunPipeline.actions": {}, + "devops.RunPipeline.artifactsZipFile": {}, + "devops.RunPipeline.causes": { + "properties": { + "_class": { + "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", + "type": "string" + }, + "shortDescription": { + "description": "short description", + "type": "string" + }, + "userId": { + "description": "user id", + "type": "string" + }, + "userName": { + "description": "user name", + "type": "string" + } + } + }, + "devops.RunPipeline.changeSet": {}, + "devops.RunPipeline.description": {}, + "devops.RunPipeline.durationInMillis": {}, + "devops.RunPipeline.enQueueTime": {}, + "devops.RunPipeline.endTime": {}, + "devops.RunPipeline.estimatedDurationInMillis": {}, + "devops.RunPipeline.name": {}, + "devops.RunPipeline.runSummary": {}, + "devops.RunPipeline.startTime": {}, "devops.SCMOrg": { "properties": { "_class": { @@ -14279,63 +11202,7 @@ } } }, - "devops.SecretTextCredential": { - "properties": { - "secret": { - "description": "secret content of credential", - "type": "string" - } - } - }, - "devops.SingleSvnSource": { - "properties": { - "credential_id": { - "description": "credential id to access svn source", - "type": "string" - }, - "remote": { - "description": "remote address url", - "type": "string" - }, - "scm_id": { - "description": "uid of scm", - "type": "string" - } - } - }, - "devops.SonarStatus": { - "properties": { - "issues": { - "$ref": "#/definitions/sonargo.IssuesSearchObject" - }, - "jenkinsAction": { - "$ref": "#/definitions/gojenkins.GeneralObj" - }, - "measures": { - "$ref": "#/definitions/sonargo.MeasuresComponentObject" - }, - "task": { - "$ref": "#/definitions/sonargo.CeTaskObject" - } - } - }, - "devops.SshCredential": { - "properties": { - "passphrase": { - "description": "passphrase of ssh credential, password of ssh credential", - "type": "string" - }, - "private_key": { - "description": "private key of ssh credential", - "type": "string" - }, - "username": { - "description": "username of ssh credential", - "type": "string" - } - } - }, - "devops.StopPipe": { + "devops.StopPipeline": { "properties": { "_class": { "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", @@ -14349,31 +11216,31 @@ "description": "the list of all actions.", "type": "array", "items": { - "$ref": "#/definitions/devops.StopPipe.actions" + "$ref": "#/definitions/devops.StopPipeline.actions" } }, "artifactsZipFile": { "description": "the artifacts zip file", - "$ref": "#/definitions/devops.StopPipe.artifactsZipFile" + "$ref": "#/definitions/devops.StopPipeline.artifactsZipFile" }, "branch": { "$ref": "#/definitions/.branch" }, "causeOfBlockage": { "description": "the cause of blockage", - "$ref": "#/definitions/devops.StopPipe.causeOfBlockage" + "$ref": "#/definitions/devops.StopPipeline.causeOfBlockage" }, "causes": { "type": "array", "items": { - "$ref": "#/definitions/devops.StopPipe.causes" + "$ref": "#/definitions/devops.StopPipeline.causes" } }, "changeSet": { "description": "changeset information", "type": "array", "items": { - "$ref": "#/definitions/devops.StopPipe.changeSet" + "$ref": "#/definitions/devops.StopPipeline.changeSet" } }, "commitId": { @@ -14382,11 +11249,11 @@ }, "commitUrl": { "description": "commit url", - "$ref": "#/definitions/devops.StopPipe.commitUrl" + "$ref": "#/definitions/devops.StopPipeline.commitUrl" }, "description": { "description": "description", - "$ref": "#/definitions/devops.StopPipe.description" + "$ref": "#/definitions/devops.StopPipeline.description" }, "durationInMillis": { "description": "duration time in millis", @@ -14412,7 +11279,7 @@ }, "name": { "description": "name", - "$ref": "#/definitions/devops.StopPipe.name" + "$ref": "#/definitions/devops.StopPipeline.name" }, "organization": { "description": "the name of organization", @@ -14424,7 +11291,7 @@ }, "pullRequest": { "description": "pull request", - "$ref": "#/definitions/devops.StopPipe.pullRequest" + "$ref": "#/definitions/devops.StopPipeline.pullRequest" }, "replayable": { "description": "replayable or not", @@ -14452,10 +11319,10 @@ } } }, - "devops.StopPipe.actions": {}, - "devops.StopPipe.artifactsZipFile": {}, - "devops.StopPipe.causeOfBlockage": {}, - "devops.StopPipe.causes": { + "devops.StopPipeline.actions": {}, + "devops.StopPipeline.artifactsZipFile": {}, + "devops.StopPipeline.causeOfBlockage": {}, + "devops.StopPipeline.causes": { "properties": { "_class": { "description": "It’s a fully qualified name and is an identifier of the producer of this resource's capability.", @@ -14467,59 +11334,11 @@ } } }, - "devops.StopPipe.changeSet": {}, - "devops.StopPipe.commitUrl": {}, - "devops.StopPipe.description": {}, - "devops.StopPipe.name": {}, - "devops.StopPipe.pullRequest": {}, - "devops.SvnSource": { - "properties": { - "credential_id": { - "description": "credential id to access svn source", - "type": "string" - }, - "excludes": { - "description": "branches do not run pipeline", - "type": "string" - }, - "includes": { - "description": "branches to run pipeline", - "type": "string" - }, - "remote": { - "description": "remote address url", - "type": "string" - }, - "scm_id": { - "description": "uid of scm", - "type": "string" - } - } - }, - "devops.TimerTrigger": { - "properties": { - "cron": { - "description": "jenkins cron script", - "type": "string" - }, - "interval": { - "description": "interval ms", - "type": "string" - } - } - }, - "devops.UsernamePasswordCredential": { - "properties": { - "password": { - "description": "password of username_password credential", - "type": "string" - }, - "username": { - "description": "username of username_password credential", - "type": "string" - } - } - }, + "devops.StopPipeline.changeSet": {}, + "devops.StopPipeline.commitUrl": {}, + "devops.StopPipeline.description": {}, + "devops.StopPipeline.name": {}, + "devops.StopPipeline.pullRequest": {}, "devops.Validates": { "properties": { "credentialId": { @@ -14539,91 +11358,6 @@ } } }, - "fluentbitclient.KubernetesSecret": { - "required": [ - "name", - "key", - "namespace" - ], - "properties": { - "key": { - "type": "string" - }, - "name": { - "type": "string" - }, - "namespace": { - "type": "string" - } - } - }, - "fluentbitclient.OutputPlugin": { - "required": [ - "parameters", - "type", - "name", - "enable" - ], - "properties": { - "enable": { - "description": "active status, one of true, false", - "type": "boolean" - }, - "id": { - "description": "output uuid", - "type": "string" - }, - "name": { - "description": "output plugin name, eg. fluentbit-output-es", - "type": "string" - }, - "parameters": { - "description": "output plugin configuration parameters", - "type": "array", - "items": { - "$ref": "#/definitions/fluentbitclient.Parameter" - } - }, - "type": { - "description": "output plugin type, eg. fluentbit-output-es", - "type": "string" - }, - "updatetime": { - "description": "last updatetime", - "type": "string", - "format": "date-time" - } - } - }, - "fluentbitclient.Parameter": { - "required": [ - "name", - "value" - ], - "properties": { - "name": { - "description": "configuration parameter key, eg. Name. refer to Fluent bit's Output Plugins Section for more configuration parameters.", - "type": "string" - }, - "value": { - "description": "configuration parameter value, eg. es. refer to Fluent bit's Output Plugins Section for more configuration parameters.", - "type": "string" - }, - "valueFrom": { - "$ref": "#/definitions/fluentbitclient.ValueFrom" - } - } - }, - "fluentbitclient.ValueFrom": { - "required": [ - "secretKeyRef" - ], - "properties": { - "secretKeyRef": { - "$ref": "#/definitions/fluentbitclient.KubernetesSecret" - } - } - }, "git.AuthInfo": { "required": [ "remoteUrl" @@ -14639,218 +11373,6 @@ } } }, - "gojenkins.BuildRevision": { - "properties": { - "SHA1": { - "type": "string" - }, - "branch": { - "type": "array", - "items": { - "$ref": "#/definitions/gojenkins.branch" - } - } - } - }, - "gojenkins.Builds": { - "required": [ - "buildNumber", - "buildResult", - "marked", - "revision" - ], - "properties": { - "buildNumber": { - "type": "integer", - "format": "int64" - }, - "buildResult": { - "$ref": "#/definitions/gojenkins.Builds.buildResult" - }, - "marked": { - "$ref": "#/definitions/gojenkins.BuildRevision" - }, - "revision": { - "$ref": "#/definitions/gojenkins.BuildRevision" - } - } - }, - "gojenkins.Builds.buildResult": {}, - "gojenkins.GeneralObj": { - "properties": { - "TotalCount": { - "type": "integer", - "format": "int64" - }, - "UrlName": { - "type": "string" - }, - "_class": { - "type": "string" - }, - "buildsByBranchName": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/gojenkins.Builds" - } - }, - "causes": { - "type": "array", - "items": { - "$ref": "#/definitions/gojenkins.GeneralObj.causes" - } - }, - "ceTaskId": { - "type": "string" - }, - "lastBuiltRevision": { - "$ref": "#/definitions/gojenkins.BuildRevision" - }, - "mercurialNodeName": { - "type": "string" - }, - "mercurialRevisionNumber": { - "type": "string" - }, - "parameters": { - "type": "array", - "items": { - "$ref": "#/definitions/gojenkins.parameter" - } - }, - "remoteUrls": { - "type": "array", - "items": { - "type": "string" - } - }, - "scmName": { - "type": "string" - }, - "serverUrl": { - "type": "string" - }, - "sonarqubeDashboardUrl": { - "type": "string" - }, - "subdir": { - "$ref": "#/definitions/gojenkins.GeneralObj.subdir" - } - } - }, - "gojenkins.GeneralObj.causes": {}, - "gojenkins.GeneralObj.subdir": {}, - "gojenkins.branch": { - "properties": { - "Name": { - "type": "string" - }, - "SHA1": { - "type": "string" - } - } - }, - "gojenkins.parameter": { - "required": [ - "Name", - "Value" - ], - "properties": { - "Name": { - "type": "string" - }, - "Value": { - "type": "string" - } - } - }, - "iam.LoginRequest": { - "required": [ - "username", - "password" - ], - "properties": { - "password": { - "description": "password", - "type": "string" - }, - "username": { - "description": "username", - "type": "string" - } - } - }, - "iam.RoleList": { - "required": [ - "clusterRole", - "roles" - ], - "properties": { - "clusterRole": { - "description": "cluster role list", - "type": "array", - "items": { - "$ref": "#/definitions/v1.ClusterRole" - } - }, - "roles": { - "description": "role list", - "type": "array", - "items": { - "$ref": "#/definitions/v1.Role" - } - } - } - }, - "iam.Spec": { - "required": [ - "token" - ], - "properties": { - "token": { - "description": "access token", - "type": "string" - } - } - }, - "iam.Status": { - "required": [ - "authenticated" - ], - "properties": { - "authenticated": { - "description": "is authenticated", - "type": "boolean" - }, - "user": { - "description": "user info", - "type": "object" - } - } - }, - "iam.TokenReview": { - "required": [ - "apiVersion", - "kind" - ], - "properties": { - "apiVersion": { - "description": "Kubernetes API version", - "type": "string" - }, - "kind": { - "description": "kind of the API object", - "type": "string" - }, - "spec": { - "$ref": "#/definitions/iam.Spec" - }, - "status": { - "description": "token review status", - "$ref": "#/definitions/iam.Status" - } - } - }, "inf.Dec": { "required": [ "unscaled", @@ -14865,92 +11387,102 @@ } } }, - "log.FluentbitOutputsResult": { + "logging.Bucket": { "required": [ - "status" + "time", + "count" ], "properties": { - "error": { - "description": "debug information", - "type": "string" - }, - "outputs": { - "description": "array of fluent bit output plugins", - "type": "array", - "items": { - "$ref": "#/definitions/fluentbitclient.OutputPlugin" - } - }, - "status": { - "description": "response status", + "count": { + "description": "total number of logs at intervals", "type": "integer", - "format": "int32" + "format": "int64" + }, + "time": { + "description": "timestamp", + "type": "integer", + "format": "int64" } } }, - "metrics.APIResponse": { + "logging.Histogram": { "required": [ - "status", - "data" + "total", + "histograms" ], "properties": { - "data": { - "description": "actual metric result", - "$ref": "#/definitions/v1alpha2.QueryResult" - }, - "error": { - "type": "string" - }, - "errorType": { - "type": "string" - }, - "metric_name": { - "description": "metric name, eg. scheduler_up_sum", - "type": "string" - }, - "status": { - "description": "result status, one of error, success", - "type": "string" - }, - "warnings": { + "histograms": { + "description": "actual array of histogram results", "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/logging.Bucket" } + }, + "total": { + "description": "total number of logs", + "type": "integer", + "format": "int64" } } }, - "metrics.Response": { + "logging.Logs": { "required": [ - "metrics_level", - "results" + "total" ], "properties": { - "metrics_level": { - "description": "metric level, eg. cluster", - "type": "string" - }, - "page": { - "description": "current page returned", - "type": "integer", - "format": "int32" - }, - "results": { + "records": { "description": "actual array of results", "type": "array", "items": { - "$ref": "#/definitions/metrics.APIResponse" + "$ref": "#/definitions/logging.Record" } }, - "total_item": { - "description": "page size", + "total": { + "description": "total number of matched results", "type": "integer", - "format": "int32" + "format": "int64" + } + } + }, + "logging.Record": { + "properties": { + "container": { + "description": "container name", + "type": "string" }, - "total_page": { - "description": "total number of pages", + "log": { + "description": "log message", + "type": "string" + }, + "namespace": { + "description": "namespace", + "type": "string" + }, + "pod": { + "description": "pod name", + "type": "string" + }, + "time": { + "description": "log timestamp", + "type": "string" + } + } + }, + "logging.Statistics": { + "required": [ + "containers", + "logs" + ], + "properties": { + "containers": { + "description": "total number of containers", "type": "integer", - "format": "int32" + "format": "int64" + }, + "logs": { + "description": "total number of logs", + "type": "integer", + "format": "int64" } } }, @@ -14989,23 +11521,6 @@ } } }, - "models.Action": { - "required": [ - "name", - "rules" - ], - "properties": { - "name": { - "type": "string" - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.PolicyRule" - } - } - } - }, "models.AppHealth": { "required": [ "workloadStatuses", @@ -15023,96 +11538,6 @@ } } }, - "models.ComponentStatus": { - "required": [ - "name", - "namespace", - "selfLink", - "label", - "startedAt", - "totalBackends", - "healthyBackends" - ], - "properties": { - "healthyBackends": { - "description": "the number of healthy backend components", - "type": "integer", - "format": "int32" - }, - "label": { - "description": "labels", - "$ref": "#/definitions/models.ComponentStatus.label" - }, - "name": { - "description": "component name", - "type": "string" - }, - "namespace": { - "description": "the name of the namespace", - "type": "string" - }, - "selfLink": { - "description": "self link", - "type": "string" - }, - "startedAt": { - "description": "started time", - "type": "string", - "format": "date-time" - }, - "totalBackends": { - "description": "the total replicas of each backend system component", - "type": "integer", - "format": "int32" - } - } - }, - "models.ComponentStatus.label": {}, - "models.HealthStatus": { - "required": [ - "kubesphereStatus", - "kubernetesStatus", - "nodeStatus" - ], - "properties": { - "kubernetesStatus": { - "description": "kubernetes components status", - "type": "array", - "items": { - "$ref": "#/definitions/v1.ComponentStatus" - } - }, - "kubesphereStatus": { - "description": "kubesphere components status", - "type": "array", - "items": { - "$ref": "#/definitions/models.ComponentStatus" - } - }, - "nodeStatus": { - "description": "nodes status", - "$ref": "#/definitions/models.NodeStatus" - } - } - }, - "models.NodeStatus": { - "required": [ - "totalNodes", - "healthyNodes" - ], - "properties": { - "healthyNodes": { - "description": "the number of healthy nodes", - "type": "integer", - "format": "int32" - }, - "totalNodes": { - "description": "total number of nodes", - "type": "integer", - "format": "int32" - } - } - }, "models.PageableResponse": { "required": [ "items", @@ -15196,143 +11621,6 @@ } } }, - "models.ResourceQuota": { - "required": [ - "namespace", - "data" - ], - "properties": { - "data": { - "description": "resource quota status", - "$ref": "#/definitions/v1.ResourceQuotaStatus" - }, - "namespace": { - "description": "namespace", - "type": "string" - } - } - }, - "models.Rule": { - "required": [ - "name", - "actions" - ], - "properties": { - "actions": { - "type": "array", - "items": { - "$ref": "#/definitions/models.Action" - } - }, - "name": { - "type": "string" - } - } - }, - "models.SimpleRule": { - "required": [ - "name", - "actions" - ], - "properties": { - "actions": { - "description": "actions", - "type": "array", - "items": { - "type": "string" - } - }, - "name": { - "description": "rule name", - "type": "string" - } - } - }, - "models.Token": { - "required": [ - "access_token" - ], - "properties": { - "access_token": { - "description": "access token", - "type": "string" - } - } - }, - "models.User": { - "required": [ - "username", - "email", - "description", - "create_time", - "avatar_url", - "last_login_time", - "status", - "cluster_role" - ], - "properties": { - "avatar_url": { - "type": "string" - }, - "cluster_role": { - "type": "string" - }, - "create_time": { - "type": "string", - "format": "date-time" - }, - "current_password": { - "type": "string" - }, - "description": { - "type": "string" - }, - "email": { - "type": "string" - }, - "groups": { - "type": "array", - "items": { - "type": "string" - } - }, - "lang": { - "type": "string" - }, - "last_login_time": { - "type": "string" - }, - "password": { - "type": "string" - }, - "role": { - "type": "string" - }, - "role_bind_time": { - "type": "string", - "format": "date-time" - }, - "role_binding": { - "type": "string" - }, - "roles": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "status": { - "type": "integer", - "format": "int32" - }, - "username": { - "type": "string" - }, - "workspace_role": { - "type": "string" - } - } - }, "models.WorkloadStatus": { "required": [ "name", @@ -15353,6 +11641,91 @@ } } }, + "monitoring.Metric": { + "properties": { + "data": { + "description": "actual metric result", + "$ref": "#/definitions/monitoring.MetricData" + }, + "error": { + "type": "string" + }, + "metric_name": { + "description": "metric name, eg. scheduler_up_sum", + "type": "string" + } + } + }, + "monitoring.MetricData": { + "properties": { + "result": { + "description": "metric data including labels, time series and values", + "type": "array", + "items": { + "$ref": "#/definitions/monitoring.MetricValue" + } + }, + "resultType": { + "description": "result type, one of matrix, vector", + "type": "string" + } + } + }, + "monitoring.MetricValue": { + "properties": { + "metric": { + "description": "time series labels", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "value": { + "description": "time series, values of vector type", + "type": "array", + "items": { + "type": "number" + } + }, + "values": { + "description": "time series, values of matrix type", + "type": "array", + "items": { + "$ref": "#/definitions/monitoring.Point" + } + } + } + }, + "monitoring.Metrics": { + "required": [ + "results" + ], + "properties": { + "page": { + "description": "current page returned", + "type": "integer", + "format": "int32" + }, + "results": { + "description": "actual array of results", + "type": "array", + "items": { + "$ref": "#/definitions/monitoring.Metric" + } + }, + "total_item": { + "description": "page size", + "type": "integer", + "format": "int32" + }, + "total_page": { + "description": "total number of pages", + "type": "integer", + "format": "int32" + } + } + }, + "monitoring.Point": {}, "openpitrix.App": { "required": [ "category_set" @@ -16233,27 +12606,6 @@ } }, "prometheus.Metrics.histograms": {}, - "registries.AuthInfo": { - "required": [ - "username", - "password", - "serverhost" - ], - "properties": { - "password": { - "description": "password", - "type": "string" - }, - "serverhost": { - "description": "registry server host", - "type": "string" - }, - "username": { - "description": "username", - "type": "string" - } - } - }, "registries.Config": { "properties": { "ArgsEscaped": { @@ -16662,734 +13014,6 @@ } } }, - "sonargo.CeTaskObject": { - "properties": { - "task": { - "$ref": "#/definitions/sonargo.Task" - } - } - }, - "sonargo.Comment": { - "properties": { - "createdAt": { - "type": "string" - }, - "htmlText": { - "type": "string" - }, - "key": { - "type": "string" - }, - "login": { - "type": "string" - }, - "markdown": { - "type": "string" - }, - "updatable": { - "type": "boolean" - } - } - }, - "sonargo.Component": { - "properties": { - "analysisDate": { - "type": "string" - }, - "description": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "id": { - "type": "string" - }, - "key": { - "type": "string" - }, - "language": { - "type": "string" - }, - "lastAnalysisDate": { - "type": "string" - }, - "leakPeriodDate": { - "type": "string" - }, - "longName": { - "type": "string" - }, - "measures": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.SonarMeasure" - } - }, - "name": { - "type": "string" - }, - "organization": { - "type": "string" - }, - "path": { - "type": "string" - }, - "project": { - "type": "string" - }, - "qualifier": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "uuid": { - "type": "string" - }, - "version": { - "type": "string" - }, - "visibility": { - "type": "string" - } - } - }, - "sonargo.Facet": { - "properties": { - "name": { - "type": "string" - }, - "property": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.FacetValue" - } - } - } - }, - "sonargo.FacetValue": { - "properties": { - "count": { - "type": "integer", - "format": "int64" - }, - "val": { - "type": "string" - } - } - }, - "sonargo.History": { - "properties": { - "date": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "sonargo.Issue": { - "properties": { - "actions": { - "type": "array", - "items": { - "type": "string" - } - }, - "assignee": { - "type": "string" - }, - "author": { - "type": "string" - }, - "closeDate": { - "type": "string" - }, - "comments": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Comment" - } - }, - "component": { - "type": "string" - }, - "creationDate": { - "type": "string" - }, - "debt": { - "type": "string" - }, - "effort": { - "type": "string" - }, - "flows": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Issue.flows" - } - }, - "fromHotspot": { - "type": "boolean" - }, - "hash": { - "type": "string" - }, - "key": { - "type": "string" - }, - "line": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "organization": { - "type": "string" - }, - "project": { - "type": "string" - }, - "resolution": { - "type": "string" - }, - "rule": { - "type": "string" - }, - "severity": { - "type": "string" - }, - "status": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "textRange": { - "$ref": "#/definitions/sonargo.TextRange" - }, - "transitions": { - "type": "array", - "items": { - "type": "string" - } - }, - "type": { - "type": "string" - }, - "updateDate": { - "type": "string" - } - } - }, - "sonargo.Issue.flows": {}, - "sonargo.IssuesSearchObject": { - "properties": { - "components": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Component" - } - }, - "debtTotal": { - "type": "integer", - "format": "int32" - }, - "effortTotal": { - "type": "integer", - "format": "int32" - }, - "facets": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Facet" - } - }, - "issues": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Issue" - } - }, - "p": { - "type": "integer", - "format": "int32" - }, - "paging": { - "$ref": "#/definitions/sonargo.Paging" - }, - "ps": { - "type": "integer", - "format": "int32" - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Rule" - } - }, - "total": { - "type": "integer", - "format": "int32" - }, - "users": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.User" - } - } - } - }, - "sonargo.MeasuresComponentObject": { - "properties": { - "component": { - "$ref": "#/definitions/sonargo.Component" - }, - "metrics": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Metric" - } - }, - "periods": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Period" - } - } - } - }, - "sonargo.Metric": { - "required": [ - "Description", - "direction", - "Domain", - "Key", - "Name", - "Type" - ], - "properties": { - "Description": { - "type": "string" - }, - "Domain": { - "type": "string" - }, - "Key": { - "type": "string" - }, - "Name": { - "type": "string" - }, - "Type": { - "type": "string" - }, - "custom": { - "type": "boolean" - }, - "decimalScale": { - "type": "integer", - "format": "int32" - }, - "direction": { - "type": "integer", - "format": "int32" - }, - "hidden": { - "type": "boolean" - }, - "id": { - "type": "string" - }, - "qualitative": { - "type": "boolean" - } - } - }, - "sonargo.Paging": { - "properties": { - "pageIndex": { - "type": "integer", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "format": "int32" - }, - "total": { - "type": "integer", - "format": "int32" - } - } - }, - "sonargo.Period": { - "properties": { - "bestValue": { - "type": "boolean" - }, - "date": { - "type": "string" - }, - "index": { - "type": "integer", - "format": "int64" - }, - "mode": { - "type": "string" - }, - "parameter": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "sonargo.Rule": { - "properties": { - "createdAt": { - "type": "string" - }, - "debtOverloaded": { - "type": "boolean" - }, - "htmlDesc": { - "type": "string" - }, - "isExternal": { - "type": "boolean" - }, - "isTemplate": { - "type": "boolean" - }, - "key": { - "type": "string" - }, - "lang": { - "type": "string" - }, - "langName": { - "type": "string" - }, - "mdDesc": { - "type": "string" - }, - "name": { - "type": "string" - }, - "params": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.RuleParam" - } - }, - "remFnOverloaded": { - "type": "boolean" - }, - "repo": { - "type": "string" - }, - "scope": { - "type": "string" - }, - "severity": { - "type": "string" - }, - "status": { - "type": "string" - }, - "sysTags": { - "type": "array", - "items": { - "type": "string" - } - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "templateKey": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "sonargo.RuleParam": { - "properties": { - "defaultValue": { - "type": "string" - }, - "htmlDesc": { - "type": "string" - }, - "key": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "sonargo.SonarMeasure": { - "properties": { - "bestValue": { - "type": "boolean" - }, - "history": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.History" - } - }, - "metric": { - "type": "string" - }, - "periods": { - "type": "array", - "items": { - "$ref": "#/definitions/sonargo.Period" - } - }, - "value": { - "type": "string" - } - } - }, - "sonargo.Task": { - "properties": { - "analysisId": { - "type": "string" - }, - "componentId": { - "type": "string" - }, - "componentKey": { - "type": "string" - }, - "componentName": { - "type": "string" - }, - "componentQualifier": { - "type": "string" - }, - "errorMessage": { - "type": "string" - }, - "errorStacktrace": { - "type": "string" - }, - "errorType": { - "type": "string" - }, - "executedAt": { - "type": "string" - }, - "executionTimeMs": { - "type": "integer", - "format": "int64" - }, - "finishedAt": { - "type": "string" - }, - "hasErrorStacktrace": { - "type": "boolean" - }, - "hasScannerContext": { - "type": "boolean" - }, - "id": { - "type": "string" - }, - "logs": { - "type": "boolean" - }, - "organization": { - "type": "string" - }, - "scannerContext": { - "type": "string" - }, - "startedAt": { - "type": "string" - }, - "status": { - "type": "string" - }, - "submittedAt": { - "type": "string" - }, - "submitterLogin": { - "type": "string" - }, - "taskType": { - "type": "string" - }, - "type": { - "type": "string" - }, - "warningCount": { - "type": "integer", - "format": "int32" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "sonargo.TextRange": { - "properties": { - "endLine": { - "type": "integer", - "format": "int32" - }, - "endOffset": { - "type": "integer", - "format": "int32" - }, - "startLine": { - "type": "integer", - "format": "int32" - }, - "startOffset": { - "type": "integer", - "format": "int32" - } - } - }, - "sonargo.User": { - "properties": { - "active": { - "type": "boolean" - }, - "avatar": { - "type": "string" - }, - "email": { - "type": "string" - }, - "externalIdentity": { - "type": "string" - }, - "externalProvider": { - "type": "string" - }, - "groups": { - "type": "array", - "items": { - "type": "string" - } - }, - "local": { - "type": "boolean" - }, - "login": { - "type": "string" - }, - "name": { - "type": "string" - }, - "scmAccounts": { - "type": "array", - "items": { - "type": "string" - } - }, - "selected": { - "type": "boolean" - }, - "tokensCount": { - "type": "integer", - "format": "int32" - } - } - }, - "status.WorkLoadStatus": { - "required": [ - "namespace", - "data" - ], - "properties": { - "data": { - "description": "the number of unhealthy workloads", - "type": "object", - "additionalProperties": { - "type": "integer" - } - }, - "items": { - "description": "unhealthy workloads", - "type": "object" - }, - "namespace": { - "description": "the name of the namespace", - "type": "string" - } - } - }, - "struct { Count uint32 \"json:\\\"count\\\"\" }": { - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer" - } - } - }, - "struct { Items ||devops.BranchPipelineRun \"json:\\\"items\\\"\"; Total int \"json:\\\"total_count\\\"\" }": { - "required": [ - "items", - "total_count" - ], - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.BranchPipelineRun" - } - }, - "total_count": { - "type": "integer", - "format": "int32" - } - } - }, - "struct { Items ||devops.Pipeline \"json:\\\"items\\\"\"; Total int \"json:\\\"total_count\\\"\" }": { - "required": [ - "items", - "total_count" - ], - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/devops.Pipeline" - } - }, - "total_count": { - "type": "integer", - "format": "int32" - } - } - }, "v1.AWSElasticBlockStoreVolumeSource": { "description": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling.", "required": [ @@ -17432,18 +13056,6 @@ } } }, - "v1.AggregationRule": { - "description": "AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole", - "properties": { - "clusterRoleSelectors": { - "description": "ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. If any of the selectors match, then the ClusterRole's permissions will be added", - "type": "array", - "items": { - "$ref": "#/definitions/v1.LabelSelector" - } - } - } - }, "v1.AzureDataDiskCachingMode": {}, "v1.AzureDataDiskKind": {}, "v1.AzureDiskVolumeSource": { @@ -17500,6 +13112,37 @@ } } }, + "v1.CSIVolumeSource": { + "description": "Represents a source location of a volume to mount, managed by an external CSI driver", + "required": [ + "driver" + ], + "properties": { + "driver": { + "description": "Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.", + "type": "string" + }, + "fsType": { + "description": "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.", + "type": "string" + }, + "nodePublishSecretRef": { + "description": "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed.", + "$ref": "#/definitions/v1.LocalObjectReference" + }, + "readOnly": { + "description": "Specifies a read-only configuration for the volume. Defaults to false (read/write).", + "type": "boolean" + }, + "volumeAttributes": { + "description": "VolumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "v1.Capabilities": { "description": "Adds and removes POSIX capabilities from running containers.", "properties": { @@ -17527,7 +13170,7 @@ ], "properties": { "monitors": { - "description": "Required: Monitors is a collection of Ceph monitors More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it", + "description": "Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", "type": "array", "items": { "type": "string" @@ -17538,19 +13181,19 @@ "type": "string" }, "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", "type": "boolean" }, "secretFile": { - "description": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it", + "description": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", "type": "string" }, "secretRef": { - "description": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it", + "description": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", "$ref": "#/definitions/v1.LocalObjectReference" }, "user": { - "description": "Optional: User is the rados user name, default is admin More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it", + "description": "Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", "type": "string" } } @@ -17562,11 +13205,11 @@ ], "properties": { "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", "type": "string" }, "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", "type": "boolean" }, "secretRef": { @@ -17574,7 +13217,7 @@ "$ref": "#/definitions/v1.LocalObjectReference" }, "volumeID": { - "description": "volume id used to identify the volume in cinder More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "description": "volume id used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", "type": "string" } } @@ -17589,86 +13232,6 @@ } } }, - "v1.ClusterRole": { - "description": "ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding.", - "required": [ - "rules" - ], - "properties": { - "aggregationRule": { - "description": "AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller.", - "$ref": "#/definitions/v1.AggregationRule" - }, - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "description": "Standard object's metadata.", - "$ref": "#/definitions/v1.ObjectMeta" - }, - "rules": { - "description": "Rules holds all the PolicyRules for this ClusterRole", - "type": "array", - "items": { - "$ref": "#/definitions/v1.PolicyRule" - } - } - } - }, - "v1.ComponentCondition": { - "description": "Information about the condition of a component.", - "required": [ - "type", - "status" - ], - "properties": { - "error": { - "description": "Condition error code for a component. For example, a health check error code.", - "type": "string" - }, - "message": { - "description": "Message about the condition for a component. For example, information about a health check.", - "type": "string" - }, - "status": { - "description": "Status of the condition for a component. Valid values for \"Healthy\": \"True\", \"False\", or \"Unknown\".", - "type": "string" - }, - "type": { - "description": "Type of condition for a component. Valid value: \"Healthy\"", - "type": "string" - } - } - }, - "v1.ComponentStatus": { - "description": "ComponentStatus (and ComponentStatusList) holds the cluster validation info.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "conditions": { - "description": "List of component conditions observed", - "type": "array", - "items": { - "$ref": "#/definitions/v1.ComponentCondition" - } - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", - "$ref": "#/definitions/v1.ObjectMeta" - } - } - }, "v1.ConfigMapEnvSource": { "description": "ConfigMapEnvSource selects a ConfigMap to populate the environment variables with.\n\nThe contents of the target ConfigMap's Data field will represent the key-value pairs as environment variables.", "properties": { @@ -17697,7 +13260,7 @@ "type": "string" }, "optional": { - "description": "Specify whether the ConfigMap or it's key must be defined", + "description": "Specify whether the ConfigMap or its key must be defined", "type": "boolean" } } @@ -17717,7 +13280,7 @@ "type": "string" }, "optional": { - "description": "Specify whether the ConfigMap or it's keys must be defined", + "description": "Specify whether the ConfigMap or its keys must be defined", "type": "boolean" } } @@ -17742,7 +13305,7 @@ "type": "string" }, "optional": { - "description": "Specify whether the ConfigMap or it's keys must be defined", + "description": "Specify whether the ConfigMap or its keys must be defined", "type": "boolean" } } @@ -17820,6 +13383,10 @@ "description": "Security options the pod should run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/", "$ref": "#/definitions/v1.SecurityContext" }, + "startupProbe": { + "description": "StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. This is an alpha feature enabled by the StartupProbe feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", + "$ref": "#/definitions/v1.Probe" + }, "stdin": { "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.", "type": "boolean" @@ -17894,23 +13461,23 @@ "description": "DaemonSet represents the configuration of a daemon set.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.DaemonSetSpec" }, "status": { - "description": "The current status of this daemon set. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "The current status of this daemon set. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.DaemonSetStatus" } } @@ -18055,11 +13622,11 @@ "description": "Deployment enables declarative updates for Pods and ReplicaSets.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { @@ -18339,6 +13906,127 @@ } } }, + "v1.EphemeralContainer": { + "description": "An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.", + "required": [ + "name" + ], + "properties": { + "args": { + "description": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "List of environment variables to set in the container. Cannot be updated.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvVar" + } + }, + "envFrom": { + "description": "List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EnvFromSource" + } + }, + "image": { + "description": "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images", + "type": "string" + }, + "imagePullPolicy": { + "description": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", + "type": "string" + }, + "lifecycle": { + "description": "Lifecycle is not allowed for ephemeral containers.", + "$ref": "#/definitions/v1.Lifecycle" + }, + "livenessProbe": { + "description": "Probes are not allowed for ephemeral containers.", + "$ref": "#/definitions/v1.Probe" + }, + "name": { + "description": "Name of the ephemeral container specified as a DNS_LABEL. This name must be unique among all containers, init containers and ephemeral containers.", + "type": "string" + }, + "ports": { + "description": "Ports are not allowed for ephemeral containers.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ContainerPort" + } + }, + "readinessProbe": { + "description": "Probes are not allowed for ephemeral containers.", + "$ref": "#/definitions/v1.Probe" + }, + "resources": { + "description": "Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources already allocated to the pod.", + "$ref": "#/definitions/v1.ResourceRequirements" + }, + "securityContext": { + "description": "SecurityContext is not allowed for ephemeral containers.", + "$ref": "#/definitions/v1.SecurityContext" + }, + "startupProbe": { + "description": "Probes are not allowed for ephemeral containers.", + "$ref": "#/definitions/v1.Probe" + }, + "stdin": { + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.", + "type": "boolean" + }, + "stdinOnce": { + "description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false", + "type": "boolean" + }, + "targetContainerName": { + "description": "If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container is run in whatever namespaces are shared for the pod. Note that the container runtime must support this feature.", + "type": "string" + }, + "terminationMessagePath": { + "description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.", + "type": "string" + }, + "terminationMessagePolicy": { + "description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", + "type": "string" + }, + "tty": { + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.", + "type": "boolean" + }, + "volumeDevices": { + "description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeDevice" + } + }, + "volumeMounts": { + "description": "Pod volumes to mount into the container's filesystem. Cannot be updated.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.VolumeMount" + } + }, + "workingDir": { + "description": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.", + "type": "string" + } + } + }, "v1.ExecAction": { "description": "ExecAction describes a \"run in container\" action.", "properties": { @@ -18481,15 +14169,15 @@ ], "properties": { "endpoints": { - "description": "EndpointsName is the endpoint name that details Glusterfs topology. More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod", + "description": "EndpointsName is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", "type": "string" }, "path": { - "description": "Path is the Glusterfs volume path. More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod", + "description": "Path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", "type": "string" }, "readOnly": { - "description": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod", + "description": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", "type": "boolean" } } @@ -18592,6 +14280,7 @@ } } }, + "v1.IPFamily": {}, "v1.ISCSIVolumeSource": { "description": "Represents an ISCSI disk. ISCSI volumes can only be mounted as read/write once. ISCSI volumes support ownership management and SELinux relabeling.", "required": [ @@ -18650,37 +14339,6 @@ } } }, - "v1.Initializer": { - "description": "Initializer is information about an initializer that has not yet completed.", - "required": [ - "name" - ], - "properties": { - "name": { - "description": "name of the process that is responsible for initializing this object.", - "type": "string" - } - } - }, - "v1.Initializers": { - "description": "Initializers tracks the progress of initialization.", - "required": [ - "pending" - ], - "properties": { - "pending": { - "description": "Pending is a list of initializers that must execute in order before this object is visible. When the last pending initializer is removed, and no failing result is set, the initializers struct will be set to nil and the object is considered as initialized and visible to all clients.", - "type": "array", - "items": { - "$ref": "#/definitions/v1.Initializer" - } - }, - "result": { - "description": "If result is set with the Failure field, the object will be persisted to storage and then deleted, ensuring that other clients can observe the deletion.", - "$ref": "#/definitions/v1.Status" - } - } - }, "v1.KeyToPath": { "description": "Maps a string key to a path within a volume.", "required": [ @@ -18754,7 +14412,7 @@ "$ref": "#/definitions/v1.Handler" }, "preStop": { - "description": "PreStop is called immediately before a container is terminated. The container is terminated after the handler completes. The reason for termination is passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", + "description": "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The reason for termination is passed to the handler. The Pod's termination grace period countdown begins before the PreStop hooked is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period. Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks", "$ref": "#/definitions/v1.Handler" } } @@ -18766,12 +14424,17 @@ "description": "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", "type": "string" }, + "remainingItemCount": { + "description": "remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact.", + "type": "integer", + "format": "int64" + }, "resourceVersion": { - "description": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", + "description": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", "type": "string" }, "selfLink": { - "description": "selfLink is a URL representing this object. Populated by the system. Read-only.", + "description": "selfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", "type": "string" } } @@ -18810,6 +14473,35 @@ } } }, + "v1.ManagedFieldsEntry": { + "description": "ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource that the fieldset applies to.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the version of this resource that this field set applies to. The format is \"group/version\" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted.", + "type": "string" + }, + "fieldsType": { + "description": "FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: \"FieldsV1\"", + "type": "string" + }, + "fieldsV1": { + "description": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.", + "type": "string" + }, + "manager": { + "description": "Manager is an identifier of the workflow managing these fields.", + "type": "string" + }, + "operation": { + "description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'.", + "type": "string" + }, + "time": { + "description": "Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'", + "type": "string" + } + } + }, "v1.MountPropagationMode": {}, "v1.NFSVolumeSource": { "description": "Represents an NFS mount that lasts the lifetime of a pod. NFS volumes do not support ownership management or SELinux relabeling.", @@ -18836,27 +14528,53 @@ "description": "Namespace provides a scope for Names. Use of multiple namespaces is optional.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "Spec defines the behavior of the Namespace. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Spec defines the behavior of the Namespace. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.NamespaceSpec" }, "status": { - "description": "Status describes the current status of a Namespace. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Status describes the current status of a Namespace. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.NamespaceStatus" } } }, + "v1.NamespaceCondition": { + "description": "NamespaceCondition contains details about state of namespace.", + "required": [ + "type", + "status" + ], + "properties": { + "lastTransitionTime": { + "type": "string" + }, + "message": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "status": { + "description": "Status of the condition, one of True, False, Unknown.", + "type": "string" + }, + "type": { + "description": "Type of namespace controller condition.", + "type": "string" + } + } + }, "v1.NamespaceSpec": { "description": "NamespaceSpec describes the attributes on a Namespace.", "properties": { @@ -18872,6 +14590,13 @@ "v1.NamespaceStatus": { "description": "NamespaceStatus is information about the current status of a Namespace.", "properties": { + "conditions": { + "description": "Represents the latest available observations of a namespace's current state.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.NamespaceCondition" + } + }, "phase": { "description": "Phase is the current lifecycle phase of the namespace. More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/", "type": "string" @@ -18983,7 +14708,7 @@ "type": "string" }, "creationTimestamp": { - "description": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "type": "string" }, "deletionGracePeriodSeconds": { @@ -18992,7 +14717,7 @@ "format": "int64" }, "deletionTimestamp": { - "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "type": "string" }, "finalizers": { @@ -19003,7 +14728,7 @@ } }, "generateName": { - "description": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency", + "description": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", "type": "string" }, "generation": { @@ -19011,10 +14736,6 @@ "type": "integer", "format": "int64" }, - "initializers": { - "description": "An initializer is a controller which enforces some system invariant at object creation time. This field is a list of initializers that have not yet acted on this object. If nil or empty, this object has been completely initialized. Otherwise, the object is considered uninitialized and is hidden (in list/watch and get calls) from clients that haven't explicitly asked to observe uninitialized objects.\n\nWhen an object is created, the system will populate this list with the current set of initializers. Only privileged users may set or modify this list. Once it is empty, it may not be modified further by any user.", - "$ref": "#/definitions/v1.Initializers" - }, "labels": { "description": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels", "type": "object", @@ -19022,6 +14743,13 @@ "type": "string" } }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like \"ci-cd\". The set of fields is always in the version that the workflow used when modifying the object.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.ManagedFieldsEntry" + } + }, "name": { "description": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names", "type": "string" @@ -19038,11 +14766,11 @@ } }, "resourceVersion": { - "description": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", + "description": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", "type": "string" }, "selfLink": { - "description": "SelfLink is a URL representing this object. Populated by the system. Read-only.", + "description": "SelfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", "type": "string" }, "uid": { @@ -19073,7 +14801,7 @@ "type": "boolean" }, "kind": { - "description": "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "name": { @@ -19091,15 +14819,15 @@ "description": "PersistentVolumeClaim is a user's request for and claim to a persistent volume", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { @@ -19145,9 +14873,6 @@ }, "v1.PersistentVolumeClaimSpec": { "description": "PersistentVolumeClaimSpec describes the common attributes of storage devices and allows a Source for provider-specific attributes", - "required": [ - "dataSource" - ], "properties": { "accessModes": { "description": "AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1", @@ -19395,6 +15120,10 @@ "items": { "$ref": "#/definitions/v1.Sysctl" } + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "$ref": "#/definitions/v1.WindowsSecurityContextOptions" } } }, @@ -19433,9 +15162,16 @@ "type": "string" }, "enableServiceLinks": { - "description": "EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links.", + "description": "EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. Optional: Defaults to true.", "type": "boolean" }, + "ephemeralContainers": { + "description": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.EphemeralContainer" + } + }, "hostAliases": { "description": "HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. This is only valid for non-hostNetwork pods.", "type": "array", @@ -19467,7 +15203,7 @@ } }, "initContainers": { - "description": "List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, or Liveness probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/", + "description": "List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/", "type": "array", "items": { "$ref": "#/definitions/v1.Container" @@ -19484,6 +15220,17 @@ "type": "string" } }, + "overhead": { + "description": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/resource.Quantity" + } + }, + "preemptionPolicy": { + "description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is alpha-level and is only honored by servers that enable the NonPreemptingPriority feature.", + "$ref": "#/definitions/v1.PreemptionPolicy" + }, "priority": { "description": "The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority.", "type": "integer", @@ -19494,7 +15241,7 @@ "type": "string" }, "readinessGates": { - "description": "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://github.com/kubernetes/community/blob/master/keps/sig-network/0007-pod-ready%2B%2B.md", + "description": "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md", "type": "array", "items": { "$ref": "#/definitions/v1.PodReadinessGate" @@ -19505,7 +15252,7 @@ "type": "string" }, "runtimeClassName": { - "description": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://github.com/kubernetes/community/blob/master/keps/sig-node/0014-runtime-class.md This is an alpha feature and may change in the future.", + "description": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md This is a beta feature as of Kubernetes v1.14.", "type": "string" }, "schedulerName": { @@ -19544,6 +15291,13 @@ "$ref": "#/definitions/v1.Toleration" } }, + "topologySpreadConstraints": { + "description": "TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. This field is alpha-level and is only honored by clusters that enables the EvenPodsSpread feature. All topologySpreadConstraints are ANDed.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.TopologySpreadConstraint" + } + }, "volumes": { "description": "List of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes", "type": "array", @@ -19557,58 +15311,15 @@ "description": "PodTemplateSpec describes the data a pod should have when created from a template", "properties": { "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.PodSpec" } } }, - "v1.PolicyRule": { - "description": "PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to.", - "required": [ - "verbs" - ], - "properties": { - "apiGroups": { - "description": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.", - "type": "array", - "items": { - "type": "string" - } - }, - "nonResourceURLs": { - "description": "NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as \"pods\" or \"secrets\") or non-resource URL paths (such as \"/api\"), but not both.", - "type": "array", - "items": { - "type": "string" - } - }, - "resourceNames": { - "description": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.", - "type": "array", - "items": { - "type": "string" - } - }, - "resources": { - "description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources.", - "type": "array", - "items": { - "type": "string" - } - }, - "verbs": { - "description": "Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, "v1.PortworxVolumeSource": { "description": "PortworxVolumeSource represents a Portworx volume resource.", "required": [ @@ -19629,6 +15340,7 @@ } } }, + "v1.PreemptionPolicy": {}, "v1.PreferredSchedulingTerm": { "description": "An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).", "required": [ @@ -19674,7 +15386,7 @@ "format": "int32" }, "successThreshold": { - "description": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness. Minimum value is 1.", + "description": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.", "type": "integer", "format": "int32" }, @@ -19729,6 +15441,10 @@ "description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes", "type": "string" }, + "tenant": { + "description": "Tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin", + "type": "string" + }, "user": { "description": "User to map volume access to Defaults to serivceaccount user", "type": "string" @@ -19751,34 +15467,34 @@ "type": "string" }, "image": { - "description": "The rados image name. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "string" }, "keyring": { - "description": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "string" }, "monitors": { - "description": "A collection of Ceph monitors. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "A collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "array", "items": { "type": "string" } }, "pool": { - "description": "The rados pool name. Default is rbd. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "The rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "string" }, "readOnly": { - "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "boolean" }, "secretRef": { - "description": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "$ref": "#/definitions/v1.LocalObjectReference" }, "user": { - "description": "The rados user name. Default is admin. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it", + "description": "The rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", "type": "string" } } @@ -19787,23 +15503,23 @@ "description": "ReplicaSet ensures that a specified number of pod replicas are running at any given time.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "If the Labels of a ReplicaSet are empty, they are defaulted to be the same as the Pod(s) that the ReplicaSet manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "Spec defines the specification of the desired behavior of the ReplicaSet. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Spec defines the specification of the desired behavior of the ReplicaSet. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.ReplicaSetSpec" }, "status": { - "description": "Status is the most recently observed status of the ReplicaSet. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Status is the most recently observed status of the ReplicaSet. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.ReplicaSetStatus" } } @@ -19961,33 +15677,6 @@ } } }, - "v1.Role": { - "description": "Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding.", - "required": [ - "rules" - ], - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "description": "Standard object's metadata.", - "$ref": "#/definitions/v1.ObjectMeta" - }, - "rules": { - "description": "Rules holds all the PolicyRules for this Role", - "type": "array", - "items": { - "$ref": "#/definitions/v1.PolicyRule" - } - } - } - }, "v1.RollingUpdateDaemonSet": { "description": "Spec to control the desired behavior of daemon set rolling update.", "properties": { @@ -20119,7 +15808,7 @@ "type": "string" }, "optional": { - "description": "Specify whether the Secret or it's key must be defined", + "description": "Specify whether the Secret or its key must be defined", "type": "boolean" } } @@ -20173,7 +15862,7 @@ } }, "optional": { - "description": "Specify whether the Secret or it's keys must be defined", + "description": "Specify whether the Secret or its keys must be defined", "type": "boolean" }, "secretName": { @@ -20222,6 +15911,10 @@ "seLinuxOptions": { "description": "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", "$ref": "#/definitions/v1.SELinuxOptions" + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + "$ref": "#/definitions/v1.WindowsSecurityContextOptions" } } }, @@ -20229,23 +15922,23 @@ "description": "Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "Spec defines the behavior of a service. https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Spec defines the behavior of a service. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.ServiceSpec" }, "status": { - "description": "Most recently observed status of the service. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Most recently observed status of the service. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1.ServiceStatus" } } @@ -20271,33 +15964,6 @@ } } }, - "v1.ServiceList": { - "description": "ServiceList holds a list of services.", - "required": [ - "items" - ], - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "items": { - "description": "List of services", - "type": "array", - "items": { - "$ref": "#/definitions/v1.Service" - } - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "$ref": "#/definitions/v1.ListMeta" - } - } - }, "v1.ServicePort": { "description": "ServicePort contains information on service's port.", "required": [ @@ -20305,7 +15971,7 @@ ], "properties": { "name": { - "description": "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects. Optional if only one ServicePort is defined on this service.", + "description": "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. When considering the endpoints for a Service, this must match the 'name' field in the EndpointPort. Optional if only one ServicePort is defined on this service.", "type": "string" }, "nodePort": { @@ -20355,6 +16021,10 @@ "type": "integer", "format": "int32" }, + "ipFamily": { + "description": "ipFamily specifies whether this Service has a preference for a particular IP family (e.g. IPv4 vs. IPv6). If a specific IP family is requested, the clusterIP field will be allocated from that family, if it is available in the cluster. If no IP family is requested, the cluster's primary IP family will be used. Other IP fields (loadBalancerIP, loadBalancerSourceRanges, externalIPs) and controllers which allocate external load-balancers should use the same IP family. Endpoints for this Service will be of this family. This field is immutable after creation. Assigning a ServiceIPFamily not available in the cluster (e.g. IPv6 in IPv4 only cluster) is an error condition and will fail during clusterIP assignment.", + "$ref": "#/definitions/v1.IPFamily" + }, "loadBalancerIP": { "description": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.", "type": "string" @@ -20393,7 +16063,7 @@ "$ref": "#/definitions/v1.SessionAffinityConfig" }, "type": { - "description": "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ExternalName\" maps to the specified externalName. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a stable IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the clusterIP. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services ", + "description": "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ExternalName\" maps to the specified externalName. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a stable IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the clusterIP. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types", "type": "string" } } @@ -20420,11 +16090,11 @@ "description": "StatefulSet represents a set of pods with consistent identities. Identities are defined as:\n - Network: A single stable DNS and hostname.\n - Storage: As many VolumeClaims as requested.\nThe StatefulSet guarantees that a given network identity will always map to the same storage identity.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { @@ -20582,94 +16252,6 @@ } } }, - "v1.Status": { - "description": "Status is a return value for calls that don't return other objects.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "code": { - "description": "Suggested HTTP return code for this status, 0 if not set.", - "type": "integer", - "format": "int32" - }, - "details": { - "description": "Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.", - "$ref": "#/definitions/v1.StatusDetails" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "message": { - "description": "A human-readable description of the status of this operation.", - "type": "string" - }, - "metadata": { - "description": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "$ref": "#/definitions/v1.ListMeta" - }, - "reason": { - "description": "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.", - "type": "string" - }, - "status": { - "description": "Status of the operation. One of: \"Success\" or \"Failure\". More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", - "type": "string" - } - } - }, - "v1.StatusCause": { - "description": "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", - "properties": { - "field": { - "description": "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"", - "type": "string" - }, - "message": { - "description": "A human-readable description of the cause of the error. This field may be presented as-is to a reader.", - "type": "string" - }, - "reason": { - "description": "A machine-readable description of the cause of the error. If this value is empty there is no information available.", - "type": "string" - } - } - }, - "v1.StatusDetails": { - "description": "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", - "properties": { - "causes": { - "description": "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.", - "type": "array", - "items": { - "$ref": "#/definitions/v1.StatusCause" - } - }, - "group": { - "description": "The group attribute of the resource associated with the status StatusReason.", - "type": "string" - }, - "kind": { - "description": "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "name": { - "description": "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).", - "type": "string" - }, - "retryAfterSeconds": { - "description": "If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action.", - "type": "integer", - "format": "int32" - }, - "uid": { - "description": "UID of the resource. (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type": "string" - } - } - }, "v1.StorageOSVolumeSource": { "description": "Represents a StorageOS persistent volume resource.", "properties": { @@ -20754,6 +16336,33 @@ } } }, + "v1.TopologySpreadConstraint": { + "description": "TopologySpreadConstraint specifies how to spread matching pods among the given topology.", + "required": [ + "maxSkew", + "topologyKey", + "whenUnsatisfiable" + ], + "properties": { + "labelSelector": { + "description": "LabelSelector is used to find matching pods. Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain.", + "$ref": "#/definitions/v1.LabelSelector" + }, + "maxSkew": { + "description": "MaxSkew describes the degree to which pods may be unevenly distributed. It's the maximum permitted difference between the number of matching pods in any two topology domains of a given topology type. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 1/1/0: ", + "type": "integer", + "format": "int32" + }, + "topologyKey": { + "description": "TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each \u003ckey, value\u003e as a \"bucket\", and try to put balanced number of pods into each bucket. It's a required field.", + "type": "string" + }, + "whenUnsatisfiable": { + "description": "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it - ScheduleAnyway tells the scheduler to still schedule it It's considered as \"Unsatisfiable\" if and only if placing incoming pod on any topology violates \"MaxSkew\". For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: ", + "type": "string" + } + } + }, "v1.TypedLocalObjectReference": { "description": "TypedLocalObjectReference contains enough information to let you locate the typed referenced object inside the same namespace.", "required": [ @@ -20799,13 +16408,17 @@ "$ref": "#/definitions/v1.CephFSVolumeSource" }, "cinder": { - "description": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "description": "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", "$ref": "#/definitions/v1.CinderVolumeSource" }, "configMap": { "description": "ConfigMap represents a configMap that should populate this volume", "$ref": "#/definitions/v1.ConfigMapVolumeSource" }, + "csi": { + "description": "CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature).", + "$ref": "#/definitions/v1.CSIVolumeSource" + }, "downwardAPI": { "description": "DownwardAPI represents downward API about the pod that should populate this volume", "$ref": "#/definitions/v1.DownwardAPIVolumeSource" @@ -20835,7 +16448,7 @@ "$ref": "#/definitions/v1.GitRepoVolumeSource" }, "glusterfs": { - "description": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md", + "description": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md", "$ref": "#/definitions/v1.GlusterfsVolumeSource" }, "hostPath": { @@ -20843,7 +16456,7 @@ "$ref": "#/definitions/v1.HostPathVolumeSource" }, "iscsi": { - "description": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://releases.k8s.io/HEAD/examples/volumes/iscsi/README.md", + "description": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md", "$ref": "#/definitions/v1.ISCSIVolumeSource" }, "name": { @@ -20875,7 +16488,7 @@ "$ref": "#/definitions/v1.QuobyteVolumeSource" }, "rbd": { - "description": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md", + "description": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md", "$ref": "#/definitions/v1.RBDVolumeSource" }, "scaleIO": { @@ -20939,6 +16552,10 @@ "subPath": { "description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).", "type": "string" + }, + "subPathExpr": { + "description": "Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to \"\" (volume's root). SubPathExpr and SubPath are mutually exclusive. This field is beta in 1.15.", + "type": "string" } } }, @@ -21005,82 +16622,39 @@ } } }, - "v1alpha1.S2iBinary": { + "v1.WindowsSecurityContextOptions": { + "description": "WindowsSecurityContextOptions contain Windows-specific options and credentials.", "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "gmsaCredentialSpec": { + "description": "GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.", "type": "string" }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "gmsaCredentialSpecName": { + "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.", "type": "string" }, - "metadata": { - "$ref": "#/definitions/v1.ObjectMeta" - }, - "spec": { - "$ref": "#/definitions/v1alpha1.S2iBinarySpec" - }, - "status": { - "$ref": "#/definitions/v1alpha1.S2iBinaryStatus" - } - } - }, - "v1alpha1.S2iBinarySpec": { - "properties": { - "downloadURL": { - "type": "string" - }, - "fileName": { - "type": "string" - }, - "md5": { - "type": "string" - }, - "size": { - "type": "string" - }, - "uploadTimeStamp": { + "runAsUserName": { + "description": "The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is alpha-level and it is only honored by servers that enable the WindowsRunAsUserName feature flag.", "type": "string" } } }, - "v1alpha1.S2iBinaryStatus": { + "v1alpha2.APIResponse": { "properties": { - "phase": { - "type": "string" + "histogram": { + "description": "histogram results", + "$ref": "#/definitions/logging.Histogram" + }, + "query": { + "description": "query results", + "$ref": "#/definitions/logging.Logs" + }, + "statistics": { + "description": "statistics results", + "$ref": "#/definitions/logging.Statistics" } } }, - "v1alpha1.Workspace": { - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/v1.ObjectMeta" - }, - "spec": { - "$ref": "#/definitions/v1alpha1.WorkspaceSpec" - }, - "status": { - "$ref": "#/definitions/v1alpha1.WorkspaceStatus" - } - } - }, - "v1alpha1.WorkspaceSpec": { - "properties": { - "manager": { - "type": "string" - } - } - }, - "v1alpha1.WorkspaceStatus": {}, "v1alpha2.BadRequestError": { "required": [ "status", @@ -21096,158 +16670,52 @@ } } }, - "v1alpha2.ClusterRoleList": { + "v1alpha2.ComponentStatus": { "required": [ - "items", - "total_count" + "name", + "namespace", + "selfLink", + "label", + "startedAt", + "totalBackends", + "healthyBackends" ], "properties": { - "items": { - "description": "paging data", - "type": "array", - "items": { - "$ref": "#/definitions/v1.ClusterRole" - } + "healthyBackends": { + "description": "the number of healthy backend components", + "type": "integer", + "format": "int32" }, - "total_count": { - "description": "total count", + "label": { + "description": "labels", + "$ref": "#/definitions/v1alpha2.ComponentStatus.label" + }, + "name": { + "description": "component name", + "type": "string" + }, + "namespace": { + "description": "the name of the namespace", + "type": "string" + }, + "selfLink": { + "description": "self link", + "type": "string" + }, + "startedAt": { + "description": "started time", + "type": "string", + "format": "date-time" + }, + "totalBackends": { + "description": "the total replicas of each backend system component", "type": "integer", "format": "int32" } } }, - "v1alpha2.CreateUserRequest": { - "required": [ - "username", - "email", - "description", - "password", - "cluster_role" - ], - "properties": { - "cluster_role": { - "description": "user's cluster role", - "type": "string" - }, - "description": { - "description": "user's description", - "type": "string" - }, - "email": { - "description": "email address", - "type": "string" - }, - "lang": { - "description": "user's language setting, default is zh-CN", - "type": "string" - }, - "password": { - "description": "password'", - "type": "string" - }, - "username": { - "description": "username", - "type": "string" - } - } - }, - "v1alpha2.DescribeWorkspaceUserResponse": { - "required": [ - "username", - "email", - "lang", - "description", - "cluster_role", - "workspace_role", - "create_time", - "last_login_time" - ], - "properties": { - "cluster_role": { - "description": "user's cluster role", - "type": "string" - }, - "create_time": { - "description": "user creation time", - "type": "string", - "format": "date-time" - }, - "description": { - "description": "user's description", - "type": "string" - }, - "email": { - "description": "email address", - "type": "string" - }, - "lang": { - "description": "user's language setting, default is zh-CN", - "type": "string" - }, - "last_login_time": { - "description": "last login time", - "type": "string", - "format": "date-time" - }, - "username": { - "description": "username", - "type": "string" - }, - "workspace_role": { - "description": "user's workspace role", - "type": "string" - } - } - }, - "v1alpha2.DevOpsProject": { - "required": [ - "project_id", - "name", - "creator", - "create_time", - "status", - "workspace" - ], - "properties": { - "create_time": { - "description": "DevOps Project's Creation time", - "type": "string", - "format": "date-time" - }, - "creator": { - "description": "Creator's username", - "type": "string" - }, - "description": { - "description": "DevOps Projects's Description, used to describe the DevOps Project", - "type": "string" - }, - "extra": { - "description": "Internal Use", - "type": "string" - }, - "name": { - "description": "DevOps Projects's Name", - "type": "string" - }, - "project_id": { - "description": "ProjectId must be unique within a workspace, it is generated by kubesphere.", - "type": "string" - }, - "status": { - "description": "DevOps project's status. e.g. active", - "type": "string" - }, - "visibility": { - "description": "Deprecated Field", - "type": "string" - }, - "workspace": { - "description": "The workspace to which the devops project belongs", - "type": "string" - } - } - }, + "v1alpha2.ComponentStatus.label": {}, + "v1alpha2.FinalizerName": {}, "v1alpha2.GraphResponse": { "required": [ "timestamp", @@ -21272,198 +16740,22 @@ } } }, - "v1alpha2.HighLight": { - "properties": { - "kubernetes.container_name.keyword": { - "description": "containers to highlight", - "type": "array", - "items": { - "type": "string" - } - }, - "kubernetes.namespace_name.keyword": { - "description": "namespaces to highlight", - "type": "array", - "items": { - "type": "string" - } - }, - "kubernetes.pod_name.keyword": { - "description": "pods to highlight", - "type": "array", - "items": { - "type": "string" - } - }, - "log": { - "description": "log messages to highlight", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "v1alpha2.HistogramRecord": { + "v1alpha2.HealthStatus": { "required": [ - "time", - "count" + "kubesphereStatus", + "nodeStatus" ], "properties": { - "count": { - "description": "total number of logs at intervals", - "type": "integer", - "format": "int64" - }, - "time": { - "description": "timestamp", - "type": "integer", - "format": "int64" - } - } - }, - "v1alpha2.HistogramResult": { - "required": [ - "total", - "histograms" - ], - "properties": { - "histograms": { - "description": "actual array of histogram results", + "kubesphereStatus": { + "description": "kubesphere components status", "type": "array", "items": { - "$ref": "#/definitions/v1alpha2.HistogramRecord" + "$ref": "#/definitions/v1alpha2.ComponentStatus" } }, - "total": { - "description": "total number of logs", - "type": "integer", - "format": "int64" - } - } - }, - "v1alpha2.Hit": { - "required": [ - "_source", - "highlight", - "sort" - ], - "properties": { - "_source": { - "$ref": "#/definitions/v1alpha2.Source" - }, - "highlight": { - "$ref": "#/definitions/v1alpha2.HighLight" - }, - "sort": { - "type": "array", - "items": { - "type": "integer" - } - } - } - }, - "v1alpha2.Hits": { - "required": [ - "total", - "hits" - ], - "properties": { - "hits": { - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.Hit" - } - }, - "total": { - "$ref": "#/definitions/v1alpha2.Hits.total" - } - } - }, - "v1alpha2.Hits.total": {}, - "v1alpha2.InviteUserRequest": { - "required": [ - "username", - "workspace_role" - ], - "properties": { - "username": { - "description": "username", - "type": "string" - }, - "workspace_role": { - "description": "user's workspace role'", - "type": "string" - } - } - }, - "v1alpha2.Kubernetes": { - "required": [ - "namespace_name", - "pod_name", - "container_name", - "host" - ], - "properties": { - "container_name": { - "type": "string" - }, - "host": { - "type": "string" - }, - "namespace_name": { - "type": "string" - }, - "pod_name": { - "type": "string" - } - } - }, - "v1alpha2.LogRecord": { - "properties": { - "container": { - "description": "container name", - "type": "string" - }, - "highlight": { - "description": "highlighted log fragment", - "$ref": "#/definitions/v1alpha2.HighLight" - }, - "host": { - "description": "node id", - "type": "string" - }, - "log": { - "description": "log message", - "type": "string" - }, - "namespace": { - "description": "namespace", - "type": "string" - }, - "pod": { - "description": "pod name", - "type": "string" - }, - "time": { - "description": "log timestamp", - "type": "string" - } - } - }, - "v1alpha2.LoginLog": { - "required": [ - "login_time", - "login_ip" - ], - "properties": { - "login_ip": { - "description": "last login ip", - "type": "string" - }, - "login_time": { - "description": "last login time", - "type": "string" + "nodeStatus": { + "description": "nodes status", + "$ref": "#/definitions/v1alpha2.NodeStatus" } } }, @@ -21487,55 +16779,21 @@ } } }, - "v1alpha2.NamespacedUser": { + "v1alpha2.NodeStatus": { "required": [ - "username", - "email", - "description", - "role", - "role_binding", - "role_bind_time", - "create_time", - "last_login_time" + "totalNodes", + "healthyNodes" ], "properties": { - "create_time": { - "description": "user creation time", - "type": "string", - "format": "date-time" + "healthyNodes": { + "description": "the number of healthy nodes", + "type": "integer", + "format": "int32" }, - "description": { - "description": "user's description", - "type": "string" - }, - "email": { - "description": "email address", - "type": "string" - }, - "lang": { - "description": "user's language setting, default is zh-CN", - "type": "string" - }, - "last_login_time": { - "description": "last login time", - "type": "string", - "format": "date-time" - }, - "role": { - "description": "user's role in the specified namespace", - "type": "string" - }, - "role_bind_time": { - "description": "user's role binding time", - "type": "string" - }, - "role_binding": { - "description": "user's role binding name in the specified namespace", - "type": "string" - }, - "username": { - "description": "username", - "type": "string" + "totalNodes": { + "description": "total number of nodes", + "type": "integer", + "format": "int32" } } }, @@ -21554,275 +16812,195 @@ } } }, - "v1alpha2.QueryResult": { + "v1alpha2.Role": { "required": [ - "resultType", - "result" + "target", + "rules" ], "properties": { - "result": { - "description": "metric data including labels, time series and values", - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.QueryValue" - } - }, - "resultType": { - "description": "result type, one of matrix, vector", - "type": "string" - } - } - }, - "v1alpha2.QueryValue": { - "properties": { - "metric": { - "description": "time series labels", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "value": { - "description": "time series, values of vector type", - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.QueryValue.value" - } - }, - "values": { - "description": "time series, values of matrix type", - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.QueryValue.values" - } - } - } - }, - "v1alpha2.QueryValue.value": {}, - "v1alpha2.QueryValue.values": {}, - "v1alpha2.ReadResult": { - "required": [ - "total" - ], - "properties": { - "_scroll_id": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, - "records": { - "description": "actual array of results", + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/v1.ObjectMeta" + }, + "rules": { "type": "array", "items": { - "$ref": "#/definitions/v1alpha2.LogRecord" + "$ref": "#/definitions/v1alpha2.RuleRef" } }, - "total": { - "description": "total number of matched results", - "type": "integer", - "format": "int64" - } - } - }, - "v1alpha2.Response": { - "required": [ - "_scroll_id", - "_shards", - "hits", - "aggregations" - ], - "properties": { - "_scroll_id": { - "type": "string" - }, - "_shards": { - "$ref": "#/definitions/v1alpha2.Shards" - }, - "aggregations": { - "type": "string" - }, - "hits": { - "$ref": "#/definitions/v1alpha2.Hits" + "target": { + "$ref": "#/definitions/v1alpha2.Target" } } }, "v1alpha2.RoleList": { "required": [ - "items", - "total_count" + "items" ], "properties": { - "items": { - "description": "paging data", - "type": "array", - "items": { - "$ref": "#/definitions/v1.Role" - } - }, - "total_count": { - "description": "total count", - "type": "integer", - "format": "int32" - } - } - }, - "v1alpha2.Shards": { - "required": [ - "total", - "successful", - "skipped", - "failed" - ], - "properties": { - "failed": { - "type": "integer", - "format": "int64" - }, - "skipped": { - "type": "integer", - "format": "int64" - }, - "successful": { - "type": "integer", - "format": "int64" - }, - "total": { - "type": "integer", - "format": "int64" - } - } - }, - "v1alpha2.Source": { - "required": [ - "log", - "time", - "kubernetes" - ], - "properties": { - "kubernetes": { - "$ref": "#/definitions/v1alpha2.Kubernetes" - }, - "log": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, - "time": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha2.Role" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/v1.ListMeta" + } + } + }, + "v1alpha2.RuleRef": { + "required": [ + "apiGroup", + "kind", + "name" + ], + "properties": { + "apiGroup": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { "type": "string" } } }, - "v1alpha2.StatisticsResult": { + "v1alpha2.Target": { "required": [ - "containers", - "logs" + "scope", + "name" ], "properties": { - "containers": { - "description": "total number of containers", - "type": "integer", - "format": "int64" + "name": { + "type": "string" }, - "logs": { - "description": "total number of logs", - "type": "integer", - "format": "int64" + "scope": { + "type": "string" } } }, - "v1alpha2.UserList": { + "v1alpha2.User": { "required": [ - "items", - "total_count" + "spec" ], "properties": { - "items": { - "description": "paging data", - "type": "array", - "items": { - "$ref": "#/definitions/v1alpha2.UserList.items" - } + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" }, - "total_count": { - "description": "total count", - "type": "integer", - "format": "int32" + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/v1.ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/v1alpha2.UserSpec" + }, + "status": { + "$ref": "#/definitions/v1alpha2.UserStatus" } } }, - "v1alpha2.UserList.items": { + "v1alpha2.UserCondition": { + "required": [ + "type", + "status" + ], + "properties": { + "lastTransitionTime": { + "type": "string" + }, + "message": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "v1alpha2.UserDetail": { + "required": [ + "User", + "globalRole" + ], + "properties": { + "User": { + "$ref": "#/definitions/v1alpha2.User" + }, + "globalRole": { + "$ref": "#/definitions/v1alpha2.Role" + } + } + }, + "v1alpha2.UserSpec": { "required": [ - "username", "email", - "description", - "cluster_role", - "create_time", - "last_login_time" + "password" ], "properties": { - "cluster_role": { - "description": "user's cluster role", + "description": { "type": "string" }, - "create_time": { - "description": "user creation time", - "type": "string", - "format": "date-time" - }, - "description": { - "description": "user's description", + "displayName": { "type": "string" }, "email": { - "description": "email address", "type": "string" }, + "finalizers": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha2.FinalizerName" + } + }, + "groups": { + "type": "array", + "items": { + "type": "string" + } + }, "lang": { - "description": "user's language setting, default is zh-CN", - "type": "string" - }, - "last_login_time": { - "description": "last login time", - "type": "string", - "format": "date-time" - }, - "username": { - "description": "username", - "type": "string" - } - } - }, - "v1alpha2.UserUpdateRequest": { - "required": [ - "username", - "email", - "lang", - "description", - "cluster_role" - ], - "properties": { - "cluster_role": { - "description": "user's cluster role", - "type": "string" - }, - "current_password": { - "description": "this is necessary if you need to change your password", - "type": "string" - }, - "description": { - "description": "user's description", - "type": "string" - }, - "email": { - "description": "email address", - "type": "string" - }, - "lang": { - "description": "user's language setting, default is zh-CN", "type": "string" }, "password": { - "description": "this is necessary if you need to change your password", "type": "string" + } + } + }, + "v1alpha2.UserStatus": { + "properties": { + "conditions": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha2.UserCondition" + } }, - "username": { - "description": "username", + "state": { "type": "string" } } @@ -21913,26 +17091,26 @@ } }, "v1beta1.Ingress": { - "description": "Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc.", + "description": "Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. DEPRECATED - This group version of Ingress is deprecated by networking.k8s.io/v1beta1 Ingress. See the release notes for more information.", "properties": { "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", "type": "string" }, "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", "type": "string" }, "metadata": { - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", "$ref": "#/definitions/v1.ObjectMeta" }, "spec": { - "description": "Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1beta1.IngressSpec" }, "status": { - "description": "Status is the current state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "description": "Status is the current state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", "$ref": "#/definitions/v1beta1.IngressStatus" } } diff --git a/go.mod b/go.mod index 4a41dfc01..6e221460f 100644 --- a/go.mod +++ b/go.mod @@ -33,8 +33,10 @@ require ( github.com/go-logr/logr v0.1.0 github.com/go-logr/zapr v0.1.1 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect + github.com/go-openapi/loads v0.19.2 github.com/go-openapi/spec v0.19.3 github.com/go-openapi/strfmt v0.19.0 + github.com/go-openapi/validate v0.19.2 github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.1 diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 78f829e71..329ee286a 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -24,7 +24,6 @@ import ( "kubesphere.io/kubesphere/pkg/apiserver/dispatch" "kubesphere.io/kubesphere/pkg/apiserver/filters" "kubesphere.io/kubesphere/pkg/apiserver/request" - ksruntime "kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/informers" configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2" devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2" @@ -150,11 +149,7 @@ func (s *APIServer) installKubeSphereAPIs() { s.Config.AuthenticationOptions)) urlruntime.Must(oauth.AddToContainer(s.container, token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient), s.Config.AuthenticationOptions)) urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container)) - devopsv1alpha2Service := ksruntime.NewWebService(devopsv1alpha2.GroupVersion) - urlruntime.Must(devopsv1alpha2.AddPipelineToWebService(devopsv1alpha2Service, s.DevopsClient)) - urlruntime.Must(devopsv1alpha2.AddS2IToWebService(devopsv1alpha2Service, s.KubernetesClient.KubeSphere(), s.InformerFactory.KubeSphereSharedInformerFactory(), s.S3Client)) - urlruntime.Must(devopsv1alpha2.AddSonarToWebService(devopsv1alpha2Service, s.DevopsClient, s.SonarClient)) - s.container.Add(devopsv1alpha2Service) + urlruntime.Must(devopsv1alpha2.AddToContainer(s.container, s.InformerFactory.KubeSphereSharedInformerFactory(), s.DevopsClient, s.SonarClient, s.KubernetesClient.KubeSphere(), s.S3Client)) } func (s *APIServer) Run(stopCh <-chan struct{}) (err error) { diff --git a/pkg/informers/null_informers.go b/pkg/informers/null_informers.go new file mode 100644 index 000000000..b6957584c --- /dev/null +++ b/pkg/informers/null_informers.go @@ -0,0 +1,34 @@ +package informers + +import ( + appinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions" + istioinformers "istio.io/client-go/pkg/informers/externalversions" + "k8s.io/client-go/informers" + ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" +) + +type nullInformerFactory struct { +} + +func NewNullInformerFactory() InformerFactory { + return &nullInformerFactory{} +} + +func (n nullInformerFactory) KubernetesSharedInformerFactory() informers.SharedInformerFactory { + return nil +} + +func (n nullInformerFactory) KubeSphereSharedInformerFactory() ksinformers.SharedInformerFactory { + return nil +} + +func (n nullInformerFactory) IstioSharedInformerFactory() istioinformers.SharedInformerFactory { + return nil +} + +func (n nullInformerFactory) ApplicationSharedInformerFactory() appinformers.SharedInformerFactory { + return nil +} + +func (n nullInformerFactory) Start(stopCh <-chan struct{}) { +} diff --git a/pkg/kapis/devops/v1alpha2/register.go b/pkg/kapis/devops/v1alpha2/register.go index c3a4bd955..f2c7fdb98 100644 --- a/pkg/kapis/devops/v1alpha2/register.go +++ b/pkg/kapis/devops/v1alpha2/register.go @@ -23,6 +23,7 @@ import ( "github.com/emicklei/go-restful-openapi" "k8s.io/apimachinery/pkg/runtime/schema" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/client/informers/externalversions" "kubesphere.io/kubesphere/pkg/constants" @@ -42,6 +43,29 @@ const ( var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"} +func AddToContainer(container *restful.Container, ksInformers externalversions.SharedInformerFactory, devopsClient devops.Interface, sonarqubeClient sonarqube.SonarInterface, ksClient versioned.Interface, s3Client s3.Interface) error { + ws := runtime.NewWebService(GroupVersion) + + err := AddPipelineToWebService(ws, devopsClient) + if err != nil { + return err + } + + err = AddSonarToWebService(ws, devopsClient, sonarqubeClient) + if err != nil { + return err + } + + err = AddS2IToWebService(ws, ksClient, ksInformers, s3Client) + if err != nil { + return err + } + + container.Add(ws) + + return nil +} + func AddPipelineToWebService(webservice *restful.WebService, devopsClient devops.Interface) error { projectPipelineEnable := devopsClient != nil diff --git a/pkg/simple/client/k8s/null_client.go b/pkg/simple/client/k8s/null_client.go new file mode 100644 index 000000000..69dee0f48 --- /dev/null +++ b/pkg/simple/client/k8s/null_client.go @@ -0,0 +1,45 @@ +package k8s + +import ( + application "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned" + istio "istio.io/client-go/pkg/clientset/versioned" + "k8s.io/client-go/discovery" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" +) + +type nullClient struct { +} + +func NewNullClient() Client { + return &nullClient{} +} + +func (n nullClient) Kubernetes() kubernetes.Interface { + return nil +} + +func (n nullClient) KubeSphere() kubesphere.Interface { + return nil +} + +func (n nullClient) Istio() istio.Interface { + return nil +} + +func (n nullClient) Application() application.Interface { + return nil +} + +func (n nullClient) Discovery() discovery.DiscoveryInterface { + return nil +} + +func (n nullClient) Master() string { + return "" +} + +func (n nullClient) Config() *rest.Config { + return nil +} diff --git a/pkg/version/version.go b/pkg/version/version.go index 27a2d5882..6df6f0acf 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -17,3 +17,5 @@ */ package version + +var Version = "v0.0.0" diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index a10d8f8a9..6035b014c 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -24,13 +24,18 @@ import ( "fmt" "github.com/emicklei/go-restful" "github.com/emicklei/go-restful-openapi" + "github.com/go-openapi/loads" "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + "github.com/pkg/errors" "io/ioutil" urlruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/klog" + authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options" "kubesphere.io/kubesphere/pkg/apiserver/runtime" - fakeksClient "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" - "kubesphere.io/kubesphere/pkg/client/informers/externalversions" "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2" iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2" loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2" @@ -42,12 +47,13 @@ import ( metricsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2" terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2" + "kubesphere.io/kubesphere/pkg/models/iam/am" + "kubesphere.io/kubesphere/pkg/models/iam/im" "kubesphere.io/kubesphere/pkg/simple/client/devops/fake" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" + "kubesphere.io/kubesphere/pkg/simple/client/k8s" fakes3 "kubesphere.io/kubesphere/pkg/simple/client/s3/fake" - "kubesphere.io/kubesphere/pkg/simple/client/sonarqube" + "kubesphere.io/kubesphere/pkg/version" "log" - "time" ) var output string @@ -58,27 +64,63 @@ func init() { func main() { flag.Parse() - generateSwaggerJson() + swaggerSpec := generateSwaggerJson() + + err := validateSpec(swaggerSpec) + if err != nil { + klog.Warningf("Swagger specification has errors") + } } -func generateSwaggerJson() { +func validateSpec(apiSpec []byte) error { + + swaggerDoc, err := loads.Analyzed(apiSpec, "") + if err != nil { + return err + } + + // Attempts to report about all errors + validate.SetContinueOnErrors(true) + + v := validate.NewSpecValidator(swaggerDoc.Schema(), strfmt.Default) + result, _ := v.Validate(swaggerDoc) + + if result.HasWarnings() { + log.Printf("See warnings below:\n") + for _, desc := range result.Warnings { + log.Printf("- WARNING: %s\n", desc.Error()) + } + + } + if result.HasErrors() { + str := fmt.Sprintf("The swagger spec is invalid against swagger specification %s.\nSee errors below:\n", swaggerDoc.Version()) + for _, desc := range result.Errors { + str += fmt.Sprintf("- %s\n", desc.Error()) + } + log.Println(str) + return errors.New(str) + } + + return nil +} + +func generateSwaggerJson() []byte { container := runtime.Container - devopsv1alpha2Service := runtime.NewWebService(devopsv1alpha2.GroupVersion) - urlruntime.Must(devopsv1alpha2.AddPipelineToWebService(devopsv1alpha2Service, &fake.Devops{}, &mysql.Database{})) - urlruntime.Must(devopsv1alpha2.AddS2IToWebService(devopsv1alpha2Service, fakeksClient.NewSimpleClientset(), externalversions.NewSharedInformerFactory( - fakeksClient.NewSimpleClientset(), time.Duration(0)), fakes3.NewFakeS3())) - urlruntime.Must(devopsv1alpha2.AddSonarToWebService(devopsv1alpha2Service, &fake.Devops{}, &mysql.Database{}, sonarqube.NewSonar(nil))) - container.Add(devopsv1alpha2Service) - urlruntime.Must(iamv1alpha2.AddToContainer(container, nil, nil, nil, nil, nil)) - urlruntime.Must(loggingv1alpha2.AddToContainer(container, nil, nil)) - urlruntime.Must(monitoringv1alpha3.AddToContainer(container, nil, nil)) - urlruntime.Must(openpitrixv1.AddToContainer(container, nil, nil)) - urlruntime.Must(operationsv1alpha2.AddToContainer(container, nil)) - urlruntime.Must(resourcesv1alpha2.AddToContainer(container, nil, nil)) - urlruntime.Must(resourcesv1alpha3.AddToContainer(container, nil)) - urlruntime.Must(tenantv1alpha2.AddToContainer(container, nil, nil, nil)) - urlruntime.Must(terminalv1alpha2.AddToContainer(container, nil, nil)) + clientsets := k8s.NewNullClient() + + informerFactory := informers.NewNullInformerFactory() + + urlruntime.Must(devopsv1alpha2.AddToContainer(container, informerFactory.KubeSphereSharedInformerFactory(), &fake.Devops{}, nil, clientsets.KubeSphere(), fakes3.NewFakeS3())) + urlruntime.Must(iamv1alpha2.AddToContainer(container, im.NewOperator(clientsets.KubeSphere(), informerFactory.KubeSphereSharedInformerFactory()), am.NewAMOperator(clientsets.KubeSphere(), informerFactory.KubeSphereSharedInformerFactory()), authoptions.NewAuthenticateOptions())) + urlruntime.Must(loggingv1alpha2.AddToContainer(container, clientsets, nil)) + urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil)) + urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, nil)) + urlruntime.Must(operationsv1alpha2.AddToContainer(container, clientsets.Kubernetes())) + urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory)) + urlruntime.Must(resourcesv1alpha3.AddToContainer(container, informerFactory)) + urlruntime.Must(tenantv1alpha2.AddToContainer(container, clientsets, informerFactory)) + urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil)) urlruntime.Must(metricsv1alpha2.AddToContainer(container)) config := restfulspec.Config{ @@ -125,7 +167,7 @@ func generateSwaggerJson() { }, { Name: "Logging", - Tags: []string{constants.LogQueryTag, constants.FluentBitSetting}, + Tags: []string{constants.LogQueryTag}, }, }) @@ -135,6 +177,8 @@ func generateSwaggerJson() { log.Fatal(err) } log.Printf("successfully written to %s", output) + + return data } func enrichSwaggerObject(swo *spec.Swagger) { @@ -151,7 +195,7 @@ func enrichSwaggerObject(swo *spec.Swagger) { Name: "Apache", URL: "http://www.apache.org/licenses/", }, - Version: "2.0.2", + Version: version.Version, }, } diff --git a/vendor/github.com/go-openapi/analysis/.gitignore b/vendor/github.com/go-openapi/analysis/.gitignore new file mode 100644 index 000000000..87c3bd3e6 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/.gitignore @@ -0,0 +1,5 @@ +secrets.yml +coverage.out +coverage.txt +*.cov +.idea diff --git a/vendor/github.com/go-openapi/analysis/.golangci.yml b/vendor/github.com/go-openapi/analysis/.golangci.yml new file mode 100644 index 000000000..212c13bf9 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/.golangci.yml @@ -0,0 +1,21 @@ +linters-settings: + govet: + check-shadowing: true + golint: + min-confidence: 0 + gocyclo: + min-complexity: 30 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 4 + +linters: + enable-all: true + disable: + - maligned + - gochecknoglobals + - gochecknoinits diff --git a/vendor/github.com/go-openapi/analysis/.travis.yml b/vendor/github.com/go-openapi/analysis/.travis.yml new file mode 100644 index 000000000..7ecf865c2 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/.travis.yml @@ -0,0 +1,15 @@ +after_success: +- bash <(curl -s https://codecov.io/bash) +go: +- 1.11.x +- 1.12.x +install: +- GO111MODULE=off go get -u gotest.tools/gotestsum +env: +- GO111MODULE=on +language: go +notifications: + slack: + secure: Sf7kZf7ZGbnwWUMpffHwMu5A0cHkLK2MYY32LNTPj4+/3qC3Ghl7+9v4TSLOqOlCwdRNjOGblAq7s+GDJed6/xgRQl1JtCi1klzZNrYX4q01pgTPvvGcwbBkIYgeMaPeIRcK9OZnud7sRXdttozgTOpytps2U6Js32ip7uj5mHSg2ub0FwoSJwlS6dbezZ8+eDhoha0F/guY99BEwx8Bd+zROrT2TFGsSGOFGN6wFc7moCqTHO/YkWib13a2QNXqOxCCVBy/lt76Wp+JkeFppjHlzs/2lP3EAk13RIUAaesdEUHvIHrzCyNJEd3/+KO2DzsWOYfpktd+KBCvgaYOsoo7ubdT3IROeAegZdCgo/6xgCEsmFc9ZcqCfN5yNx2A+BZ2Vwmpws+bQ1E1+B5HDzzaiLcYfG4X2O210QVGVDLWsv1jqD+uPYeHY2WRfh5ZsIUFvaqgUEnwHwrK44/8REAhQavt1QAj5uJpsRd7CkRVPWRNK+yIky+wgbVUFEchRNmS55E7QWf+W4+4QZkQi7vUTMc9nbTUu2Es9NfvfudOpM2wZbn98fjpb/qq/nRv6Bk+ca+7XD5/IgNLMbWp2ouDdzbiHLCOfDUiHiDJhLfFZx9Bwo7ZwfzeOlbrQX66bx7xRKYmOe4DLrXhNcpbsMa8qbfxlZRCmYbubB/Y8h4= +script: +- gotestsum -f short-verbose -- -race -timeout=20m -coverprofile=coverage.txt -covermode=atomic ./... diff --git a/vendor/github.com/go-openapi/analysis/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/analysis/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/analysis/LICENSE b/vendor/github.com/go-openapi/analysis/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/vendor/github.com/go-openapi/analysis/README.md b/vendor/github.com/go-openapi/analysis/README.md new file mode 100644 index 000000000..3724bfc48 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/README.md @@ -0,0 +1,9 @@ +# OpenAPI initiative analysis [![Build Status](https://travis-ci.org/go-openapi/analysis.svg?branch=master)](https://travis-ci.org/go-openapi/analysis) [![codecov](https://codecov.io/gh/go-openapi/analysis/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/analysis) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/analysis/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/go-openapi/analysis?status.svg)](http://godoc.org/github.com/go-openapi/analysis) +[![GolangCI](https://golangci.com/badges/github.com/go-openapi/analysis.svg)](https://golangci.com) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/analysis)](https://goreportcard.com/report/github.com/go-openapi/analysis) + + +A foundational library to analyze an OAI specification document for easier reasoning about the content. diff --git a/vendor/github.com/go-openapi/analysis/analyzer.go b/vendor/github.com/go-openapi/analysis/analyzer.go new file mode 100644 index 000000000..85711d577 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/analyzer.go @@ -0,0 +1,996 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis + +import ( + "fmt" + slashpath "path" + "strconv" + "strings" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/spec" + "github.com/go-openapi/swag" +) + +type referenceAnalysis struct { + schemas map[string]spec.Ref + responses map[string]spec.Ref + parameters map[string]spec.Ref + items map[string]spec.Ref + headerItems map[string]spec.Ref + parameterItems map[string]spec.Ref + allRefs map[string]spec.Ref + pathItems map[string]spec.Ref +} + +func (r *referenceAnalysis) addRef(key string, ref spec.Ref) { + r.allRefs["#"+key] = ref +} + +func (r *referenceAnalysis) addItemsRef(key string, items *spec.Items, location string) { + r.items["#"+key] = items.Ref + r.addRef(key, items.Ref) + if location == "header" { + // NOTE: in swagger 2.0, headers and parameters (but not body param schemas) are simple schemas + // and $ref are not supported here. However it is possible to analyze this. + r.headerItems["#"+key] = items.Ref + } else { + r.parameterItems["#"+key] = items.Ref + } +} + +func (r *referenceAnalysis) addSchemaRef(key string, ref SchemaRef) { + r.schemas["#"+key] = ref.Schema.Ref + r.addRef(key, ref.Schema.Ref) +} + +func (r *referenceAnalysis) addResponseRef(key string, resp *spec.Response) { + r.responses["#"+key] = resp.Ref + r.addRef(key, resp.Ref) +} + +func (r *referenceAnalysis) addParamRef(key string, param *spec.Parameter) { + r.parameters["#"+key] = param.Ref + r.addRef(key, param.Ref) +} + +func (r *referenceAnalysis) addPathItemRef(key string, pathItem *spec.PathItem) { + r.pathItems["#"+key] = pathItem.Ref + r.addRef(key, pathItem.Ref) +} + +type patternAnalysis struct { + parameters map[string]string + headers map[string]string + items map[string]string + schemas map[string]string + allPatterns map[string]string +} + +func (p *patternAnalysis) addPattern(key, pattern string) { + p.allPatterns["#"+key] = pattern +} + +func (p *patternAnalysis) addParameterPattern(key, pattern string) { + p.parameters["#"+key] = pattern + p.addPattern(key, pattern) +} + +func (p *patternAnalysis) addHeaderPattern(key, pattern string) { + p.headers["#"+key] = pattern + p.addPattern(key, pattern) +} + +func (p *patternAnalysis) addItemsPattern(key, pattern string) { + p.items["#"+key] = pattern + p.addPattern(key, pattern) +} + +func (p *patternAnalysis) addSchemaPattern(key, pattern string) { + p.schemas["#"+key] = pattern + p.addPattern(key, pattern) +} + +type enumAnalysis struct { + parameters map[string][]interface{} + headers map[string][]interface{} + items map[string][]interface{} + schemas map[string][]interface{} + allEnums map[string][]interface{} +} + +func (p *enumAnalysis) addEnum(key string, enum []interface{}) { + p.allEnums["#"+key] = enum +} + +func (p *enumAnalysis) addParameterEnum(key string, enum []interface{}) { + p.parameters["#"+key] = enum + p.addEnum(key, enum) +} + +func (p *enumAnalysis) addHeaderEnum(key string, enum []interface{}) { + p.headers["#"+key] = enum + p.addEnum(key, enum) +} + +func (p *enumAnalysis) addItemsEnum(key string, enum []interface{}) { + p.items["#"+key] = enum + p.addEnum(key, enum) +} + +func (p *enumAnalysis) addSchemaEnum(key string, enum []interface{}) { + p.schemas["#"+key] = enum + p.addEnum(key, enum) +} + +// New takes a swagger spec object and returns an analyzed spec document. +// The analyzed document contains a number of indices that make it easier to +// reason about semantics of a swagger specification for use in code generation +// or validation etc. +func New(doc *spec.Swagger) *Spec { + a := &Spec{ + spec: doc, + consumes: make(map[string]struct{}, 150), + produces: make(map[string]struct{}, 150), + authSchemes: make(map[string]struct{}, 150), + operations: make(map[string]map[string]*spec.Operation, 150), + allSchemas: make(map[string]SchemaRef, 150), + allOfs: make(map[string]SchemaRef, 150), + references: referenceAnalysis{ + schemas: make(map[string]spec.Ref, 150), + pathItems: make(map[string]spec.Ref, 150), + responses: make(map[string]spec.Ref, 150), + parameters: make(map[string]spec.Ref, 150), + items: make(map[string]spec.Ref, 150), + headerItems: make(map[string]spec.Ref, 150), + parameterItems: make(map[string]spec.Ref, 150), + allRefs: make(map[string]spec.Ref, 150), + }, + patterns: patternAnalysis{ + parameters: make(map[string]string, 150), + headers: make(map[string]string, 150), + items: make(map[string]string, 150), + schemas: make(map[string]string, 150), + allPatterns: make(map[string]string, 150), + }, + enums: enumAnalysis{ + parameters: make(map[string][]interface{}, 150), + headers: make(map[string][]interface{}, 150), + items: make(map[string][]interface{}, 150), + schemas: make(map[string][]interface{}, 150), + allEnums: make(map[string][]interface{}, 150), + }, + } + a.initialize() + return a +} + +// Spec is an analyzed specification object. It takes a swagger spec object and turns it into a registry +// with a bunch of utility methods to act on the information in the spec. +type Spec struct { + spec *spec.Swagger + consumes map[string]struct{} + produces map[string]struct{} + authSchemes map[string]struct{} + operations map[string]map[string]*spec.Operation + references referenceAnalysis + patterns patternAnalysis + enums enumAnalysis + allSchemas map[string]SchemaRef + allOfs map[string]SchemaRef +} + +func (s *Spec) reset() { + s.consumes = make(map[string]struct{}, 150) + s.produces = make(map[string]struct{}, 150) + s.authSchemes = make(map[string]struct{}, 150) + s.operations = make(map[string]map[string]*spec.Operation, 150) + s.allSchemas = make(map[string]SchemaRef, 150) + s.allOfs = make(map[string]SchemaRef, 150) + s.references.schemas = make(map[string]spec.Ref, 150) + s.references.pathItems = make(map[string]spec.Ref, 150) + s.references.responses = make(map[string]spec.Ref, 150) + s.references.parameters = make(map[string]spec.Ref, 150) + s.references.items = make(map[string]spec.Ref, 150) + s.references.headerItems = make(map[string]spec.Ref, 150) + s.references.parameterItems = make(map[string]spec.Ref, 150) + s.references.allRefs = make(map[string]spec.Ref, 150) + s.patterns.parameters = make(map[string]string, 150) + s.patterns.headers = make(map[string]string, 150) + s.patterns.items = make(map[string]string, 150) + s.patterns.schemas = make(map[string]string, 150) + s.patterns.allPatterns = make(map[string]string, 150) + s.enums.parameters = make(map[string][]interface{}, 150) + s.enums.headers = make(map[string][]interface{}, 150) + s.enums.items = make(map[string][]interface{}, 150) + s.enums.schemas = make(map[string][]interface{}, 150) + s.enums.allEnums = make(map[string][]interface{}, 150) +} + +func (s *Spec) reload() { + s.reset() + s.initialize() +} + +func (s *Spec) initialize() { + for _, c := range s.spec.Consumes { + s.consumes[c] = struct{}{} + } + for _, c := range s.spec.Produces { + s.produces[c] = struct{}{} + } + for _, ss := range s.spec.Security { + for k := range ss { + s.authSchemes[k] = struct{}{} + } + } + for path, pathItem := range s.AllPaths() { + s.analyzeOperations(path, &pathItem) + } + + for name, parameter := range s.spec.Parameters { + refPref := slashpath.Join("/parameters", jsonpointer.Escape(name)) + if parameter.Items != nil { + s.analyzeItems("items", parameter.Items, refPref, "parameter") + } + if parameter.In == "body" && parameter.Schema != nil { + s.analyzeSchema("schema", *parameter.Schema, refPref) + } + if parameter.Pattern != "" { + s.patterns.addParameterPattern(refPref, parameter.Pattern) + } + if len(parameter.Enum) > 0 { + s.enums.addParameterEnum(refPref, parameter.Enum) + } + } + + for name, response := range s.spec.Responses { + refPref := slashpath.Join("/responses", jsonpointer.Escape(name)) + for k, v := range response.Headers { + hRefPref := slashpath.Join(refPref, "headers", k) + if v.Items != nil { + s.analyzeItems("items", v.Items, hRefPref, "header") + } + if v.Pattern != "" { + s.patterns.addHeaderPattern(hRefPref, v.Pattern) + } + if len(v.Enum) > 0 { + s.enums.addHeaderEnum(hRefPref, v.Enum) + } + } + if response.Schema != nil { + s.analyzeSchema("schema", *response.Schema, refPref) + } + } + + for name, schema := range s.spec.Definitions { + s.analyzeSchema(name, schema, "/definitions") + } + // TODO: after analyzing all things and flattening schemas etc + // resolve all the collected references to their final representations + // best put in a separate method because this could get expensive +} + +func (s *Spec) analyzeOperations(path string, pi *spec.PathItem) { + // TODO: resolve refs here? + // Currently, operations declared via pathItem $ref are known only after expansion + op := pi + if pi.Ref.String() != "" { + key := slashpath.Join("/paths", jsonpointer.Escape(path)) + s.references.addPathItemRef(key, pi) + } + s.analyzeOperation("GET", path, op.Get) + s.analyzeOperation("PUT", path, op.Put) + s.analyzeOperation("POST", path, op.Post) + s.analyzeOperation("PATCH", path, op.Patch) + s.analyzeOperation("DELETE", path, op.Delete) + s.analyzeOperation("HEAD", path, op.Head) + s.analyzeOperation("OPTIONS", path, op.Options) + for i, param := range op.Parameters { + refPref := slashpath.Join("/paths", jsonpointer.Escape(path), "parameters", strconv.Itoa(i)) + if param.Ref.String() != "" { + s.references.addParamRef(refPref, ¶m) + } + if param.Pattern != "" { + s.patterns.addParameterPattern(refPref, param.Pattern) + } + if len(param.Enum) > 0 { + s.enums.addParameterEnum(refPref, param.Enum) + } + if param.Items != nil { + s.analyzeItems("items", param.Items, refPref, "parameter") + } + if param.Schema != nil { + s.analyzeSchema("schema", *param.Schema, refPref) + } + } +} + +func (s *Spec) analyzeItems(name string, items *spec.Items, prefix, location string) { + if items == nil { + return + } + refPref := slashpath.Join(prefix, name) + s.analyzeItems(name, items.Items, refPref, location) + if items.Ref.String() != "" { + s.references.addItemsRef(refPref, items, location) + } + if items.Pattern != "" { + s.patterns.addItemsPattern(refPref, items.Pattern) + } + if len(items.Enum) > 0 { + s.enums.addItemsEnum(refPref, items.Enum) + } +} + +func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) { + if op == nil { + return + } + + for _, c := range op.Consumes { + s.consumes[c] = struct{}{} + } + for _, c := range op.Produces { + s.produces[c] = struct{}{} + } + for _, ss := range op.Security { + for k := range ss { + s.authSchemes[k] = struct{}{} + } + } + if _, ok := s.operations[method]; !ok { + s.operations[method] = make(map[string]*spec.Operation) + } + s.operations[method][path] = op + prefix := slashpath.Join("/paths", jsonpointer.Escape(path), strings.ToLower(method)) + for i, param := range op.Parameters { + refPref := slashpath.Join(prefix, "parameters", strconv.Itoa(i)) + if param.Ref.String() != "" { + s.references.addParamRef(refPref, ¶m) + } + if param.Pattern != "" { + s.patterns.addParameterPattern(refPref, param.Pattern) + } + if len(param.Enum) > 0 { + s.enums.addParameterEnum(refPref, param.Enum) + } + s.analyzeItems("items", param.Items, refPref, "parameter") + if param.In == "body" && param.Schema != nil { + s.analyzeSchema("schema", *param.Schema, refPref) + } + } + if op.Responses != nil { + if op.Responses.Default != nil { + refPref := slashpath.Join(prefix, "responses", "default") + if op.Responses.Default.Ref.String() != "" { + s.references.addResponseRef(refPref, op.Responses.Default) + } + for k, v := range op.Responses.Default.Headers { + hRefPref := slashpath.Join(refPref, "headers", k) + s.analyzeItems("items", v.Items, hRefPref, "header") + if v.Pattern != "" { + s.patterns.addHeaderPattern(hRefPref, v.Pattern) + } + } + if op.Responses.Default.Schema != nil { + s.analyzeSchema("schema", *op.Responses.Default.Schema, refPref) + } + } + for k, res := range op.Responses.StatusCodeResponses { + refPref := slashpath.Join(prefix, "responses", strconv.Itoa(k)) + if res.Ref.String() != "" { + s.references.addResponseRef(refPref, &res) + } + for k, v := range res.Headers { + hRefPref := slashpath.Join(refPref, "headers", k) + s.analyzeItems("items", v.Items, hRefPref, "header") + if v.Pattern != "" { + s.patterns.addHeaderPattern(hRefPref, v.Pattern) + } + if len(v.Enum) > 0 { + s.enums.addHeaderEnum(hRefPref, v.Enum) + } + } + if res.Schema != nil { + s.analyzeSchema("schema", *res.Schema, refPref) + } + } + } +} + +func (s *Spec) analyzeSchema(name string, schema spec.Schema, prefix string) { + refURI := slashpath.Join(prefix, jsonpointer.Escape(name)) + schRef := SchemaRef{ + Name: name, + Schema: &schema, + Ref: spec.MustCreateRef("#" + refURI), + TopLevel: prefix == "/definitions", + } + + s.allSchemas["#"+refURI] = schRef + + if schema.Ref.String() != "" { + s.references.addSchemaRef(refURI, schRef) + } + if schema.Pattern != "" { + s.patterns.addSchemaPattern(refURI, schema.Pattern) + } + if len(schema.Enum) > 0 { + s.enums.addSchemaEnum(refURI, schema.Enum) + } + + for k, v := range schema.Definitions { + s.analyzeSchema(k, v, slashpath.Join(refURI, "definitions")) + } + for k, v := range schema.Properties { + s.analyzeSchema(k, v, slashpath.Join(refURI, "properties")) + } + for k, v := range schema.PatternProperties { + // NOTE: swagger 2.0 does not support PatternProperties. + // However it is possible to analyze this in a schema + s.analyzeSchema(k, v, slashpath.Join(refURI, "patternProperties")) + } + for i, v := range schema.AllOf { + s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "allOf")) + } + if len(schema.AllOf) > 0 { + s.allOfs["#"+refURI] = schRef + } + for i, v := range schema.AnyOf { + // NOTE: swagger 2.0 does not support anyOf constructs. + // However it is possible to analyze this in a schema + s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "anyOf")) + } + for i, v := range schema.OneOf { + // NOTE: swagger 2.0 does not support oneOf constructs. + // However it is possible to analyze this in a schema + s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "oneOf")) + } + if schema.Not != nil { + // NOTE: swagger 2.0 does not support "not" constructs. + // However it is possible to analyze this in a schema + s.analyzeSchema("not", *schema.Not, refURI) + } + if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { + s.analyzeSchema("additionalProperties", *schema.AdditionalProperties.Schema, refURI) + } + if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { + // NOTE: swagger 2.0 does not support AdditionalItems. + // However it is possible to analyze this in a schema + s.analyzeSchema("additionalItems", *schema.AdditionalItems.Schema, refURI) + } + if schema.Items != nil { + if schema.Items.Schema != nil { + s.analyzeSchema("items", *schema.Items.Schema, refURI) + } + for i, sch := range schema.Items.Schemas { + s.analyzeSchema(strconv.Itoa(i), sch, slashpath.Join(refURI, "items")) + } + } +} + +// SecurityRequirement is a representation of a security requirement for an operation +type SecurityRequirement struct { + Name string + Scopes []string +} + +// SecurityRequirementsFor gets the security requirements for the operation +func (s *Spec) SecurityRequirementsFor(operation *spec.Operation) [][]SecurityRequirement { + if s.spec.Security == nil && operation.Security == nil { + return nil + } + + schemes := s.spec.Security + if operation.Security != nil { + schemes = operation.Security + } + + result := [][]SecurityRequirement{} + for _, scheme := range schemes { + if len(scheme) == 0 { + // append a zero object for anonymous + result = append(result, []SecurityRequirement{{}}) + continue + } + var reqs []SecurityRequirement + for k, v := range scheme { + if v == nil { + v = []string{} + } + reqs = append(reqs, SecurityRequirement{Name: k, Scopes: v}) + } + result = append(result, reqs) + } + return result +} + +// SecurityDefinitionsForRequirements gets the matching security definitions for a set of requirements +func (s *Spec) SecurityDefinitionsForRequirements(requirements []SecurityRequirement) map[string]spec.SecurityScheme { + result := make(map[string]spec.SecurityScheme) + + for _, v := range requirements { + if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok { + if definition != nil { + result[v.Name] = *definition + } + } + } + return result +} + +// SecurityDefinitionsFor gets the matching security definitions for a set of requirements +func (s *Spec) SecurityDefinitionsFor(operation *spec.Operation) map[string]spec.SecurityScheme { + requirements := s.SecurityRequirementsFor(operation) + if len(requirements) == 0 { + return nil + } + + result := make(map[string]spec.SecurityScheme) + for _, reqs := range requirements { + for _, v := range reqs { + if v.Name == "" { + // optional requirement + continue + } + if _, ok := result[v.Name]; ok { + // duplicate requirement + continue + } + if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok { + if definition != nil { + result[v.Name] = *definition + } + } + } + } + return result +} + +// ConsumesFor gets the mediatypes for the operation +func (s *Spec) ConsumesFor(operation *spec.Operation) []string { + + if len(operation.Consumes) == 0 { + cons := make(map[string]struct{}, len(s.spec.Consumes)) + for _, k := range s.spec.Consumes { + cons[k] = struct{}{} + } + return s.structMapKeys(cons) + } + + cons := make(map[string]struct{}, len(operation.Consumes)) + for _, c := range operation.Consumes { + cons[c] = struct{}{} + } + return s.structMapKeys(cons) +} + +// ProducesFor gets the mediatypes for the operation +func (s *Spec) ProducesFor(operation *spec.Operation) []string { + if len(operation.Produces) == 0 { + prod := make(map[string]struct{}, len(s.spec.Produces)) + for _, k := range s.spec.Produces { + prod[k] = struct{}{} + } + return s.structMapKeys(prod) + } + + prod := make(map[string]struct{}, len(operation.Produces)) + for _, c := range operation.Produces { + prod[c] = struct{}{} + } + return s.structMapKeys(prod) +} + +func mapKeyFromParam(param *spec.Parameter) string { + return fmt.Sprintf("%s#%s", param.In, fieldNameFromParam(param)) +} + +func fieldNameFromParam(param *spec.Parameter) string { + // TODO: this should be x-go-name + if nm, ok := param.Extensions.GetString("go-name"); ok { + return nm + } + return swag.ToGoName(param.Name) +} + +// ErrorOnParamFunc is a callback function to be invoked +// whenever an error is encountered while resolving references +// on parameters. +// +// This function takes as input the spec.Parameter which triggered the +// error and the error itself. +// +// If the callback function returns false, the calling function should bail. +// +// If it returns true, the calling function should continue evaluating parameters. +// A nil ErrorOnParamFunc must be evaluated as equivalent to panic(). +type ErrorOnParamFunc func(spec.Parameter, error) bool + +func (s *Spec) paramsAsMap(parameters []spec.Parameter, res map[string]spec.Parameter, callmeOnError ErrorOnParamFunc) { + for _, param := range parameters { + pr := param + if pr.Ref.String() != "" { + obj, _, err := pr.Ref.GetPointer().Get(s.spec) + if err != nil { + if callmeOnError != nil { + if callmeOnError(param, fmt.Errorf("invalid reference: %q", pr.Ref.String())) { + continue + } + break + } else { + panic(fmt.Sprintf("invalid reference: %q", pr.Ref.String())) + } + } + if objAsParam, ok := obj.(spec.Parameter); ok { + pr = objAsParam + } else { + if callmeOnError != nil { + if callmeOnError(param, fmt.Errorf("resolved reference is not a parameter: %q", pr.Ref.String())) { + continue + } + break + } else { + panic(fmt.Sprintf("resolved reference is not a parameter: %q", pr.Ref.String())) + } + } + } + res[mapKeyFromParam(&pr)] = pr + } +} + +// ParametersFor the specified operation id. +// +// Assumes parameters properly resolve references if any and that +// such references actually resolve to a parameter object. +// Otherwise, panics. +func (s *Spec) ParametersFor(operationID string) []spec.Parameter { + return s.SafeParametersFor(operationID, nil) +} + +// SafeParametersFor the specified operation id. +// +// Does not assume parameters properly resolve references or that +// such references actually resolve to a parameter object. +// +// Upon error, invoke a ErrorOnParamFunc callback with the erroneous +// parameters. If the callback is set to nil, panics upon errors. +func (s *Spec) SafeParametersFor(operationID string, callmeOnError ErrorOnParamFunc) []spec.Parameter { + gatherParams := func(pi *spec.PathItem, op *spec.Operation) []spec.Parameter { + bag := make(map[string]spec.Parameter) + s.paramsAsMap(pi.Parameters, bag, callmeOnError) + s.paramsAsMap(op.Parameters, bag, callmeOnError) + + var res []spec.Parameter + for _, v := range bag { + res = append(res, v) + } + return res + } + for _, pi := range s.spec.Paths.Paths { + if pi.Get != nil && pi.Get.ID == operationID { + return gatherParams(&pi, pi.Get) + } + if pi.Head != nil && pi.Head.ID == operationID { + return gatherParams(&pi, pi.Head) + } + if pi.Options != nil && pi.Options.ID == operationID { + return gatherParams(&pi, pi.Options) + } + if pi.Post != nil && pi.Post.ID == operationID { + return gatherParams(&pi, pi.Post) + } + if pi.Patch != nil && pi.Patch.ID == operationID { + return gatherParams(&pi, pi.Patch) + } + if pi.Put != nil && pi.Put.ID == operationID { + return gatherParams(&pi, pi.Put) + } + if pi.Delete != nil && pi.Delete.ID == operationID { + return gatherParams(&pi, pi.Delete) + } + } + return nil +} + +// ParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that +// apply for the method and path. +// +// Assumes parameters properly resolve references if any and that +// such references actually resolve to a parameter object. +// Otherwise, panics. +func (s *Spec) ParamsFor(method, path string) map[string]spec.Parameter { + return s.SafeParamsFor(method, path, nil) +} + +// SafeParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that +// apply for the method and path. +// +// Does not assume parameters properly resolve references or that +// such references actually resolve to a parameter object. +// +// Upon error, invoke a ErrorOnParamFunc callback with the erroneous +// parameters. If the callback is set to nil, panics upon errors. +func (s *Spec) SafeParamsFor(method, path string, callmeOnError ErrorOnParamFunc) map[string]spec.Parameter { + res := make(map[string]spec.Parameter) + if pi, ok := s.spec.Paths.Paths[path]; ok { + s.paramsAsMap(pi.Parameters, res, callmeOnError) + s.paramsAsMap(s.operations[strings.ToUpper(method)][path].Parameters, res, callmeOnError) + } + return res +} + +// OperationForName gets the operation for the given id +func (s *Spec) OperationForName(operationID string) (string, string, *spec.Operation, bool) { + for method, pathItem := range s.operations { + for path, op := range pathItem { + if operationID == op.ID { + return method, path, op, true + } + } + } + return "", "", nil, false +} + +// OperationFor the given method and path +func (s *Spec) OperationFor(method, path string) (*spec.Operation, bool) { + if mp, ok := s.operations[strings.ToUpper(method)]; ok { + op, fn := mp[path] + return op, fn + } + return nil, false +} + +// Operations gathers all the operations specified in the spec document +func (s *Spec) Operations() map[string]map[string]*spec.Operation { + return s.operations +} + +func (s *Spec) structMapKeys(mp map[string]struct{}) []string { + if len(mp) == 0 { + return nil + } + + result := make([]string, 0, len(mp)) + for k := range mp { + result = append(result, k) + } + return result +} + +// AllPaths returns all the paths in the swagger spec +func (s *Spec) AllPaths() map[string]spec.PathItem { + if s.spec == nil || s.spec.Paths == nil { + return nil + } + return s.spec.Paths.Paths +} + +// OperationIDs gets all the operation ids based on method an dpath +func (s *Spec) OperationIDs() []string { + if len(s.operations) == 0 { + return nil + } + result := make([]string, 0, len(s.operations)) + for method, v := range s.operations { + for p, o := range v { + if o.ID != "" { + result = append(result, o.ID) + } else { + result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p)) + } + } + } + return result +} + +// OperationMethodPaths gets all the operation ids based on method an dpath +func (s *Spec) OperationMethodPaths() []string { + if len(s.operations) == 0 { + return nil + } + result := make([]string, 0, len(s.operations)) + for method, v := range s.operations { + for p := range v { + result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p)) + } + } + return result +} + +// RequiredConsumes gets all the distinct consumes that are specified in the specification document +func (s *Spec) RequiredConsumes() []string { + return s.structMapKeys(s.consumes) +} + +// RequiredProduces gets all the distinct produces that are specified in the specification document +func (s *Spec) RequiredProduces() []string { + return s.structMapKeys(s.produces) +} + +// RequiredSecuritySchemes gets all the distinct security schemes that are specified in the swagger spec +func (s *Spec) RequiredSecuritySchemes() []string { + return s.structMapKeys(s.authSchemes) +} + +// SchemaRef is a reference to a schema +type SchemaRef struct { + Name string + Ref spec.Ref + Schema *spec.Schema + TopLevel bool +} + +// SchemasWithAllOf returns schema references to all schemas that are defined +// with an allOf key +func (s *Spec) SchemasWithAllOf() (result []SchemaRef) { + for _, v := range s.allOfs { + result = append(result, v) + } + return +} + +// AllDefinitions returns schema references for all the definitions that were discovered +func (s *Spec) AllDefinitions() (result []SchemaRef) { + for _, v := range s.allSchemas { + result = append(result, v) + } + return +} + +// AllDefinitionReferences returns json refs for all the discovered schemas +func (s *Spec) AllDefinitionReferences() (result []string) { + for _, v := range s.references.schemas { + result = append(result, v.String()) + } + return +} + +// AllParameterReferences returns json refs for all the discovered parameters +func (s *Spec) AllParameterReferences() (result []string) { + for _, v := range s.references.parameters { + result = append(result, v.String()) + } + return +} + +// AllResponseReferences returns json refs for all the discovered responses +func (s *Spec) AllResponseReferences() (result []string) { + for _, v := range s.references.responses { + result = append(result, v.String()) + } + return +} + +// AllPathItemReferences returns the references for all the items +func (s *Spec) AllPathItemReferences() (result []string) { + for _, v := range s.references.pathItems { + result = append(result, v.String()) + } + return +} + +// AllItemsReferences returns the references for all the items in simple schemas (parameters or headers). +// +// NOTE: since Swagger 2.0 forbids $ref in simple params, this should always yield an empty slice for a valid +// Swagger 2.0 spec. +func (s *Spec) AllItemsReferences() (result []string) { + for _, v := range s.references.items { + result = append(result, v.String()) + } + return +} + +// AllReferences returns all the references found in the document, with possible duplicates +func (s *Spec) AllReferences() (result []string) { + for _, v := range s.references.allRefs { + result = append(result, v.String()) + } + return +} + +// AllRefs returns all the unique references found in the document +func (s *Spec) AllRefs() (result []spec.Ref) { + set := make(map[string]struct{}) + for _, v := range s.references.allRefs { + a := v.String() + if a == "" { + continue + } + if _, ok := set[a]; !ok { + set[a] = struct{}{} + result = append(result, v) + } + } + return +} + +func cloneStringMap(source map[string]string) map[string]string { + res := make(map[string]string, len(source)) + for k, v := range source { + res[k] = v + } + return res +} + +func cloneEnumMap(source map[string][]interface{}) map[string][]interface{} { + res := make(map[string][]interface{}, len(source)) + for k, v := range source { + res[k] = v + } + return res +} + +// ParameterPatterns returns all the patterns found in parameters +// the map is cloned to avoid accidental changes +func (s *Spec) ParameterPatterns() map[string]string { + return cloneStringMap(s.patterns.parameters) +} + +// HeaderPatterns returns all the patterns found in response headers +// the map is cloned to avoid accidental changes +func (s *Spec) HeaderPatterns() map[string]string { + return cloneStringMap(s.patterns.headers) +} + +// ItemsPatterns returns all the patterns found in simple array items +// the map is cloned to avoid accidental changes +func (s *Spec) ItemsPatterns() map[string]string { + return cloneStringMap(s.patterns.items) +} + +// SchemaPatterns returns all the patterns found in schemas +// the map is cloned to avoid accidental changes +func (s *Spec) SchemaPatterns() map[string]string { + return cloneStringMap(s.patterns.schemas) +} + +// AllPatterns returns all the patterns found in the spec +// the map is cloned to avoid accidental changes +func (s *Spec) AllPatterns() map[string]string { + return cloneStringMap(s.patterns.allPatterns) +} + +// ParameterEnums returns all the enums found in parameters +// the map is cloned to avoid accidental changes +func (s *Spec) ParameterEnums() map[string][]interface{} { + return cloneEnumMap(s.enums.parameters) +} + +// HeaderEnums returns all the enums found in response headers +// the map is cloned to avoid accidental changes +func (s *Spec) HeaderEnums() map[string][]interface{} { + return cloneEnumMap(s.enums.headers) +} + +// ItemsEnums returns all the enums found in simple array items +// the map is cloned to avoid accidental changes +func (s *Spec) ItemsEnums() map[string][]interface{} { + return cloneEnumMap(s.enums.items) +} + +// SchemaEnums returns all the enums found in schemas +// the map is cloned to avoid accidental changes +func (s *Spec) SchemaEnums() map[string][]interface{} { + return cloneEnumMap(s.enums.schemas) +} + +// AllEnums returns all the enums found in the spec +// the map is cloned to avoid accidental changes +func (s *Spec) AllEnums() map[string][]interface{} { + return cloneEnumMap(s.enums.allEnums) +} diff --git a/vendor/github.com/go-openapi/analysis/debug.go b/vendor/github.com/go-openapi/analysis/debug.go new file mode 100644 index 000000000..84cc4e54c --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/debug.go @@ -0,0 +1,47 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" +) + +var ( + // Debug is true when the SWAGGER_DEBUG env var is not empty. + // It enables a more verbose logging of the spec analyzer. + Debug = os.Getenv("SWAGGER_DEBUG") != "" + // analysisLogger is a debug logger for this package + analysisLogger *log.Logger +) + +func init() { + debugOptions() +} + +func debugOptions() { + analysisLogger = log.New(os.Stdout, "analysis:", log.LstdFlags) +} + +func debugLog(msg string, args ...interface{}) { + // A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog() + if Debug { + _, file1, pos1, _ := runtime.Caller(1) + analysisLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...)) + } +} diff --git a/vendor/github.com/go-openapi/analysis/doc.go b/vendor/github.com/go-openapi/analysis/doc.go new file mode 100644 index 000000000..d5294c095 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/doc.go @@ -0,0 +1,43 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis provides methods to work with a Swagger specification document from +package go-openapi/spec. + +Analyzing a specification + +An analysed specification object (type Spec) provides methods to work with swagger definition. + +Flattening or expanding a specification + +Flattening a specification bundles all remote $ref in the main spec document. +Depending on flattening options, additional preprocessing may take place: + - full flattening: replacing all inline complex constructs by a named entry in #/definitions + - expand: replace all $ref's in the document by their expanded content + +Merging several specifications + +Mixin several specifications merges all Swagger constructs, and warns about found conflicts. + +Fixing a specification + +Unmarshalling a specification with golang json unmarshalling may lead to +some unwanted result on present but empty fields. + +Analyzing a Swagger schema + +Swagger schemas are analyzed to determine their complexity and qualify their content. +*/ +package analysis diff --git a/vendor/github.com/go-openapi/analysis/fixer.go b/vendor/github.com/go-openapi/analysis/fixer.go new file mode 100644 index 000000000..bfe014ca5 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/fixer.go @@ -0,0 +1,76 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis + +import "github.com/go-openapi/spec" + +// FixEmptyResponseDescriptions replaces empty ("") response +// descriptions in the input with "(empty)" to ensure that the +// resulting Swagger is stays valid. The problem appears to arise +// from reading in valid specs that have a explicit response +// description of "" (valid, response.description is required), but +// due to zero values being omitted upon re-serializing (omitempty) we +// lose them unless we stick some chars in there. +func FixEmptyResponseDescriptions(s *spec.Swagger) { + if s.Paths != nil { + for _, v := range s.Paths.Paths { + if v.Get != nil { + FixEmptyDescs(v.Get.Responses) + } + if v.Put != nil { + FixEmptyDescs(v.Put.Responses) + } + if v.Post != nil { + FixEmptyDescs(v.Post.Responses) + } + if v.Delete != nil { + FixEmptyDescs(v.Delete.Responses) + } + if v.Options != nil { + FixEmptyDescs(v.Options.Responses) + } + if v.Head != nil { + FixEmptyDescs(v.Head.Responses) + } + if v.Patch != nil { + FixEmptyDescs(v.Patch.Responses) + } + } + } + for k, v := range s.Responses { + FixEmptyDesc(&v) + s.Responses[k] = v + } +} + +// FixEmptyDescs adds "(empty)" as the description for any Response in +// the given Responses object that doesn't already have one. +func FixEmptyDescs(rs *spec.Responses) { + FixEmptyDesc(rs.Default) + for k, v := range rs.StatusCodeResponses { + FixEmptyDesc(&v) + rs.StatusCodeResponses[k] = v + } +} + +// FixEmptyDesc adds "(empty)" as the description to the given +// Response object if it doesn't already have one and isn't a +// ref. No-op on nil input. +func FixEmptyDesc(rs *spec.Response) { + if rs == nil || rs.Description != "" || rs.Ref.Ref.GetURL() != nil { + return + } + rs.Description = "(empty)" +} diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go new file mode 100644 index 000000000..0095e8258 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/flatten.go @@ -0,0 +1,1525 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis + +import ( + "fmt" + "log" + "net/http" + "net/url" + "os" + slashpath "path" + "path/filepath" + "sort" + "strings" + + "strconv" + + "github.com/go-openapi/analysis/internal" + "github.com/go-openapi/jsonpointer" + swspec "github.com/go-openapi/spec" + "github.com/go-openapi/swag" +) + +// FlattenOpts configuration for flattening a swagger specification. +type FlattenOpts struct { + Spec *Spec // The analyzed spec to work with + flattenContext *context // Internal context to track flattening activity + + BasePath string + + // Flattening options + Expand bool // If Expand is true, we skip flattening the spec and expand it instead + Minimal bool + Verbose bool + RemoveUnused bool + + /* Extra keys */ + _ struct{} // require keys +} + +// ExpandOpts creates a spec.ExpandOptions to configure expanding a specification document. +func (f *FlattenOpts) ExpandOpts(skipSchemas bool) *swspec.ExpandOptions { + return &swspec.ExpandOptions{RelativeBase: f.BasePath, SkipSchemas: skipSchemas} +} + +// Swagger gets the swagger specification for this flatten operation +func (f *FlattenOpts) Swagger() *swspec.Swagger { + return f.Spec.spec +} + +// newRef stores information about refs created during the flattening process +type newRef struct { + key string + newName string + path string + isOAIGen bool + resolved bool + schema *swspec.Schema + parents []string +} + +// context stores intermediary results from flatten +type context struct { + newRefs map[string]*newRef + warnings []string + resolved map[string]string +} + +func newContext() *context { + return &context{ + newRefs: make(map[string]*newRef, 150), + warnings: make([]string, 0), + resolved: make(map[string]string, 50), + } +} + +// Flatten an analyzed spec and produce a self-contained spec bundle. +// +// There is a minimal and a full flattening mode. +// +// Minimally flattening a spec means: +// - Expanding parameters, responses, path items, parameter items and header items (references to schemas are left +// unscathed) +// - Importing external (http, file) references so they become internal to the document +// - Moving every JSON pointer to a $ref to a named definition (i.e. the reworked spec does not contain pointers +// like "$ref": "#/definitions/myObject/allOfs/1") +// +// A minimally flattened spec thus guarantees the following properties: +// - all $refs point to a local definition (i.e. '#/definitions/...') +// - definitions are unique +// +// NOTE: arbitrary JSON pointers (other than $refs to top level definitions) are rewritten as definitions if they +// represent a complex schema or express commonality in the spec. +// Otherwise, they are simply expanded. +// +// Minimal flattening is necessary and sufficient for codegen rendering using go-swagger. +// +// Fully flattening a spec means: +// - Moving every complex inline schema to be a definition with an auto-generated name in a depth-first fashion. +// +// By complex, we mean every JSON object with some properties. +// Arrays, when they do not define a tuple, +// or empty objects with or without additionalProperties, are not considered complex and remain inline. +// +// NOTE: rewritten schemas get a vendor extension x-go-gen-location so we know from which part of the spec definitions +// have been created. +// +// Available flattening options: +// - Minimal: stops flattening after minimal $ref processing, leaving schema constructs untouched +// - Expand: expand all $ref's in the document (inoperant if Minimal set to true) +// - Verbose: croaks about name conflicts detected +// - RemoveUnused: removes unused parameters, responses and definitions after expansion/flattening +// +// NOTE: expansion removes all $ref save circular $ref, which remain in place +// +// TODO: additional options +// - ProgagateNameExtensions: ensure that created entries properly follow naming rules when their parent have set a +// x-go-name extension +// - LiftAllOfs: +// - limit the flattening of allOf members when simple objects +// - merge allOf with validation only +// - merge allOf with extensions only +// - ... +// +func Flatten(opts FlattenOpts) error { + // Make sure opts.BasePath is an absolute path + if !filepath.IsAbs(opts.BasePath) { + cwd, _ := os.Getwd() + opts.BasePath = filepath.Join(cwd, opts.BasePath) + } + + opts.flattenContext = newContext() + + // recursively expand responses, parameters, path items and items in simple schemas. + // This simplifies the spec and leaves $ref only into schema objects. + // + if err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(!opts.Expand)); err != nil { + return err + } + + // strip current file from $ref's, so we can recognize them as proper definitions + // In particular, this works around for issue go-openapi/spec#76: leading absolute file in $ref is stripped + if err := normalizeRef(&opts); err != nil { + return err + } + + if opts.RemoveUnused { + // optionally removes shared parameters and responses already expanded (now unused) + // default parameters (i.e. under paths) remain. + opts.Swagger().Parameters = nil + opts.Swagger().Responses = nil + } + + opts.Spec.reload() // re-analyze + + // at this point there are no other references left but schemas + for imported := false; !imported; { + var err error + if imported, err = importExternalReferences(&opts); err != nil { + return err + } + opts.Spec.reload() // re-analyze + } + + if !opts.Minimal && !opts.Expand { + // full flattening: rewrite inline schemas (schemas that aren't simple types or arrays or maps) + if err := nameInlinedSchemas(&opts); err != nil { + return err + } + + opts.Spec.reload() // re-analyze + } + // rewrite JSON pointers other than $ref to named definitions + // and attempts to resolve conflicting names + if err := stripPointersAndOAIGen(&opts); err != nil { + return err + } + + if opts.RemoveUnused { + // remove unused definitions + expected := make(map[string]struct{}) + for k := range opts.Swagger().Definitions { + expected[slashpath.Join(definitionsPath, jsonpointer.Escape(k))] = struct{}{} + } + for _, k := range opts.Spec.AllDefinitionReferences() { + if _, ok := expected[k]; ok { + delete(expected, k) + } + } + for k := range expected { + debugLog("removing unused definition %s", slashpath.Base(k)) + if opts.Verbose { + log.Printf("info: removing unused definition: %s", slashpath.Base(k)) + } + delete(opts.Swagger().Definitions, slashpath.Base(k)) + } + opts.Spec.reload() // re-analyze + } + + // TODO: simplify known schema patterns to flat objects with properties + // examples: + // - lift simple allOf object, + // - empty allOf with validation only or extensions only + // - rework allOf arrays + // - rework allOf additionalProperties + + if opts.Verbose { + // issue notifications + croak(&opts) + } + return nil +} + +// isAnalyzedAsComplex determines if an analyzed schema is eligible to flattening (i.e. it is "complex"). +// +// Complex means the schema is any of: +// - a simple type (primitive) +// - an array of something (items are possibly complex ; if this is the case, items will generate a definition) +// - a map of something (additionalProperties are possibly complex ; if this is the case, additionalProperties will +// generate a definition) +func isAnalyzedAsComplex(asch *AnalyzedSchema) bool { + if !asch.IsSimpleSchema && !asch.IsArray && !asch.IsMap { + return true + } + return false +} + +// nameInlinedSchemas replaces every complex inline construct by a named definition. +func nameInlinedSchemas(opts *FlattenOpts) error { + debugLog("nameInlinedSchemas") + namer := &inlineSchemaNamer{ + Spec: opts.Swagger(), + Operations: opRefsByRef(gatherOperations(opts.Spec, nil)), + flattenContext: opts.flattenContext, + opts: opts, + } + depthFirst := sortDepthFirst(opts.Spec.allSchemas) + for _, key := range depthFirst { + sch := opts.Spec.allSchemas[key] + if sch.Schema != nil && sch.Schema.Ref.String() == "" && !sch.TopLevel { // inline schema + asch, err := Schema(SchemaOpts{Schema: sch.Schema, Root: opts.Swagger(), BasePath: opts.BasePath}) + if err != nil { + return fmt.Errorf("schema analysis [%s]: %v", key, err) + } + + if isAnalyzedAsComplex(asch) { // move complex schemas to definitions + if err := namer.Name(key, sch.Schema, asch); err != nil { + return err + } + } + } + } + return nil +} + +var depthGroupOrder = []string{ + "sharedParam", "sharedResponse", "sharedOpParam", "opParam", "codeResponse", "defaultResponse", "definition", +} + +func sortDepthFirst(data map[string]SchemaRef) []string { + // group by category (shared params, op param, statuscode response, default response, definitions) + // sort groups internally by number of parts in the key and lexical names + // flatten groups into a single list of keys + sorted := make([]string, 0, len(data)) + grouped := make(map[string]keys, len(data)) + for k := range data { + split := keyParts(k) + var pk string + if split.IsSharedOperationParam() { + pk = "sharedOpParam" + } + if split.IsOperationParam() { + pk = "opParam" + } + if split.IsStatusCodeResponse() { + pk = "codeResponse" + } + if split.IsDefaultResponse() { + pk = "defaultResponse" + } + if split.IsDefinition() { + pk = "definition" + } + if split.IsSharedParam() { + pk = "sharedParam" + } + if split.IsSharedResponse() { + pk = "sharedResponse" + } + grouped[pk] = append(grouped[pk], key{Segments: len(split), Key: k}) + } + + for _, pk := range depthGroupOrder { + res := grouped[pk] + sort.Sort(res) + for _, v := range res { + sorted = append(sorted, v.Key) + } + } + return sorted +} + +type key struct { + Segments int + Key string +} +type keys []key + +func (k keys) Len() int { return len(k) } +func (k keys) Swap(i, j int) { k[i], k[j] = k[j], k[i] } +func (k keys) Less(i, j int) bool { + return k[i].Segments > k[j].Segments || (k[i].Segments == k[j].Segments && k[i].Key < k[j].Key) +} + +type inlineSchemaNamer struct { + Spec *swspec.Swagger + Operations map[string]opRef + flattenContext *context + opts *FlattenOpts +} + +func opRefsByRef(oprefs map[string]opRef) map[string]opRef { + result := make(map[string]opRef, len(oprefs)) + for _, v := range oprefs { + result[v.Ref.String()] = v + } + return result +} + +func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *AnalyzedSchema) error { + debugLog("naming inlined schema at %s", key) + + parts := keyParts(key) + for _, name := range namesFromKey(parts, aschema, isn.Operations) { + if name != "" { + // create unique name + newName, isOAIGen := uniqifyName(isn.Spec.Definitions, swag.ToJSONName(name)) + + // clone schema + sch, err := cloneSchema(schema) + if err != nil { + return err + } + + // replace values on schema + if err := rewriteSchemaToRef(isn.Spec, key, + swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil { + return fmt.Errorf("error while creating definition %q from inline schema: %v", newName, err) + } + + // rewrite any dependent $ref pointing to this place, + // when not already pointing to a top-level definition. + // NOTE: this is important if such referers use arbitrary JSON pointers. + an := New(isn.Spec) + for k, v := range an.references.allRefs { + r, _, erd := deepestRef(isn.opts, v) + if erd != nil { + return fmt.Errorf("at %s, %v", k, erd) + } + if r.String() == key || + r.String() == slashpath.Join(definitionsPath, newName) && + slashpath.Dir(v.String()) != definitionsPath { + debugLog("found a $ref to a rewritten schema: %s points to %s", k, v.String()) + // rewrite $ref to the new target + if err := updateRef(isn.Spec, k, + swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil { + return err + } + } + } + + // NOTE: this extension is currently not used by go-swagger (provided for information only) + sch.AddExtension("x-go-gen-location", genLocation(parts)) + // save cloned schema to definitions + saveSchema(isn.Spec, newName, sch) + + // keep track of created refs + if isn.flattenContext != nil { + debugLog("track created ref: key=%s, newName=%s, isOAIGen=%t", key, newName, isOAIGen) + resolved := false + if _, ok := isn.flattenContext.newRefs[key]; ok { + resolved = isn.flattenContext.newRefs[key].resolved + } + isn.flattenContext.newRefs[key] = &newRef{ + key: key, + newName: newName, + path: slashpath.Join(definitionsPath, newName), + isOAIGen: isOAIGen, + resolved: resolved, + schema: sch, + } + } + } + } + return nil +} + +// genLocation indicates from which section of the specification (models or operations) a definition has been created. +// This is reflected in the output spec with a "x-go-gen-location" extension. At the moment, this is is provided +// for information only. +func genLocation(parts splitKey) string { + if parts.IsOperation() { + return "operations" + } + if parts.IsDefinition() { + return "models" + } + return "" +} + +func uniqifyName(definitions swspec.Definitions, name string) (string, bool) { + isOAIGen := false + if name == "" { + name = "oaiGen" + isOAIGen = true + } + if len(definitions) == 0 { + return name, isOAIGen + } + + unq := true + for k := range definitions { + if strings.ToLower(k) == strings.ToLower(name) { + unq = false + break + } + } + + if unq { + return name, isOAIGen + } + + name += "OAIGen" + isOAIGen = true + var idx int + unique := name + _, known := definitions[unique] + for known { + idx++ + unique = fmt.Sprintf("%s%d", name, idx) + _, known = definitions[unique] + } + return unique, isOAIGen +} + +func namesFromKey(parts splitKey, aschema *AnalyzedSchema, operations map[string]opRef) []string { + var baseNames [][]string + var startIndex int + if parts.IsOperation() { + // params + if parts.IsOperationParam() || parts.IsSharedOperationParam() { + piref := parts.PathItemRef() + if piref.String() != "" && parts.IsOperationParam() { + if op, ok := operations[piref.String()]; ok { + startIndex = 5 + baseNames = append(baseNames, []string{op.ID, "params", "body"}) + } + } else if parts.IsSharedOperationParam() { + pref := parts.PathRef() + for k, v := range operations { + if strings.HasPrefix(k, pref.String()) { + startIndex = 4 + baseNames = append(baseNames, []string{v.ID, "params", "body"}) + } + } + } + } + // responses + if parts.IsOperationResponse() { + piref := parts.PathItemRef() + if piref.String() != "" { + if op, ok := operations[piref.String()]; ok { + startIndex = 6 + baseNames = append(baseNames, []string{op.ID, parts.ResponseName(), "body"}) + } + } + } + } + + // definitions + if parts.IsDefinition() { + nm := parts.DefinitionName() + if nm != "" { + startIndex = 2 + baseNames = append(baseNames, []string{parts.DefinitionName()}) + } + } + + var result []string + for _, segments := range baseNames { + nm := parts.BuildName(segments, startIndex, aschema) + if nm != "" { + result = append(result, nm) + } + } + sort.Strings(result) + return result +} + +const ( + paths = "paths" + responses = "responses" + parameters = "parameters" + definitions = "definitions" + definitionsPath = "#/definitions" +) + +var ( + ignoredKeys map[string]struct{} + validMethods map[string]struct{} +) + +func init() { + ignoredKeys = map[string]struct{}{ + "schema": {}, + "properties": {}, + "not": {}, + "anyOf": {}, + "oneOf": {}, + } + + validMethods = map[string]struct{}{ + "GET": {}, + "HEAD": {}, + "OPTIONS": {}, + "PATCH": {}, + "POST": {}, + "PUT": {}, + "DELETE": {}, + } +} + +type splitKey []string + +func (s splitKey) IsDefinition() bool { + return len(s) > 1 && s[0] == definitions +} + +func (s splitKey) DefinitionName() string { + if !s.IsDefinition() { + return "" + } + return s[1] +} + +func (s splitKey) isKeyName(i int) bool { + if i <= 0 { + return false + } + count := 0 + for idx := i - 1; idx > 0; idx-- { + if s[idx] != "properties" { + break + } + count++ + } + + return count%2 != 0 +} + +func (s splitKey) BuildName(segments []string, startIndex int, aschema *AnalyzedSchema) string { + for i, part := range s[startIndex:] { + if _, ignored := ignoredKeys[part]; !ignored || s.isKeyName(startIndex+i) { + if part == "items" || part == "additionalItems" { + if aschema.IsTuple || aschema.IsTupleWithExtra { + segments = append(segments, "tuple") + } else { + segments = append(segments, "items") + } + if part == "additionalItems" { + segments = append(segments, part) + } + continue + } + segments = append(segments, part) + } + } + return strings.Join(segments, " ") +} + +func (s splitKey) IsOperation() bool { + return len(s) > 1 && s[0] == paths +} + +func (s splitKey) IsSharedOperationParam() bool { + return len(s) > 2 && s[0] == paths && s[2] == parameters +} + +func (s splitKey) IsSharedParam() bool { + return len(s) > 1 && s[0] == parameters +} + +func (s splitKey) IsOperationParam() bool { + return len(s) > 3 && s[0] == paths && s[3] == parameters +} + +func (s splitKey) IsOperationResponse() bool { + return len(s) > 3 && s[0] == paths && s[3] == responses +} + +func (s splitKey) IsSharedResponse() bool { + return len(s) > 1 && s[0] == responses +} + +func (s splitKey) IsDefaultResponse() bool { + return len(s) > 4 && s[0] == paths && s[3] == responses && s[4] == "default" +} + +func (s splitKey) IsStatusCodeResponse() bool { + isInt := func() bool { + _, err := strconv.Atoi(s[4]) + return err == nil + } + return len(s) > 4 && s[0] == paths && s[3] == responses && isInt() +} + +func (s splitKey) ResponseName() string { + if s.IsStatusCodeResponse() { + code, _ := strconv.Atoi(s[4]) + return http.StatusText(code) + } + if s.IsDefaultResponse() { + return "Default" + } + return "" +} + +func (s splitKey) PathItemRef() swspec.Ref { + if len(s) < 3 { + return swspec.Ref{} + } + pth, method := s[1], s[2] + if _, isValidMethod := validMethods[strings.ToUpper(method)]; !isValidMethod && !strings.HasPrefix(method, "x-") { + return swspec.Ref{} + } + return swspec.MustCreateRef("#" + slashpath.Join("/", paths, jsonpointer.Escape(pth), strings.ToUpper(method))) +} + +func (s splitKey) PathRef() swspec.Ref { + if !s.IsOperation() { + return swspec.Ref{} + } + return swspec.MustCreateRef("#" + slashpath.Join("/", paths, jsonpointer.Escape(s[1]))) +} + +func keyParts(key string) splitKey { + var res []string + for _, part := range strings.Split(key[1:], "/") { + if part != "" { + res = append(res, jsonpointer.Unescape(part)) + } + } + return res +} + +func rewriteSchemaToRef(spec *swspec.Swagger, key string, ref swspec.Ref) error { + debugLog("rewriting schema to ref for %s with %s", key, ref.String()) + _, value, err := getPointerFromKey(spec, key) + if err != nil { + return err + } + + switch refable := value.(type) { + case *swspec.Schema: + return rewriteParentRef(spec, key, ref) + + case swspec.Schema: + return rewriteParentRef(spec, key, ref) + + case *swspec.SchemaOrArray: + if refable.Schema != nil { + refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + } + + case *swspec.SchemaOrBool: + if refable.Schema != nil { + refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + } + default: + return fmt.Errorf("no schema with ref found at %s for %T", key, value) + } + + return nil +} + +func rewriteParentRef(spec *swspec.Swagger, key string, ref swspec.Ref) error { + parent, entry, pvalue, err := getParentFromKey(spec, key) + if err != nil { + return err + } + + debugLog("rewriting holder for %T", pvalue) + switch container := pvalue.(type) { + case swspec.Response: + if err := rewriteParentRef(spec, "#"+parent, ref); err != nil { + return err + } + + case *swspec.Response: + container.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case *swspec.Responses: + statusCode, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", key[1:], err) + } + resp := container.StatusCodeResponses[statusCode] + resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + container.StatusCodeResponses[statusCode] = resp + + case map[string]swspec.Response: + resp := container[entry] + resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + container[entry] = resp + + case swspec.Parameter: + if err := rewriteParentRef(spec, "#"+parent, ref); err != nil { + return err + } + + case map[string]swspec.Parameter: + param := container[entry] + param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + container[entry] = param + + case []swspec.Parameter: + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", key[1:], err) + } + param := container[idx] + param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + container[idx] = param + + case swspec.Definitions: + container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case map[string]swspec.Schema: + container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case []swspec.Schema: + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", key[1:], err) + } + container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case *swspec.SchemaOrArray: + // NOTE: this is necessarily an array - otherwise, the parent would be *Schema + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", key[1:], err) + } + container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + // NOTE: can't have case *swspec.SchemaOrBool = parent in this case is *Schema + + default: + return fmt.Errorf("unhandled parent schema rewrite %s (%T)", key, pvalue) + } + return nil +} + +func cloneSchema(schema *swspec.Schema) (*swspec.Schema, error) { + var sch swspec.Schema + if err := swag.FromDynamicJSON(schema, &sch); err != nil { + return nil, fmt.Errorf("cannot clone schema: %v", err) + } + return &sch, nil +} + +func importExternalReferences(opts *FlattenOpts) (bool, error) { + groupedRefs := reverseIndexForSchemaRefs(opts) + sortedRefStr := make([]string, 0, len(groupedRefs)) + if opts.flattenContext == nil { + opts.flattenContext = newContext() + } + + // sort $ref resolution to ensure deterministic name conflict resolution + for refStr := range groupedRefs { + sortedRefStr = append(sortedRefStr, refStr) + } + sort.Strings(sortedRefStr) + + complete := true + for _, refStr := range sortedRefStr { + entry := groupedRefs[refStr] + if !entry.Ref.HasFragmentOnly { + complete = false + var isOAIGen bool + + newName := opts.flattenContext.resolved[refStr] + if newName != "" { + // rewrite ref with already resolved external ref (useful for cyclicali refs) + debugLog("resolving known ref [%s] to %s", refStr, newName) + // rewrite the external refs to local ones + for _, key := range entry.Keys { + if err := updateRef(opts.Swagger(), key, + swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil { + return false, err + } + } + } else { + debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr) + + // resolve to actual schema + sch := new(swspec.Schema) + sch.Ref = entry.Ref + if err := swspec.ExpandSchemaWithBasePath(sch, nil, opts.ExpandOpts(false)); err != nil { + return false, err + } + if sch == nil { + return false, fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", ")) + } + debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr) + + // generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name + newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref)) + debugLog("new name for [%s]: %s - with name conflict:%t", + strings.Join(entry.Keys, ", "), newName, isOAIGen) + + opts.flattenContext.resolved[refStr] = newName + + // rewrite the external refs to local ones + for _, key := range entry.Keys { + if err := updateRef(opts.Swagger(), key, + swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil { + return false, err + } + + // keep track of created refs + resolved := false + if _, ok := opts.flattenContext.newRefs[key]; ok { + resolved = opts.flattenContext.newRefs[key].resolved + } + opts.flattenContext.newRefs[key] = &newRef{ + key: key, + newName: newName, + path: slashpath.Join(definitionsPath, newName), + isOAIGen: isOAIGen, + resolved: resolved, + schema: sch, + } + } + + // add the resolved schema to the definitions + saveSchema(opts.Swagger(), newName, sch) + } + } + } + return complete, nil +} + +type refRevIdx struct { + Ref swspec.Ref + Keys []string +} + +// normalizePath renders absolute path on remote file refs +func normalizePath(ref swspec.Ref, opts *FlattenOpts) (normalizedPath string) { + if ref.HasFragmentOnly || filepath.IsAbs(ref.String()) { + normalizedPath = ref.String() + return + } + + refURL, _ := url.Parse(ref.String()) + if refURL.Host != "" { + normalizedPath = ref.String() + return + } + + parts := strings.Split(ref.String(), "#") + parts[0] = filepath.Join(filepath.Dir(opts.BasePath), parts[0]) + normalizedPath = strings.Join(parts, "#") + return +} + +func reverseIndexForSchemaRefs(opts *FlattenOpts) map[string]refRevIdx { + collected := make(map[string]refRevIdx) + for key, schRef := range opts.Spec.references.schemas { + // normalize paths before sorting, + // so we get together keys in same external file + normalizedPath := normalizePath(schRef, opts) + if entry, ok := collected[normalizedPath]; ok { + entry.Keys = append(entry.Keys, key) + collected[normalizedPath] = entry + } else { + collected[normalizedPath] = refRevIdx{ + Ref: schRef, + Keys: []string{key}, + } + } + } + return collected +} + +func nameFromRef(ref swspec.Ref) string { + u := ref.GetURL() + if u.Fragment != "" { + return swag.ToJSONName(slashpath.Base(u.Fragment)) + } + if u.Path != "" { + bn := slashpath.Base(u.Path) + if bn != "" && bn != "/" { + ext := slashpath.Ext(bn) + if ext != "" { + return swag.ToJSONName(bn[:len(bn)-len(ext)]) + } + return swag.ToJSONName(bn) + } + } + return swag.ToJSONName(strings.Replace(u.Host, ".", " ", -1)) +} + +func saveSchema(spec *swspec.Swagger, name string, schema *swspec.Schema) { + if schema == nil { + return + } + if spec.Definitions == nil { + spec.Definitions = make(map[string]swspec.Schema, 150) + } + spec.Definitions[name] = *schema +} + +// getPointerFromKey retrieves the content of the JSON pointer "key" +func getPointerFromKey(spec *swspec.Swagger, key string) (string, interface{}, error) { + // unescape chars in key, e.g. "{}" from path params + pth, _ := internal.PathUnescape(key[1:]) + ptr, err := jsonpointer.New(pth) + if err != nil { + return "", nil, err + } + + value, _, err := ptr.Get(spec) + if err != nil { + debugLog("error when getting key: %s with path: %s", key, pth) + return "", nil, err + } + return pth, value, nil +} + +// getParentFromKey retrieves the container of the JSON pointer "key" +func getParentFromKey(spec *swspec.Swagger, key string) (string, string, interface{}, error) { + // unescape chars in key, e.g. "{}" from path params + pth, _ := internal.PathUnescape(key[1:]) + + parent, entry := slashpath.Dir(pth), slashpath.Base(pth) + debugLog("getting schema holder at: %s, with entry: %s", parent, entry) + + pptr, err := jsonpointer.New(parent) + if err != nil { + return "", "", nil, err + } + pvalue, _, err := pptr.Get(spec) + if err != nil { + return "", "", nil, fmt.Errorf("can't get parent for %s: %v", parent, err) + } + return parent, entry, pvalue, nil +} + +// updateRef replaces a ref by another one +func updateRef(spec *swspec.Swagger, key string, ref swspec.Ref) error { + debugLog("updating ref for %s with %s", key, ref.String()) + pth, value, err := getPointerFromKey(spec, key) + if err != nil { + return err + } + + switch refable := value.(type) { + case *swspec.Schema: + refable.Ref = ref + case *swspec.SchemaOrArray: + if refable.Schema != nil { + refable.Schema.Ref = ref + } + case *swspec.SchemaOrBool: + if refable.Schema != nil { + refable.Schema.Ref = ref + } + case swspec.Schema: + debugLog("rewriting holder for %T", refable) + _, entry, pvalue, erp := getParentFromKey(spec, key) + if erp != nil { + return err + } + switch container := pvalue.(type) { + case swspec.Definitions: + container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case map[string]swspec.Schema: + container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case []swspec.Schema: + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", pth, err) + } + container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + case *swspec.SchemaOrArray: + // NOTE: this is necessarily an array - otherwise, the parent would be *Schema + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", pth, err) + } + container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}} + + // NOTE: can't have case *swspec.SchemaOrBool = parent in this case is *Schema + + default: + return fmt.Errorf("unhandled container type at %s: %T", key, value) + } + + default: + return fmt.Errorf("no schema with ref found at %s for %T", key, value) + } + + return nil +} + +// updateRefWithSchema replaces a ref with a schema (i.e. re-inline schema) +func updateRefWithSchema(spec *swspec.Swagger, key string, sch *swspec.Schema) error { + debugLog("updating ref for %s with schema", key) + pth, value, err := getPointerFromKey(spec, key) + if err != nil { + return err + } + + switch refable := value.(type) { + case *swspec.Schema: + *refable = *sch + case swspec.Schema: + _, entry, pvalue, erp := getParentFromKey(spec, key) + if erp != nil { + return err + } + switch container := pvalue.(type) { + case swspec.Definitions: + container[entry] = *sch + + case map[string]swspec.Schema: + container[entry] = *sch + + case []swspec.Schema: + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", pth, err) + } + container[idx] = *sch + + case *swspec.SchemaOrArray: + // NOTE: this is necessarily an array - otherwise, the parent would be *Schema + idx, err := strconv.Atoi(entry) + if err != nil { + return fmt.Errorf("%s not a number: %v", pth, err) + } + container.Schemas[idx] = *sch + + // NOTE: can't have case *swspec.SchemaOrBool = parent in this case is *Schema + + default: + return fmt.Errorf("unhandled type for parent of [%s]: %T", key, value) + } + case *swspec.SchemaOrArray: + *refable.Schema = *sch + // NOTE: can't have case *swspec.SchemaOrBool = parent in this case is *Schema + case *swspec.SchemaOrBool: + *refable.Schema = *sch + default: + return fmt.Errorf("no schema with ref found at %s for %T", key, value) + } + + return nil +} + +func containsString(names []string, name string) bool { + for _, nm := range names { + if nm == name { + return true + } + } + return false +} + +type opRef struct { + Method string + Path string + Key string + ID string + Op *swspec.Operation + Ref swspec.Ref +} + +type opRefs []opRef + +func (o opRefs) Len() int { return len(o) } +func (o opRefs) Swap(i, j int) { o[i], o[j] = o[j], o[i] } +func (o opRefs) Less(i, j int) bool { return o[i].Key < o[j].Key } + +func gatherOperations(specDoc *Spec, operationIDs []string) map[string]opRef { + var oprefs opRefs + + for method, pathItem := range specDoc.Operations() { + for pth, operation := range pathItem { + vv := *operation + oprefs = append(oprefs, opRef{ + Key: swag.ToGoName(strings.ToLower(method) + " " + pth), + Method: method, + Path: pth, + ID: vv.ID, + Op: &vv, + Ref: swspec.MustCreateRef("#" + slashpath.Join("/paths", jsonpointer.Escape(pth), method)), + }) + } + } + + sort.Sort(oprefs) + + operations := make(map[string]opRef) + for _, opr := range oprefs { + nm := opr.ID + if nm == "" { + nm = opr.Key + } + + oo, found := operations[nm] + if found && oo.Method != opr.Method && oo.Path != opr.Path { + nm = opr.Key + } + if len(operationIDs) == 0 || containsString(operationIDs, opr.ID) || containsString(operationIDs, nm) { + opr.ID = nm + opr.Op.ID = nm + operations[nm] = opr + } + } + return operations +} + +// stripPointersAndOAIGen removes anonymous JSON pointers from spec and chain with name conflicts handler. +// This loops until the spec has no such pointer and all name conflicts have been reduced as much as possible. +func stripPointersAndOAIGen(opts *FlattenOpts) error { + // name all JSON pointers to anonymous documents + if err := namePointers(opts); err != nil { + return err + } + + // remove unnecessary OAIGen ref (created when flattening external refs creates name conflicts) + hasIntroducedPointerOrInline, ers := stripOAIGen(opts) + if ers != nil { + return ers + } + + // iterate as pointer or OAIGen resolution may introduce inline schemas or pointers + for hasIntroducedPointerOrInline { + if !opts.Minimal { + if err := nameInlinedSchemas(opts); err != nil { + return err + } + } + + if err := namePointers(opts); err != nil { + return err + } + + // restrip + if hasIntroducedPointerOrInline, ers = stripOAIGen(opts); ers != nil { + return ers + } + } + return nil +} + +// stripOAIGen strips the spec from unnecessary OAIGen constructs, initially created to dedupe flattened definitions. +// A dedupe is deemed unnecessary whenever: +// - the only conflict is with its (single) parent: OAIGen is merged into its parent +// - there is a conflict with multiple parents: merge OAIGen in first parent, the rewrite other parents to point to +// the first parent. +// +// This function returns a true bool whenever it re-inlined a complex schema, so the caller may chose to iterate +// flattening again. +// +// NOTE: the OAIGen definition cannot be itself a $ref. +func stripOAIGen(opts *FlattenOpts) (bool, error) { + debugLog("stripOAIGen") + replacedWithComplex := false + for k, v := range opts.Spec.references.allRefs { + // figure out referers of OAIGen definitions + for _, r := range opts.flattenContext.newRefs { + if r.isOAIGen && !r.resolved && r.path == v.String() { // bail on already resolved entries (avoid looping) + r.parents = append(r.parents, k) + } + } + } + + for _, r := range opts.flattenContext.newRefs { + if r.isOAIGen && len(r.parents) >= 1 && r.schema.Ref.String() == "" { + pr := r.parents + sort.Strings(pr) + // rewrite first parent schema in lexicographical order + debugLog("rewrite first parent %s with schema", pr[0]) + if err := updateRefWithSchema(opts.Swagger(), pr[0], r.schema); err != nil { + return false, err + } + // rewrite other parents to point to first parent + if len(pr) > 1 { + for _, p := range pr[1:] { + replacingRef := swspec.MustCreateRef(pr[0]) + // Set complex when replacing ref is an anonymous jsonpointer: further processing may be required + replacedWithComplex = replacedWithComplex || + slashpath.Dir(replacingRef.String()) != definitionsPath + debugLog("rewrite parent with ref: %s", replacingRef.String()) + // NOTE: it is possible at this stage to introduce json pointers (to non-definitions places). + // Those are stripped later on. + if err := updateRef(opts.Swagger(), p, replacingRef); err != nil { + return false, err + } + } + } + // remove OAIGen definition + debugLog("removing definition %s", slashpath.Base(r.path)) + delete(opts.Swagger().Definitions, slashpath.Base(r.path)) + // mark naming conflict as resolved + opts.flattenContext.newRefs[r.key].isOAIGen = false + opts.flattenContext.newRefs[r.key].resolved = true + + // determine if the previous substitution did inline a complex schema + if r.schema != nil && r.schema.Ref.String() == "" { // inline schema + asch, err := Schema(SchemaOpts{Schema: r.schema, Root: opts.Swagger(), BasePath: opts.BasePath}) + if err != nil { + return false, err + } + debugLog("re-inline schema: parent: %s, %t", pr[0], isAnalyzedAsComplex(asch)) + replacedWithComplex = replacedWithComplex || + !(slashpath.Dir(pr[0]) == definitionsPath) && isAnalyzedAsComplex(asch) + } + } + } + opts.Spec.reload() // re-analyze + return replacedWithComplex, nil +} + +// croak logs notifications and warnings about valid, but possibly unwanted constructs resulting +// from flattening a spec +func croak(opts *FlattenOpts) { + reported := make(map[string]bool, len(opts.flattenContext.newRefs)) + for _, v := range opts.Spec.references.allRefs { + // warns about duplicate handling + for _, r := range opts.flattenContext.newRefs { + if r.isOAIGen && r.path == v.String() { + reported[r.newName] = true + } + } + } + for k := range reported { + log.Printf("warning: duplicate flattened definition name resolved as %s", k) + } + // warns about possible type mismatches + uniqueMsg := make(map[string]bool) + for _, msg := range opts.flattenContext.warnings { + if _, ok := uniqueMsg[msg]; ok { + continue + } + log.Printf("warning: %s", msg) + uniqueMsg[msg] = true + } +} + +// namePointers replaces all JSON pointers to anonymous documents by a $ref to a new named definitions. +// +// This is carried on depth-first. Pointers to $refs which are top level definitions are replaced by the $ref itself. +// Pointers to simple types are expanded, unless they express commonality (i.e. several such $ref are used). +func namePointers(opts *FlattenOpts) error { + debugLog("name pointers") + refsToReplace := make(map[string]SchemaRef, len(opts.Spec.references.schemas)) + for k, ref := range opts.Spec.references.allRefs { + if slashpath.Dir(ref.String()) == definitionsPath { + // this a ref to a top-level definition: ok + continue + } + replacingRef, sch, erd := deepestRef(opts, ref) + if erd != nil { + return fmt.Errorf("at %s, %v", k, erd) + } + debugLog("planning pointer to replace at %s: %s, resolved to: %s", k, ref.String(), replacingRef.String()) + refsToReplace[k] = SchemaRef{ + Name: k, // caller + Ref: replacingRef, // callee + Schema: sch, + TopLevel: slashpath.Dir(replacingRef.String()) == definitionsPath, + } + } + depthFirst := sortDepthFirst(refsToReplace) + namer := &inlineSchemaNamer{ + Spec: opts.Swagger(), + Operations: opRefsByRef(gatherOperations(opts.Spec, nil)), + flattenContext: opts.flattenContext, + opts: opts, + } + + for _, key := range depthFirst { + v := refsToReplace[key] + // update current replacement, which may have been updated by previous changes of deeper elements + replacingRef, sch, erd := deepestRef(opts, v.Ref) + if erd != nil { + return fmt.Errorf("at %s, %v", key, erd) + } + v.Ref = replacingRef + v.Schema = sch + v.TopLevel = slashpath.Dir(replacingRef.String()) == definitionsPath + debugLog("replacing pointer at %s: resolved to: %s", key, v.Ref.String()) + + if v.TopLevel { + debugLog("replace pointer %s by canonical definition: %s", key, v.Ref.String()) + // if the schema is a $ref to a top level definition, just rewrite the pointer to this $ref + if err := updateRef(opts.Swagger(), key, v.Ref); err != nil { + return err + } + } else { + // this is a JSON pointer to an anonymous document (internal or external): + // create a definition for this schema when: + // - it is a complex schema + // - or it is pointed by more than one $ref (i.e. expresses commonality) + // otherwise, expand the pointer (single reference to a simple type) + // + // The named definition for this follows the target's key, not the caller's + debugLog("namePointers at %s for %s", key, v.Ref.String()) + + // qualify the expanded schema + asch, ers := Schema(SchemaOpts{Schema: v.Schema, Root: opts.Swagger(), BasePath: opts.BasePath}) + if ers != nil { + return fmt.Errorf("schema analysis [%s]: %v", key, ers) + } + callers := make([]string, 0, 64) + + debugLog("looking for callers") + an := New(opts.Swagger()) + for k, w := range an.references.allRefs { + r, _, erd := deepestRef(opts, w) + if erd != nil { + return fmt.Errorf("at %s, %v", key, erd) + } + if r.String() == v.Ref.String() { + callers = append(callers, k) + } + } + debugLog("callers for %s: %d", v.Ref.String(), len(callers)) + if len(callers) == 0 { + // has already been updated and resolved + continue + } + + parts := keyParts(v.Ref.String()) + debugLog("number of callers for %s: %d", v.Ref.String(), len(callers)) + // identifying edge case when the namer did nothing because we point to a non-schema object + // no definition is created and we expand the $ref for all callers + if (!asch.IsSimpleSchema || len(callers) > 1) && !parts.IsSharedParam() && !parts.IsSharedResponse() { + debugLog("replace JSON pointer at [%s] by definition: %s", key, v.Ref.String()) + if err := namer.Name(v.Ref.String(), v.Schema, asch); err != nil { + return err + } + + // regular case: we named the $ref as a definition, and we move all callers to this new $ref + for _, caller := range callers { + if caller != key { + // move $ref for next to resolve + debugLog("identified caller of %s at [%s]", v.Ref.String(), caller) + c := refsToReplace[caller] + c.Ref = v.Ref + refsToReplace[caller] = c + } + } + } else { + debugLog("expand JSON pointer for key=%s", key) + if err := updateRefWithSchema(opts.Swagger(), key, v.Schema); err != nil { + return err + } + // NOTE: there is no other caller to update + } + } + } + opts.Spec.reload() // re-analyze + return nil +} + +// deepestRef finds the first definition ref, from a cascade of nested refs which are not definitions. +// - if no definition is found, returns the deepest ref. +// - pointers to external files are expanded +// +// NOTE: all external $ref's are assumed to be already expanded at this stage. +func deepestRef(opts *FlattenOpts, ref swspec.Ref) (swspec.Ref, *swspec.Schema, error) { + if !ref.HasFragmentOnly { + // we found an external $ref, which is odd + // does nothing on external $refs + return ref, nil, nil + } + currentRef := ref + visited := make(map[string]bool, 64) +DOWNREF: + for currentRef.String() != "" { + if slashpath.Dir(currentRef.String()) == definitionsPath { + // this is a top-level definition: stop here and return this ref + return currentRef, nil, nil + } + if _, beenThere := visited[currentRef.String()]; beenThere { + return swspec.Ref{}, nil, + fmt.Errorf("cannot resolve cyclic chain of pointers under %s", currentRef.String()) + } + visited[currentRef.String()] = true + value, _, err := currentRef.GetPointer().Get(opts.Swagger()) + if err != nil { + return swspec.Ref{}, nil, err + } + switch refable := value.(type) { + case *swspec.Schema: + if refable.Ref.String() == "" { + break DOWNREF + } + currentRef = refable.Ref + + case swspec.Schema: + if refable.Ref.String() == "" { + break DOWNREF + } + currentRef = refable.Ref + + case *swspec.SchemaOrArray: + if refable.Schema == nil || refable.Schema != nil && refable.Schema.Ref.String() == "" { + break DOWNREF + } + currentRef = refable.Schema.Ref + + case *swspec.SchemaOrBool: + if refable.Schema == nil || refable.Schema != nil && refable.Schema.Ref.String() == "" { + break DOWNREF + } + currentRef = refable.Schema.Ref + + case swspec.Response: + // a pointer points to a schema initially marshalled in responses section... + // Attempt to convert this to a schema. If this fails, the spec is invalid + asJSON, _ := refable.MarshalJSON() + var asSchema swspec.Schema + err := asSchema.UnmarshalJSON(asJSON) + if err != nil { + return swspec.Ref{}, nil, + fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T", + currentRef.String(), value) + + } + opts.flattenContext.warnings = append(opts.flattenContext.warnings, + fmt.Sprintf("found $ref %q (response) interpreted as schema", currentRef.String())) + + if asSchema.Ref.String() == "" { + break DOWNREF + } + currentRef = asSchema.Ref + + case swspec.Parameter: + // a pointer points to a schema initially marshalled in parameters section... + // Attempt to convert this to a schema. If this fails, the spec is invalid + asJSON, _ := refable.MarshalJSON() + var asSchema swspec.Schema + err := asSchema.UnmarshalJSON(asJSON) + if err != nil { + return swspec.Ref{}, nil, + fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T", + currentRef.String(), value) + + } + opts.flattenContext.warnings = append(opts.flattenContext.warnings, + fmt.Sprintf("found $ref %q (parameter) interpreted as schema", currentRef.String())) + + if asSchema.Ref.String() == "" { + break DOWNREF + } + currentRef = asSchema.Ref + + default: + return swspec.Ref{}, nil, + fmt.Errorf("unhandled type to resolve JSON pointer %s. Expected a Schema, got: %T", + currentRef.String(), value) + + } + } + // assess what schema we're ending with + sch, erv := swspec.ResolveRefWithBase(opts.Swagger(), ¤tRef, opts.ExpandOpts(false)) + if erv != nil { + return swspec.Ref{}, nil, erv + } + if sch == nil { + return swspec.Ref{}, nil, fmt.Errorf("no schema found at %s", currentRef.String()) + } + return currentRef, sch, nil +} + +// normalizeRef strips the current file from any $ref. This works around issue go-openapi/spec#76: +// leading absolute file in $ref is stripped +func normalizeRef(opts *FlattenOpts) error { + debugLog("normalizeRef") + opts.Spec.reload() // re-analyze + for k, w := range opts.Spec.references.allRefs { + if strings.HasPrefix(w.String(), opts.BasePath+definitionsPath) { // may be a mix of / and \, depending on OS + // strip base path from definition + debugLog("stripping absolute path for: %s", w.String()) + if err := updateRef(opts.Swagger(), k, + swspec.MustCreateRef(slashpath.Join(definitionsPath, slashpath.Base(w.String())))); err != nil { + return err + } + } + } + opts.Spec.reload() // re-analyze + return nil +} diff --git a/vendor/github.com/go-openapi/analysis/go.mod b/vendor/github.com/go-openapi/analysis/go.mod new file mode 100644 index 000000000..95652cbe3 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/go.mod @@ -0,0 +1,13 @@ +module github.com/go-openapi/analysis + +require ( + github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect + github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect + github.com/go-openapi/errors v0.19.2 // indirect + github.com/go-openapi/jsonpointer v0.19.2 + github.com/go-openapi/loads v0.19.0 + github.com/go-openapi/spec v0.19.2 + github.com/go-openapi/strfmt v0.19.0 + github.com/go-openapi/swag v0.19.2 + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/github.com/go-openapi/analysis/go.sum b/vendor/github.com/go-openapi/analysis/go.sum new file mode 100644 index 000000000..5a8c0dbee --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/go.sum @@ -0,0 +1,79 @@ +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-openapi/analysis/internal/post_go18.go b/vendor/github.com/go-openapi/analysis/internal/post_go18.go new file mode 100644 index 000000000..f96f55c08 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/internal/post_go18.go @@ -0,0 +1,29 @@ +// +build go1.8 + +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 internal + +import "net/url" + +// PathUnescape provides url.PathUnescape(), with seamless +// go version support for pre-go1.8 +// +// TODO: this function is currently defined in go-openapi/swag, +// but unexported. We might chose to export it, or simple phase +// out pre-go1.8 support. +func PathUnescape(path string) (string, error) { + return url.PathUnescape(path) +} diff --git a/vendor/github.com/go-openapi/analysis/internal/pre_go18.go b/vendor/github.com/go-openapi/analysis/internal/pre_go18.go new file mode 100644 index 000000000..4cc644182 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/internal/pre_go18.go @@ -0,0 +1,29 @@ +// +build !go1.8 + +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 internal + +import "net/url" + +// PathUnescape provides url.PathUnescape(), with seamless +// go version support for pre-go1.8 +// +// TODO: this function is currently defined in go-openapi/swag, +// but unexported. We might chose to export it, or simple phase +// out pre-go1.8 support. +func PathUnescape(path string) (string, error) { + return url.QueryUnescape(path) +} diff --git a/vendor/github.com/go-openapi/analysis/mixin.go b/vendor/github.com/go-openapi/analysis/mixin.go new file mode 100644 index 000000000..49806b4f7 --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/mixin.go @@ -0,0 +1,334 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 analysis + +import ( + "fmt" + "reflect" + + "github.com/go-openapi/spec" +) + +// Mixin modifies the primary swagger spec by adding the paths and +// definitions from the mixin specs. Top level parameters and +// responses from the mixins are also carried over. Operation id +// collisions are avoided by appending "Mixin" but only if +// needed. +// +// The following parts of primary are never modified by merging: +// - Info +// - BasePath +// - Host +// - ExternalDocs +// +// Consider calling FixEmptyResponseDescriptions() on the modified primary +// if you read them from storage and they are valid to start with. +// +// Entries in "paths", "definitions", "parameters" and "responses" are +// added to the primary in the order of the given mixins. If the entry +// already exists in primary it is skipped with a warning message. +// +// The count of skipped entries (from collisions) is returned so any +// deviation from the number expected can flag a warning in your build +// scripts. Carefully review the collisions before accepting them; +// consider renaming things if possible. +// +// No key normalization takes place (paths, type defs, +// etc). Ensure they are canonical if your downstream tools do +// key normalization of any form. +// +// Merging schemes (http, https), and consumers/producers do not account for +// collisions. +func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string { + skipped := make([]string, 0, len(mixins)) + opIds := getOpIds(primary) + initPrimary(primary) + + for i, m := range mixins { + skipped = append(skipped, mergeConsumes(primary, m)...) + + skipped = append(skipped, mergeProduces(primary, m)...) + + skipped = append(skipped, mergeTags(primary, m)...) + + skipped = append(skipped, mergeSchemes(primary, m)...) + + skipped = append(skipped, mergeSecurityDefinitions(primary, m)...) + + skipped = append(skipped, mergeSecurityRequirements(primary, m)...) + + skipped = append(skipped, mergeDefinitions(primary, m)...) + + // merging paths requires a map of operationIDs to work with + skipped = append(skipped, mergePaths(primary, m, opIds, i)...) + + skipped = append(skipped, mergeParameters(primary, m)...) + + skipped = append(skipped, mergeResponses(primary, m)...) + } + return skipped +} + +// getOpIds extracts all the paths..operationIds from the given +// spec and returns them as the keys in a map with 'true' values. +func getOpIds(s *spec.Swagger) map[string]bool { + rv := make(map[string]bool) + if s.Paths == nil { + return rv + } + for _, v := range s.Paths.Paths { + piops := pathItemOps(v) + for _, op := range piops { + rv[op.ID] = true + } + } + return rv +} + +func pathItemOps(p spec.PathItem) []*spec.Operation { + var rv []*spec.Operation + rv = appendOp(rv, p.Get) + rv = appendOp(rv, p.Put) + rv = appendOp(rv, p.Post) + rv = appendOp(rv, p.Delete) + rv = appendOp(rv, p.Head) + rv = appendOp(rv, p.Patch) + return rv +} + +func appendOp(ops []*spec.Operation, op *spec.Operation) []*spec.Operation { + if op == nil { + return ops + } + return append(ops, op) +} + +func mergeSecurityDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for k, v := range m.SecurityDefinitions { + if _, exists := primary.SecurityDefinitions[k]; exists { + warn := fmt.Sprintf( + "SecurityDefinitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k) + skipped = append(skipped, warn) + continue + } + primary.SecurityDefinitions[k] = v + } + return +} + +func mergeSecurityRequirements(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for _, v := range m.Security { + found := false + for _, vv := range primary.Security { + if reflect.DeepEqual(v, vv) { + found = true + break + } + } + if found { + warn := fmt.Sprintf( + "Security requirement: '%v' already exists in primary or higher priority mixin, skipping\n", v) + skipped = append(skipped, warn) + continue + } + primary.Security = append(primary.Security, v) + } + return +} + +func mergeDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for k, v := range m.Definitions { + // assume name collisions represent IDENTICAL type. careful. + if _, exists := primary.Definitions[k]; exists { + warn := fmt.Sprintf( + "definitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k) + skipped = append(skipped, warn) + continue + } + primary.Definitions[k] = v + } + return +} + +func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIds map[string]bool, mixIndex int) (skipped []string) { + if m.Paths != nil { + for k, v := range m.Paths.Paths { + if _, exists := primary.Paths.Paths[k]; exists { + warn := fmt.Sprintf( + "paths entry '%v' already exists in primary or higher priority mixin, skipping\n", k) + skipped = append(skipped, warn) + continue + } + + // Swagger requires that operationIds be + // unique within a spec. If we find a + // collision we append "Mixin0" to the + // operatoinId we are adding, where 0 is mixin + // index. We assume that operationIds with + // all the proivded specs are already unique. + piops := pathItemOps(v) + for _, piop := range piops { + if opIds[piop.ID] { + piop.ID = fmt.Sprintf("%v%v%v", piop.ID, "Mixin", mixIndex) + } + opIds[piop.ID] = true + } + primary.Paths.Paths[k] = v + } + } + return +} + +func mergeParameters(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for k, v := range m.Parameters { + // could try to rename on conflict but would + // have to fix $refs in the mixin. Complain + // for now + if _, exists := primary.Parameters[k]; exists { + warn := fmt.Sprintf( + "top level parameters entry '%v' already exists in primary or higher priority mixin, skipping\n", k) + skipped = append(skipped, warn) + continue + } + primary.Parameters[k] = v + } + return +} + +func mergeResponses(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for k, v := range m.Responses { + // could try to rename on conflict but would + // have to fix $refs in the mixin. Complain + // for now + if _, exists := primary.Responses[k]; exists { + warn := fmt.Sprintf( + "top level responses entry '%v' already exists in primary or higher priority mixin, skipping\n", k) + skipped = append(skipped, warn) + continue + } + primary.Responses[k] = v + } + return +} + +func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for _, v := range m.Consumes { + found := false + for _, vv := range primary.Consumes { + if v == vv { + found = true + break + } + } + if found { + // no warning here: we just skip it + continue + } + primary.Consumes = append(primary.Consumes, v) + } + return +} + +func mergeProduces(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for _, v := range m.Produces { + found := false + for _, vv := range primary.Produces { + if v == vv { + found = true + break + } + } + if found { + // no warning here: we just skip it + continue + } + primary.Produces = append(primary.Produces, v) + } + return +} + +func mergeTags(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for _, v := range m.Tags { + found := false + for _, vv := range primary.Tags { + if v.Name == vv.Name { + found = true + break + } + } + if found { + warn := fmt.Sprintf( + "top level tags entry with name '%v' already exists in primary or higher priority mixin, skipping\n", v.Name) + skipped = append(skipped, warn) + continue + } + primary.Tags = append(primary.Tags, v) + } + return +} + +func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) { + for _, v := range m.Schemes { + found := false + for _, vv := range primary.Schemes { + if v == vv { + found = true + break + } + } + if found { + // no warning here: we just skip it + continue + } + primary.Schemes = append(primary.Schemes, v) + } + return +} + +func initPrimary(primary *spec.Swagger) { + if primary.SecurityDefinitions == nil { + primary.SecurityDefinitions = make(map[string]*spec.SecurityScheme) + } + if primary.Security == nil { + primary.Security = make([]map[string][]string, 0, 10) + } + if primary.Produces == nil { + primary.Produces = make([]string, 0, 10) + } + if primary.Consumes == nil { + primary.Consumes = make([]string, 0, 10) + } + if primary.Tags == nil { + primary.Tags = make([]spec.Tag, 0, 10) + } + if primary.Schemes == nil { + primary.Schemes = make([]string, 0, 10) + } + if primary.Paths == nil { + primary.Paths = &spec.Paths{Paths: make(map[string]spec.PathItem)} + } + if primary.Paths.Paths == nil { + primary.Paths.Paths = make(map[string]spec.PathItem) + } + if primary.Definitions == nil { + primary.Definitions = make(spec.Definitions) + } + if primary.Parameters == nil { + primary.Parameters = make(map[string]spec.Parameter) + } + if primary.Responses == nil { + primary.Responses = make(map[string]spec.Response) + } +} diff --git a/vendor/github.com/go-openapi/analysis/schema.go b/vendor/github.com/go-openapi/analysis/schema.go new file mode 100644 index 000000000..afbf932ff --- /dev/null +++ b/vendor/github.com/go-openapi/analysis/schema.go @@ -0,0 +1,240 @@ +package analysis + +import ( + "fmt" + + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +// SchemaOpts configures the schema analyzer +type SchemaOpts struct { + Schema *spec.Schema + Root interface{} + BasePath string + _ struct{} +} + +// Schema analysis, will classify the schema according to known +// patterns. +func Schema(opts SchemaOpts) (*AnalyzedSchema, error) { + if opts.Schema == nil { + return nil, fmt.Errorf("no schema to analyze") + } + + a := &AnalyzedSchema{ + schema: opts.Schema, + root: opts.Root, + basePath: opts.BasePath, + } + + a.initializeFlags() + a.inferKnownType() + a.inferEnum() + a.inferBaseType() + + if err := a.inferMap(); err != nil { + return nil, err + } + if err := a.inferArray(); err != nil { + return nil, err + } + + if err := a.inferTuple(); err != nil { + // NOTE(fredbi): currently, inferTuple() never returns an error + return nil, err + } + + if err := a.inferFromRef(); err != nil { + return nil, err + } + + a.inferSimpleSchema() + return a, nil +} + +// AnalyzedSchema indicates what the schema represents +type AnalyzedSchema struct { + schema *spec.Schema + root interface{} + basePath string + + hasProps bool + hasAllOf bool + hasItems bool + hasAdditionalProps bool + hasAdditionalItems bool + hasRef bool + + IsKnownType bool + IsSimpleSchema bool + IsArray bool + IsSimpleArray bool + IsMap bool + IsSimpleMap bool + IsExtendedObject bool + IsTuple bool + IsTupleWithExtra bool + IsBaseType bool + IsEnum bool +} + +// Inherits copies value fields from other onto this schema +func (a *AnalyzedSchema) inherits(other *AnalyzedSchema) { + if other == nil { + return + } + a.hasProps = other.hasProps + a.hasAllOf = other.hasAllOf + a.hasItems = other.hasItems + a.hasAdditionalItems = other.hasAdditionalItems + a.hasAdditionalProps = other.hasAdditionalProps + a.hasRef = other.hasRef + + a.IsKnownType = other.IsKnownType + a.IsSimpleSchema = other.IsSimpleSchema + a.IsArray = other.IsArray + a.IsSimpleArray = other.IsSimpleArray + a.IsMap = other.IsMap + a.IsSimpleMap = other.IsSimpleMap + a.IsExtendedObject = other.IsExtendedObject + a.IsTuple = other.IsTuple + a.IsTupleWithExtra = other.IsTupleWithExtra + a.IsBaseType = other.IsBaseType + a.IsEnum = other.IsEnum +} + +func (a *AnalyzedSchema) inferFromRef() error { + if a.hasRef { + sch := new(spec.Schema) + sch.Ref = a.schema.Ref + err := spec.ExpandSchema(sch, a.root, nil) + if err != nil { + return err + } + if sch != nil { + // NOTE(fredbi): currently the only cause for errors in + // unresolved ref. Since spec.ExpandSchema() expands the + // schema recursively, there is no chance to get there, + // until we add more causes for error in this schema analysis. + rsch, err := Schema(SchemaOpts{ + Schema: sch, + Root: a.root, + BasePath: a.basePath, + }) + if err != nil { + return err + } + a.inherits(rsch) + } + } + return nil +} + +func (a *AnalyzedSchema) inferSimpleSchema() { + a.IsSimpleSchema = a.IsKnownType || a.IsSimpleArray || a.IsSimpleMap +} + +func (a *AnalyzedSchema) inferKnownType() { + tpe := a.schema.Type + format := a.schema.Format + a.IsKnownType = tpe.Contains("boolean") || + tpe.Contains("integer") || + tpe.Contains("number") || + tpe.Contains("string") || + (format != "" && strfmt.Default.ContainsName(format)) || + (a.isObjectType() && !a.hasProps && !a.hasAllOf && !a.hasAdditionalProps && !a.hasAdditionalItems) +} + +func (a *AnalyzedSchema) inferMap() error { + if a.isObjectType() { + hasExtra := a.hasProps || a.hasAllOf + a.IsMap = a.hasAdditionalProps && !hasExtra + a.IsExtendedObject = a.hasAdditionalProps && hasExtra + if a.IsMap { + if a.schema.AdditionalProperties.Schema != nil { + msch, err := Schema(SchemaOpts{ + Schema: a.schema.AdditionalProperties.Schema, + Root: a.root, + BasePath: a.basePath, + }) + if err != nil { + return err + } + a.IsSimpleMap = msch.IsSimpleSchema + } else if a.schema.AdditionalProperties.Allows { + a.IsSimpleMap = true + } + } + } + return nil +} + +func (a *AnalyzedSchema) inferArray() error { + // an array has Items defined as an object schema, otherwise we qualify this JSON array as a tuple + // (yes, even if the Items array contains only one element). + // arrays in JSON schema may be unrestricted (i.e no Items specified). + // Note that arrays in Swagger MUST have Items. Nonetheless, we analyze unrestricted arrays. + // + // NOTE: the spec package misses the distinction between: + // items: [] and items: {}, so we consider both arrays here. + a.IsArray = a.isArrayType() && (a.schema.Items == nil || a.schema.Items.Schemas == nil) + if a.IsArray && a.hasItems { + if a.schema.Items.Schema != nil { + itsch, err := Schema(SchemaOpts{ + Schema: a.schema.Items.Schema, + Root: a.root, + BasePath: a.basePath, + }) + if err != nil { + return err + } + a.IsSimpleArray = itsch.IsSimpleSchema + } + } + if a.IsArray && !a.hasItems { + a.IsSimpleArray = true + } + return nil +} + +func (a *AnalyzedSchema) inferTuple() error { + tuple := a.hasItems && a.schema.Items.Schemas != nil + a.IsTuple = tuple && !a.hasAdditionalItems + a.IsTupleWithExtra = tuple && a.hasAdditionalItems + return nil +} + +func (a *AnalyzedSchema) inferBaseType() { + if a.isObjectType() { + a.IsBaseType = a.schema.Discriminator != "" + } +} + +func (a *AnalyzedSchema) inferEnum() { + a.IsEnum = len(a.schema.Enum) > 0 +} + +func (a *AnalyzedSchema) initializeFlags() { + a.hasProps = len(a.schema.Properties) > 0 + a.hasAllOf = len(a.schema.AllOf) > 0 + a.hasRef = a.schema.Ref.String() != "" + + a.hasItems = a.schema.Items != nil && + (a.schema.Items.Schema != nil || len(a.schema.Items.Schemas) > 0) + + a.hasAdditionalProps = a.schema.AdditionalProperties != nil && + (a.schema.AdditionalProperties != nil || a.schema.AdditionalProperties.Allows) + + a.hasAdditionalItems = a.schema.AdditionalItems != nil && + (a.schema.AdditionalItems.Schema != nil || a.schema.AdditionalItems.Allows) + +} + +func (a *AnalyzedSchema) isObjectType() bool { + return !a.hasRef && (a.schema.Type == nil || a.schema.Type.Contains("") || a.schema.Type.Contains("object")) +} + +func (a *AnalyzedSchema) isArrayType() bool { + return !a.hasRef && (a.schema.Type != nil && a.schema.Type.Contains("array")) +} diff --git a/vendor/github.com/go-openapi/loads/.editorconfig b/vendor/github.com/go-openapi/loads/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/loads/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/loads/.gitignore b/vendor/github.com/go-openapi/loads/.gitignore new file mode 100644 index 000000000..e4f15f17b --- /dev/null +++ b/vendor/github.com/go-openapi/loads/.gitignore @@ -0,0 +1,4 @@ +secrets.yml +coverage.out +profile.cov +profile.out diff --git a/vendor/github.com/go-openapi/loads/.golangci.yml b/vendor/github.com/go-openapi/loads/.golangci.yml new file mode 100644 index 000000000..1932914e6 --- /dev/null +++ b/vendor/github.com/go-openapi/loads/.golangci.yml @@ -0,0 +1,22 @@ +linters-settings: + govet: + check-shadowing: true + golint: + min-confidence: 0 + gocyclo: + min-complexity: 30 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 4 + +linters: + enable-all: true + disable: + - maligned + - lll + - gochecknoglobals + - gochecknoinits diff --git a/vendor/github.com/go-openapi/loads/.travis.yml b/vendor/github.com/go-openapi/loads/.travis.yml new file mode 100644 index 000000000..8a7e05d91 --- /dev/null +++ b/vendor/github.com/go-openapi/loads/.travis.yml @@ -0,0 +1,15 @@ +after_success: +- bash <(curl -s https://codecov.io/bash) +go: +- 1.11.x +- 1.12.x +install: +- GO111MODULE=off go get -u gotest.tools/gotestsum +env: +- GO111MODULE=on +language: go +notifications: + slack: + secure: OxkPwVp35qBTUilgWC8xykSj+sGMcj0h8IIOKD+Rflx2schZVlFfdYdyVBM+s9OqeOfvtuvnR9v1Ye2rPKAvcjWdC4LpRGUsgmItZaI6Um8Aj6+K9udCw5qrtZVfOVmRu8LieH//XznWWKdOultUuniW0MLqw5+II87Gd00RWbCGi0hk0PykHe7uK+PDA2BEbqyZ2WKKYCvfB3j+0nrFOHScXqnh0V05l2E83J4+Sgy1fsPy+1WdX58ZlNBG333ibaC1FS79XvKSmTgKRkx3+YBo97u6ZtUmJa5WZjf2OdLG3KIckGWAv6R5xgxeU31N0Ng8L332w/Edpp2O/M2bZwdnKJ8hJQikXIAQbICbr+lTDzsoNzMdEIYcHpJ5hjPbiUl3Bmd+Jnsjf5McgAZDiWIfpCKZ29tPCEkVwRsOCqkyPRMNMzHHmoja495P5jR+ODS7+J8RFg5xgcnOgpP9D4Wlhztlf5WyZMpkLxTUD+bZq2SRf50HfHFXTkfq22zPl3d1eq0yrLwh/Z/fWKkfb6SyysROL8y6s8u3dpFX1YHSg0BR6i913h4aoZw9B2BG27cafLLTwKYsp2dFo1PWl4O6u9giFJIeqwloZHLKKrwh0cBFhB7RH0I58asxkZpCH6uWjJierahmHe7iS+E6i+9oCHkOZ59hmCYNimIs3hM= +script: +- gotestsum -f short-verbose -- -race -timeout=20m -coverprofile=coverage.txt -covermode=atomic ./... diff --git a/vendor/github.com/go-openapi/loads/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/loads/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/loads/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/loads/LICENSE b/vendor/github.com/go-openapi/loads/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/loads/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/vendor/github.com/go-openapi/loads/README.md b/vendor/github.com/go-openapi/loads/README.md new file mode 100644 index 000000000..071cf69ab --- /dev/null +++ b/vendor/github.com/go-openapi/loads/README.md @@ -0,0 +1,7 @@ +# Loads OAI specs [![Build Status](https://travis-ci.org/go-openapi/loads.svg?branch=master)](https://travis-ci.org/go-openapi/loads) [![codecov](https://codecov.io/gh/go-openapi/loads/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/loads) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/loads/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/loads?status.svg)](http://godoc.org/github.com/go-openapi/loads) +[![GolangCI](https://golangci.com/badges/github.com/go-openapi/loads.svg)](https://golangci.com) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/loads)](https://goreportcard.com/report/github.com/go-openapi/loads) + +Loading of OAI specification documents from local or remote locations. Supports JSON and YAML documents. diff --git a/vendor/github.com/go-openapi/loads/doc.go b/vendor/github.com/go-openapi/loads/doc.go new file mode 100644 index 000000000..3046da4ce --- /dev/null +++ b/vendor/github.com/go-openapi/loads/doc.go @@ -0,0 +1,21 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 loads provides document loading methods for swagger (OAI) specifications. + +It is used by other go-openapi packages to load and run analysis on local or remote spec documents. + +*/ +package loads diff --git a/vendor/github.com/go-openapi/loads/go.mod b/vendor/github.com/go-openapi/loads/go.mod new file mode 100644 index 000000000..e83c6ec30 --- /dev/null +++ b/vendor/github.com/go-openapi/loads/go.mod @@ -0,0 +1,9 @@ +module github.com/go-openapi/loads + +require ( + github.com/go-openapi/analysis v0.19.2 + github.com/go-openapi/spec v0.19.2 + github.com/go-openapi/swag v0.19.2 + github.com/stretchr/testify v1.3.0 + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/vendor/github.com/go-openapi/loads/go.sum b/vendor/github.com/go-openapi/loads/go.sum new file mode 100644 index 000000000..b0658b2cd --- /dev/null +++ b/vendor/github.com/go-openapi/loads/go.sum @@ -0,0 +1,79 @@ +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU= +github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-openapi/loads/spec.go b/vendor/github.com/go-openapi/loads/spec.go new file mode 100644 index 000000000..e4b4a3cf7 --- /dev/null +++ b/vendor/github.com/go-openapi/loads/spec.go @@ -0,0 +1,298 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 loads + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "fmt" + "net/url" + + "github.com/go-openapi/analysis" + "github.com/go-openapi/spec" + "github.com/go-openapi/swag" +) + +// JSONDoc loads a json document from either a file or a remote url +func JSONDoc(path string) (json.RawMessage, error) { + data, err := swag.LoadFromFileOrHTTP(path) + if err != nil { + return nil, err + } + return json.RawMessage(data), nil +} + +// DocLoader represents a doc loader type +type DocLoader func(string) (json.RawMessage, error) + +// DocMatcher represents a predicate to check if a loader matches +type DocMatcher func(string) bool + +var ( + loaders *loader + defaultLoader *loader +) + +func init() { + defaultLoader = &loader{Match: func(_ string) bool { return true }, Fn: JSONDoc} + loaders = defaultLoader + spec.PathLoader = loaders.Fn + AddLoader(swag.YAMLMatcher, swag.YAMLDoc) + + gob.Register(map[string]interface{}{}) + gob.Register([]interface{}{}) + //gob.Register(spec.Refable{}) +} + +// AddLoader for a document +func AddLoader(predicate DocMatcher, load DocLoader) { + prev := loaders + loaders = &loader{ + Match: predicate, + Fn: load, + Next: prev, + } + spec.PathLoader = loaders.Fn +} + +type loader struct { + Fn DocLoader + Match DocMatcher + Next *loader +} + +// JSONSpec loads a spec from a json document +func JSONSpec(path string) (*Document, error) { + data, err := JSONDoc(path) + if err != nil { + return nil, err + } + // convert to json + return Analyzed(data, "") +} + +// Document represents a swagger spec document +type Document struct { + // specAnalyzer + Analyzer *analysis.Spec + spec *spec.Swagger + specFilePath string + origSpec *spec.Swagger + schema *spec.Schema + raw json.RawMessage +} + +// Embedded returns a Document based on embedded specs. No analysis is required +func Embedded(orig, flat json.RawMessage) (*Document, error) { + var origSpec, flatSpec spec.Swagger + if err := json.Unmarshal(orig, &origSpec); err != nil { + return nil, err + } + if err := json.Unmarshal(flat, &flatSpec); err != nil { + return nil, err + } + return &Document{ + raw: orig, + origSpec: &origSpec, + spec: &flatSpec, + }, nil +} + +// Spec loads a new spec document +func Spec(path string) (*Document, error) { + specURL, err := url.Parse(path) + if err != nil { + return nil, err + } + var lastErr error + for l := loaders.Next; l != nil; l = l.Next { + if loaders.Match(specURL.Path) { + b, err2 := loaders.Fn(path) + if err2 != nil { + lastErr = err2 + continue + } + doc, err3 := Analyzed(b, "") + if err3 != nil { + return nil, err3 + } + if doc != nil { + doc.specFilePath = path + } + return doc, nil + } + } + if lastErr != nil { + return nil, lastErr + } + b, err := defaultLoader.Fn(path) + if err != nil { + return nil, err + } + + document, err := Analyzed(b, "") + if document != nil { + document.specFilePath = path + } + + return document, err +} + +// Analyzed creates a new analyzed spec document +func Analyzed(data json.RawMessage, version string) (*Document, error) { + if version == "" { + version = "2.0" + } + if version != "2.0" { + return nil, fmt.Errorf("spec version %q is not supported", version) + } + + raw := data + trimmed := bytes.TrimSpace(data) + if len(trimmed) > 0 { + if trimmed[0] != '{' && trimmed[0] != '[' { + yml, err := swag.BytesToYAMLDoc(trimmed) + if err != nil { + return nil, fmt.Errorf("analyzed: %v", err) + } + d, err := swag.YAMLToJSON(yml) + if err != nil { + return nil, fmt.Errorf("analyzed: %v", err) + } + raw = d + } + } + + swspec := new(spec.Swagger) + if err := json.Unmarshal(raw, swspec); err != nil { + return nil, err + } + + origsqspec, err := cloneSpec(swspec) + if err != nil { + return nil, err + } + + d := &Document{ + Analyzer: analysis.New(swspec), + schema: spec.MustLoadSwagger20Schema(), + spec: swspec, + raw: raw, + origSpec: origsqspec, + } + return d, nil +} + +// Expanded expands the ref fields in the spec document and returns a new spec document +func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) { + swspec := new(spec.Swagger) + if err := json.Unmarshal(d.raw, swspec); err != nil { + return nil, err + } + + var expandOptions *spec.ExpandOptions + if len(options) > 0 { + expandOptions = options[0] + } else { + expandOptions = &spec.ExpandOptions{ + RelativeBase: d.specFilePath, + } + } + + if err := spec.ExpandSpec(swspec, expandOptions); err != nil { + return nil, err + } + + dd := &Document{ + Analyzer: analysis.New(swspec), + spec: swspec, + specFilePath: d.specFilePath, + schema: spec.MustLoadSwagger20Schema(), + raw: d.raw, + origSpec: d.origSpec, + } + return dd, nil +} + +// BasePath the base path for this spec +func (d *Document) BasePath() string { + return d.spec.BasePath +} + +// Version returns the version of this spec +func (d *Document) Version() string { + return d.spec.Swagger +} + +// Schema returns the swagger 2.0 schema +func (d *Document) Schema() *spec.Schema { + return d.schema +} + +// Spec returns the swagger spec object model +func (d *Document) Spec() *spec.Swagger { + return d.spec +} + +// Host returns the host for the API +func (d *Document) Host() string { + return d.spec.Host +} + +// Raw returns the raw swagger spec as json bytes +func (d *Document) Raw() json.RawMessage { + return d.raw +} + +// OrigSpec yields the original spec +func (d *Document) OrigSpec() *spec.Swagger { + return d.origSpec +} + +// ResetDefinitions gives a shallow copy with the models reset +func (d *Document) ResetDefinitions() *Document { + defs := make(map[string]spec.Schema, len(d.origSpec.Definitions)) + for k, v := range d.origSpec.Definitions { + defs[k] = v + } + + d.spec.Definitions = defs + return d +} + +// Pristine creates a new pristine document instance based on the input data +func (d *Document) Pristine() *Document { + dd, _ := Analyzed(d.Raw(), d.Version()) + return dd +} + +// SpecFilePath returns the file path of the spec if one is defined +func (d *Document) SpecFilePath() string { + return d.specFilePath +} + +func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) { + var b bytes.Buffer + if err := gob.NewEncoder(&b).Encode(src); err != nil { + return nil, err + } + + var dst spec.Swagger + if err := gob.NewDecoder(&b).Decode(&dst); err != nil { + return nil, err + } + return &dst, nil +} diff --git a/vendor/github.com/go-openapi/runtime/.editorconfig b/vendor/github.com/go-openapi/runtime/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/runtime/.gitignore b/vendor/github.com/go-openapi/runtime/.gitignore new file mode 100644 index 000000000..fea8b84ec --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/.gitignore @@ -0,0 +1,5 @@ +secrets.yml +coverage.out +*.cov +*.out +playground diff --git a/vendor/github.com/go-openapi/runtime/.travis.yml b/vendor/github.com/go-openapi/runtime/.travis.yml new file mode 100644 index 000000000..87228c6c2 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/.travis.yml @@ -0,0 +1,23 @@ +after_success: +- bash <(curl -s https://codecov.io/bash) +go: +- 1.11.x +- 1.12.x +install: +- go get -u github.com/axw/gocov/gocov +- go get -u gopkg.in/matm/v1/gocov-html +- go get -u github.com/cee-dub/go-junit-report +- go get -u github.com/stretchr/testify/assert +- go get -u gopkg.in/yaml.v2 +- go get -u github.com/go-openapi/analysis +- go get -u github.com/go-openapi/errors +- go get -u github.com/go-openapi/loads +- go get -u github.com/go-openapi/strfmt +- go get -u github.com/go-openapi/validate +- go get -u github.com/docker/go-units +language: go +notifications: + slack: + secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA= +script: +- ./hack/coverage diff --git a/vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/runtime/LICENSE b/vendor/github.com/go-openapi/runtime/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/vendor/github.com/go-openapi/runtime/README.md b/vendor/github.com/go-openapi/runtime/README.md new file mode 100644 index 000000000..5b1ec6494 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/README.md @@ -0,0 +1,7 @@ +# runtime [![Build Status](https://travis-ci.org/go-openapi/runtime.svg?branch=client-context)](https://travis-ci.org/go-openapi/runtime) [![codecov](https://codecov.io/gh/go-openapi/runtime/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/runtime) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/runtime?status.svg)](http://godoc.org/github.com/go-openapi/runtime) + +# golang Open-API toolkit - runtime + +The runtime component for use in codegeneration or as untyped usage. diff --git a/vendor/github.com/go-openapi/runtime/bytestream.go b/vendor/github.com/go-openapi/runtime/bytestream.go new file mode 100644 index 000000000..9845e10cf --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/bytestream.go @@ -0,0 +1,151 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "bytes" + "encoding" + "errors" + "fmt" + "io" + "reflect" + + "github.com/go-openapi/swag" +) + +func defaultCloser() error { return nil } + +type byteStreamOpt func(opts *byteStreamOpts) + +// ClosesStream when the bytestream consumer or producer is finished +func ClosesStream(opts *byteStreamOpts) { + opts.Close = true +} + +type byteStreamOpts struct { + Close bool +} + +// ByteStreamConsumer creates a consmer for byte streams, +// takes a Writer/BinaryUnmarshaler interface or binary slice by reference, +// and reads from the provided reader +func ByteStreamConsumer(opts ...byteStreamOpt) Consumer { + var vals byteStreamOpts + for _, opt := range opts { + opt(&vals) + } + + return ConsumerFunc(func(reader io.Reader, data interface{}) error { + if reader == nil { + return errors.New("ByteStreamConsumer requires a reader") // early exit + } + + close := defaultCloser + if vals.Close { + if cl, ok := reader.(io.Closer); ok { + close = cl.Close + } + } + defer close() + + if wrtr, ok := data.(io.Writer); ok { + _, err := io.Copy(wrtr, reader) + return err + } + + buf := new(bytes.Buffer) + _, err := buf.ReadFrom(reader) + if err != nil { + return err + } + b := buf.Bytes() + + if bu, ok := data.(encoding.BinaryUnmarshaler); ok { + return bu.UnmarshalBinary(b) + } + + if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr { + v := reflect.Indirect(reflect.ValueOf(data)) + if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { + v.SetBytes(b) + return nil + } + } + + return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s", + data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface") + }) +} + +// ByteStreamProducer creates a producer for byte streams, +// takes a Reader/BinaryMarshaler interface or binary slice, +// and writes to a writer (essentially a pipe) +func ByteStreamProducer(opts ...byteStreamOpt) Producer { + var vals byteStreamOpts + for _, opt := range opts { + opt(&vals) + } + return ProducerFunc(func(writer io.Writer, data interface{}) error { + if writer == nil { + return errors.New("ByteStreamProducer requires a writer") // early exit + } + close := defaultCloser + if vals.Close { + if cl, ok := writer.(io.Closer); ok { + close = cl.Close + } + } + defer close() + + if rdr, ok := data.(io.Reader); ok { + _, err := io.Copy(writer, rdr) + return err + } + + if bm, ok := data.(encoding.BinaryMarshaler); ok { + bytes, err := bm.MarshalBinary() + if err != nil { + return err + } + + _, err = writer.Write(bytes) + return err + } + + if data != nil { + if e, ok := data.(error); ok { + _, err := writer.Write([]byte(e.Error())) + return err + } + + v := reflect.Indirect(reflect.ValueOf(data)) + if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { + _, err := writer.Write(v.Bytes()) + return err + } + if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice { + b, err := swag.WriteJSON(data) + if err != nil { + return err + } + _, err = writer.Write(b) + return err + } + } + + return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s", + data, data, "can be resolved by supporting Reader/BinaryMarshaler interface") + }) +} diff --git a/vendor/github.com/go-openapi/runtime/client_auth_info.go b/vendor/github.com/go-openapi/runtime/client_auth_info.go new file mode 100644 index 000000000..c6c97d9a7 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/client_auth_info.go @@ -0,0 +1,30 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import "github.com/go-openapi/strfmt" + +// A ClientAuthInfoWriterFunc converts a function to a request writer interface +type ClientAuthInfoWriterFunc func(ClientRequest, strfmt.Registry) error + +// AuthenticateRequest adds authentication data to the request +func (fn ClientAuthInfoWriterFunc) AuthenticateRequest(req ClientRequest, reg strfmt.Registry) error { + return fn(req, reg) +} + +// A ClientAuthInfoWriter implementor knows how to write authentication info to a request +type ClientAuthInfoWriter interface { + AuthenticateRequest(ClientRequest, strfmt.Registry) error +} diff --git a/vendor/github.com/go-openapi/runtime/client_operation.go b/vendor/github.com/go-openapi/runtime/client_operation.go new file mode 100644 index 000000000..fa21eacf3 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/client_operation.go @@ -0,0 +1,41 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "context" + "net/http" +) + +// ClientOperation represents the context for a swagger operation to be submitted to the transport +type ClientOperation struct { + ID string + Method string + PathPattern string + ProducesMediaTypes []string + ConsumesMediaTypes []string + Schemes []string + AuthInfo ClientAuthInfoWriter + Params ClientRequestWriter + Reader ClientResponseReader + Context context.Context + Client *http.Client +} + +// A ClientTransport implementor knows how to submit Request objects to some destination +type ClientTransport interface { + //Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error) + Submit(*ClientOperation) (interface{}, error) +} diff --git a/vendor/github.com/go-openapi/runtime/client_request.go b/vendor/github.com/go-openapi/runtime/client_request.go new file mode 100644 index 000000000..904196ae3 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/client_request.go @@ -0,0 +1,103 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "io" + "io/ioutil" + "net/http" + "net/url" + "time" + + "github.com/go-openapi/strfmt" +) + +// ClientRequestWriterFunc converts a function to a request writer interface +type ClientRequestWriterFunc func(ClientRequest, strfmt.Registry) error + +// WriteToRequest adds data to the request +func (fn ClientRequestWriterFunc) WriteToRequest(req ClientRequest, reg strfmt.Registry) error { + return fn(req, reg) +} + +// ClientRequestWriter is an interface for things that know how to write to a request +type ClientRequestWriter interface { + WriteToRequest(ClientRequest, strfmt.Registry) error +} + +// ClientRequest is an interface for things that know how to +// add information to a swagger client request +type ClientRequest interface { + SetHeaderParam(string, ...string) error + + GetHeaderParams() http.Header + + SetQueryParam(string, ...string) error + + SetFormParam(string, ...string) error + + SetPathParam(string, string) error + + GetQueryParams() url.Values + + SetFileParam(string, ...NamedReadCloser) error + + SetBodyParam(interface{}) error + + SetTimeout(time.Duration) error + + GetMethod() string + + GetPath() string + + GetBody() []byte + + GetBodyParam() interface{} + + GetFileParam() map[string][]NamedReadCloser +} + +// NamedReadCloser represents a named ReadCloser interface +type NamedReadCloser interface { + io.ReadCloser + Name() string +} + +// NamedReader creates a NamedReadCloser for use as file upload +func NamedReader(name string, rdr io.Reader) NamedReadCloser { + rc, ok := rdr.(io.ReadCloser) + if !ok { + rc = ioutil.NopCloser(rdr) + } + return &namedReadCloser{ + name: name, + cr: rc, + } +} + +type namedReadCloser struct { + name string + cr io.ReadCloser +} + +func (n *namedReadCloser) Close() error { + return n.cr.Close() +} +func (n *namedReadCloser) Read(p []byte) (int, error) { + return n.cr.Read(p) +} +func (n *namedReadCloser) Name() string { + return n.name +} diff --git a/vendor/github.com/go-openapi/runtime/client_response.go b/vendor/github.com/go-openapi/runtime/client_response.go new file mode 100644 index 000000000..729e18b22 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/client_response.go @@ -0,0 +1,63 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "fmt" + "io" +) + +// A ClientResponse represents a client response +// This bridges between responses obtained from different transports +type ClientResponse interface { + Code() int + Message() string + GetHeader(string) string + Body() io.ReadCloser +} + +// A ClientResponseReaderFunc turns a function into a ClientResponseReader interface implementation +type ClientResponseReaderFunc func(ClientResponse, Consumer) (interface{}, error) + +// ReadResponse reads the response +func (read ClientResponseReaderFunc) ReadResponse(resp ClientResponse, consumer Consumer) (interface{}, error) { + return read(resp, consumer) +} + +// A ClientResponseReader is an interface for things want to read a response. +// An application of this is to create structs from response values +type ClientResponseReader interface { + ReadResponse(ClientResponse, Consumer) (interface{}, error) +} + +// NewAPIError creates a new API error +func NewAPIError(opName string, payload interface{}, code int) *APIError { + return &APIError{ + OperationName: opName, + Response: payload, + Code: code, + } +} + +// APIError wraps an error model and captures the status code +type APIError struct { + OperationName string + Response interface{} + Code int +} + +func (a *APIError) Error() string { + return fmt.Sprintf("%s (status %d): %+v ", a.OperationName, a.Code, a.Response) +} diff --git a/vendor/github.com/go-openapi/runtime/constants.go b/vendor/github.com/go-openapi/runtime/constants.go new file mode 100644 index 000000000..a4de897ad --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/constants.go @@ -0,0 +1,47 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +const ( + // HeaderContentType represents a http content-type header, it's value is supposed to be a mime type + HeaderContentType = "Content-Type" + + // HeaderTransferEncoding represents a http transfer-encoding header. + HeaderTransferEncoding = "Transfer-Encoding" + + // HeaderAccept the Accept header + HeaderAccept = "Accept" + + charsetKey = "charset" + + // DefaultMime the default fallback mime type + DefaultMime = "application/octet-stream" + // JSONMime the json mime type + JSONMime = "application/json" + // YAMLMime the yaml mime type + YAMLMime = "application/x-yaml" + // XMLMime the xml mime type + XMLMime = "application/xml" + // TextMime the text mime type + TextMime = "text/plain" + // HTMLMime the html mime type + HTMLMime = "text/html" + // CSVMime the csv mime type + CSVMime = "text/csv" + // MultipartFormMime the multipart form mime type + MultipartFormMime = "multipart/form-data" + // URLencodedFormMime the url encoded form mime type + URLencodedFormMime = "application/x-www-form-urlencoded" +) diff --git a/vendor/github.com/go-openapi/runtime/csv.go b/vendor/github.com/go-openapi/runtime/csv.go new file mode 100644 index 000000000..d807bd915 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/csv.go @@ -0,0 +1,77 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "bytes" + "encoding/csv" + "errors" + "io" +) + +// CSVConsumer creates a new CSV consumer +func CSVConsumer() Consumer { + return ConsumerFunc(func(reader io.Reader, data interface{}) error { + if reader == nil { + return errors.New("CSVConsumer requires a reader") + } + + csvReader := csv.NewReader(reader) + writer, ok := data.(io.Writer) + if !ok { + return errors.New("data type must be io.Writer") + } + csvWriter := csv.NewWriter(writer) + records, err := csvReader.ReadAll() + if err != nil { + return err + } + for _, r := range records { + if err := csvWriter.Write(r); err != nil { + return err + } + } + csvWriter.Flush() + return nil + }) +} + +// CSVProducer creates a new CSV producer +func CSVProducer() Producer { + return ProducerFunc(func(writer io.Writer, data interface{}) error { + if writer == nil { + return errors.New("CSVProducer requires a writer") + } + + dataBytes, ok := data.([]byte) + if !ok { + return errors.New("data type must be byte array") + } + + csvReader := csv.NewReader(bytes.NewBuffer(dataBytes)) + records, err := csvReader.ReadAll() + if err != nil { + return err + } + csvWriter := csv.NewWriter(writer) + for _, r := range records { + if err := csvWriter.Write(r); err != nil { + return err + } + } + csvWriter.Flush() + return nil + }) +} diff --git a/vendor/github.com/go-openapi/runtime/discard.go b/vendor/github.com/go-openapi/runtime/discard.go new file mode 100644 index 000000000..0d390cfd6 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/discard.go @@ -0,0 +1,9 @@ +package runtime + +import "io" + +// DiscardConsumer does absolutely nothing, it's a black hole. +var DiscardConsumer = ConsumerFunc(func(_ io.Reader, _ interface{}) error { return nil }) + +// DiscardProducer does absolutely nothing, it's a black hole. +var DiscardProducer = ProducerFunc(func(_ io.Writer, _ interface{}) error { return nil }) diff --git a/vendor/github.com/go-openapi/runtime/file.go b/vendor/github.com/go-openapi/runtime/file.go new file mode 100644 index 000000000..85971c18c --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/file.go @@ -0,0 +1,33 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import "mime/multipart" + +// File represents an uploaded file. +type File struct { + Data multipart.File + Header *multipart.FileHeader +} + +// Read bytes from the file +func (f *File) Read(p []byte) (n int, err error) { + return f.Data.Read(p) +} + +// Close the file +func (f *File) Close() error { + return f.Data.Close() +} diff --git a/vendor/github.com/go-openapi/runtime/go.mod b/vendor/github.com/go-openapi/runtime/go.mod new file mode 100644 index 000000000..51e4d721e --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/go.mod @@ -0,0 +1,25 @@ +module github.com/go-openapi/runtime + +require ( + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/docker/go-units v0.3.3 + github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect + github.com/go-openapi/analysis v0.18.0 + github.com/go-openapi/errors v0.18.0 + github.com/go-openapi/jsonpointer v0.18.0 // indirect + github.com/go-openapi/jsonreference v0.18.0 // indirect + github.com/go-openapi/loads v0.18.0 + github.com/go-openapi/spec v0.18.0 + github.com/go-openapi/strfmt v0.18.0 + github.com/go-openapi/swag v0.18.0 + github.com/go-openapi/validate v0.18.0 + github.com/google/uuid v1.1.1 // indirect + github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.3.0 + golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 // indirect + golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 // indirect + golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/vendor/github.com/go-openapi/runtime/go.sum b/vendor/github.com/go-openapi/runtime/go.sum new file mode 100644 index 000000000..5ac448f0a --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/go.sum @@ -0,0 +1,87 @@ +github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.17.2 h1:eYp14J1o8TTSCzndHBtsNuckikV1PfZOSnx4BcBeu0c= +github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.17.2 h1:azEQ8Fnx0jmtFF2fxsnmd6I0x6rsweUF63qqSO1NmKk= +github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.17.2 h1:3ekBy41gar/iJi2KSh/au/PrC2vpLr85upF/UZmm3W0= +github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.17.2 h1:lF3z7AH8dd0IKXc1zEBi1dj0B4XgVb5cVjn39dCK3Ls= +github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.17.2 h1:tEXYu6Xc0pevpzzQx5ghrMN9F7IVpN/+u4iD3rkYE5o= +github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.17.2 h1:eb2NbuCnoe8cWAxhtK6CfMWUYmiFEZJ9Hx3Z2WRwJ5M= +github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.17.2 h1:2KDns36DMHXG9/iYkOjiX+/8fKK9GCU5ELZ+J6qcRVA= +github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.17.2 h1:K/ycE/XTUDFltNHSO32cGRUhrVGJD64o8WgAIZNyc3k= +github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.17.2 h1:lwFfiS4sv5DvOrsYDsYq4N7UU8ghXiYtPJ+VcQnC3Xg= +github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-openapi/runtime/headers.go b/vendor/github.com/go-openapi/runtime/headers.go new file mode 100644 index 000000000..4d111db4f --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/headers.go @@ -0,0 +1,45 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "mime" + "net/http" + + "github.com/go-openapi/errors" +) + +// ContentType parses a content type header +func ContentType(headers http.Header) (string, string, error) { + ct := headers.Get(HeaderContentType) + orig := ct + if ct == "" { + ct = DefaultMime + } + if ct == "" { + return "", "", nil + } + + mt, opts, err := mime.ParseMediaType(ct) + if err != nil { + return "", "", errors.NewParseError(HeaderContentType, "header", orig, err) + } + + if cs, ok := opts[charsetKey]; ok { + return mt, cs, nil + } + + return mt, "", nil +} diff --git a/vendor/github.com/go-openapi/runtime/interfaces.go b/vendor/github.com/go-openapi/runtime/interfaces.go new file mode 100644 index 000000000..65de0aa44 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/interfaces.go @@ -0,0 +1,103 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "io" + "net/http" + + "github.com/go-openapi/strfmt" +) + +// OperationHandlerFunc an adapter for a function to the OperationHandler interface +type OperationHandlerFunc func(interface{}) (interface{}, error) + +// Handle implements the operation handler interface +func (s OperationHandlerFunc) Handle(data interface{}) (interface{}, error) { + return s(data) +} + +// OperationHandler a handler for a swagger operation +type OperationHandler interface { + Handle(interface{}) (interface{}, error) +} + +// ConsumerFunc represents a function that can be used as a consumer +type ConsumerFunc func(io.Reader, interface{}) error + +// Consume consumes the reader into the data parameter +func (fn ConsumerFunc) Consume(reader io.Reader, data interface{}) error { + return fn(reader, data) +} + +// Consumer implementations know how to bind the values on the provided interface to +// data provided by the request body +type Consumer interface { + // Consume performs the binding of request values + Consume(io.Reader, interface{}) error +} + +// ProducerFunc represents a function that can be used as a producer +type ProducerFunc func(io.Writer, interface{}) error + +// Produce produces the response for the provided data +func (f ProducerFunc) Produce(writer io.Writer, data interface{}) error { + return f(writer, data) +} + +// Producer implementations know how to turn the provided interface into a valid +// HTTP response +type Producer interface { + // Produce writes to the http response + Produce(io.Writer, interface{}) error +} + +// AuthenticatorFunc turns a function into an authenticator +type AuthenticatorFunc func(interface{}) (bool, interface{}, error) + +// Authenticate authenticates the request with the provided data +func (f AuthenticatorFunc) Authenticate(params interface{}) (bool, interface{}, error) { + return f(params) +} + +// Authenticator represents an authentication strategy +// implementations of Authenticator know how to authenticate the +// request data and translate that into a valid principal object or an error +type Authenticator interface { + Authenticate(interface{}) (bool, interface{}, error) +} + +// AuthorizerFunc turns a function into an authorizer +type AuthorizerFunc func(*http.Request, interface{}) error + +// Authorize authorizes the processing of the request for the principal +func (f AuthorizerFunc) Authorize(r *http.Request, principal interface{}) error { + return f(r, principal) +} + +// Authorizer represents an authorization strategy +// implementations of Authorizer know how to authorize the principal object +// using the request data and returns error if unauthorized +type Authorizer interface { + Authorize(*http.Request, interface{}) error +} + +// Validatable types implementing this interface allow customizing their validation +// this will be used instead of the reflective validation based on the spec document. +// the implementations are assumed to have been generated by the swagger tool so they should +// contain all the validations obtained from the spec +type Validatable interface { + Validate(strfmt.Registry) error +} diff --git a/vendor/github.com/go-openapi/runtime/json.go b/vendor/github.com/go-openapi/runtime/json.go new file mode 100644 index 000000000..5a690559c --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/json.go @@ -0,0 +1,38 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "encoding/json" + "io" +) + +// JSONConsumer creates a new JSON consumer +func JSONConsumer() Consumer { + return ConsumerFunc(func(reader io.Reader, data interface{}) error { + dec := json.NewDecoder(reader) + dec.UseNumber() // preserve number formats + return dec.Decode(data) + }) +} + +// JSONProducer creates a new JSON producer +func JSONProducer() Producer { + return ProducerFunc(func(writer io.Writer, data interface{}) error { + enc := json.NewEncoder(writer) + enc.SetEscapeHTML(false) + return enc.Encode(data) + }) +} diff --git a/vendor/github.com/go-openapi/runtime/request.go b/vendor/github.com/go-openapi/runtime/request.go new file mode 100644 index 000000000..87b73da45 --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/request.go @@ -0,0 +1,77 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "io" + "net/http" + "strings" + + "github.com/go-openapi/swag" +) + +// CanHaveBody returns true if this method can have a body +func CanHaveBody(method string) bool { + mn := strings.ToUpper(method) + return mn == "POST" || mn == "PUT" || mn == "PATCH" || mn == "DELETE" +} + +// IsSafe returns true if this is a request with a safe method +func IsSafe(r *http.Request) bool { + mn := strings.ToUpper(r.Method) + return mn == "GET" || mn == "HEAD" +} + +// AllowsBody returns true if the request allows for a body +func AllowsBody(r *http.Request) bool { + mn := strings.ToUpper(r.Method) + return mn != "HEAD" +} + +// HasBody returns true if this method needs a content-type +func HasBody(r *http.Request) bool { + return len(r.TransferEncoding) > 0 || r.ContentLength > 0 +} + +// JSONRequest creates a new http request with json headers set +func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) { + req, err := http.NewRequest(method, urlStr, body) + if err != nil { + return nil, err + } + req.Header.Add(HeaderContentType, JSONMime) + req.Header.Add(HeaderAccept, JSONMime) + return req, nil +} + +// Gettable for things with a method GetOK(string) (data string, hasKey bool, hasValue bool) +type Gettable interface { + GetOK(string) ([]string, bool, bool) +} + +// ReadSingleValue reads a single value from the source +func ReadSingleValue(values Gettable, name string) string { + vv, _, hv := values.GetOK(name) + if hv { + return vv[len(vv)-1] + } + return "" +} + +// ReadCollectionValue reads a collection value from a string data source +func ReadCollectionValue(values Gettable, name, collectionFormat string) []string { + v := ReadSingleValue(values, name) + return swag.SplitByFormat(v, collectionFormat) +} diff --git a/vendor/github.com/go-openapi/runtime/statuses.go b/vendor/github.com/go-openapi/runtime/statuses.go new file mode 100644 index 000000000..3b011a0bf --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/statuses.go @@ -0,0 +1,90 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +// Statuses lists the most common HTTP status codes to default message +// taken from https://httpstatuses.com/ +var Statuses = map[int]string{ + 100: "Continue", + 101: "Switching Protocols", + 102: "Processing", + 103: "Checkpoint", + 122: "URI too long", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Request Processed", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi-Status", + 208: "Already Reported", + 226: "IM Used", + 300: "Multiple Choices", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 306: "Switch Proxy", + 307: "Temporary Redirect", + 308: "Permanent Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Request Range Not Satisfiable", + 417: "Expectation Failed", + 418: "I'm a teapot", + 420: "Enhance Your Calm", + 422: "Unprocessable Entity", + 423: "Locked", + 424: "Failed Dependency", + 426: "Upgrade Required", + 428: "Precondition Required", + 429: "Too Many Requests", + 431: "Request Header Fields Too Large", + 444: "No Response", + 449: "Retry With", + 450: "Blocked by Windows Parental Controls", + 451: "Wrong Exchange Server", + 499: "Client Closed Request", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported", + 506: "Variant Also Negotiates", + 507: "Insufficient Storage", + 508: "Loop Detected", + 509: "Bandwidth Limit Exceeded", + 510: "Not Extended", + 511: "Network Authentication Required", + 598: "Network read timeout error", + 599: "Network connect timeout error", +} diff --git a/vendor/github.com/go-openapi/runtime/text.go b/vendor/github.com/go-openapi/runtime/text.go new file mode 100644 index 000000000..77099feda --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/text.go @@ -0,0 +1,111 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "bytes" + "encoding" + "errors" + "fmt" + "io" + "reflect" + + "github.com/go-openapi/swag" +) + +// TextConsumer creates a new text consumer +func TextConsumer() Consumer { + return ConsumerFunc(func(reader io.Reader, data interface{}) error { + if reader == nil { + return errors.New("TextConsumer requires a reader") // early exit + } + + buf := new(bytes.Buffer) + _, err := buf.ReadFrom(reader) + if err != nil { + return err + } + b := buf.Bytes() + + if tu, ok := data.(encoding.TextUnmarshaler); ok { + err := tu.UnmarshalText(b) + if err != nil { + return fmt.Errorf("text consumer: %v", err) + } + + return nil + } + + t := reflect.TypeOf(data) + if data != nil && t.Kind() == reflect.Ptr { + v := reflect.Indirect(reflect.ValueOf(data)) + if t.Elem().Kind() == reflect.String { + v.SetString(string(b)) + return nil + } + } + + return fmt.Errorf("%v (%T) is not supported by the TextConsumer, %s", + data, data, "can be resolved by supporting TextUnmarshaler interface") + }) +} + +// TextProducer creates a new text producer +func TextProducer() Producer { + return ProducerFunc(func(writer io.Writer, data interface{}) error { + if writer == nil { + return errors.New("TextProducer requires a writer") // early exit + } + + if data == nil { + return errors.New("no data given to produce text from") + } + + if tm, ok := data.(encoding.TextMarshaler); ok { + txt, err := tm.MarshalText() + if err != nil { + return fmt.Errorf("text producer: %v", err) + } + _, err = writer.Write(txt) + return err + } + + if str, ok := data.(error); ok { + _, err := writer.Write([]byte(str.Error())) + return err + } + + if str, ok := data.(fmt.Stringer); ok { + _, err := writer.Write([]byte(str.String())) + return err + } + + v := reflect.Indirect(reflect.ValueOf(data)) + if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice { + b, err := swag.WriteJSON(data) + if err != nil { + return err + } + _, err = writer.Write(b) + return err + } + if v.Kind() != reflect.String { + return fmt.Errorf("%T is not a supported type by the TextProducer", data) + } + + _, err := writer.Write([]byte(v.String())) + return err + }) +} diff --git a/vendor/github.com/go-openapi/runtime/values.go b/vendor/github.com/go-openapi/runtime/values.go new file mode 100644 index 000000000..11f5732af --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/values.go @@ -0,0 +1,19 @@ +package runtime + +// Values typically represent parameters on a http request. +type Values map[string][]string + +// GetOK returns the values collection for the given key. +// When the key is present in the map it will return true for hasKey. +// When the value is not empty it will return true for hasValue. +func (v Values) GetOK(key string) (value []string, hasKey bool, hasValue bool) { + value, hasKey = v[key] + if !hasKey { + return + } + if len(value) == 0 { + return + } + hasValue = true + return +} diff --git a/vendor/github.com/go-openapi/runtime/xml.go b/vendor/github.com/go-openapi/runtime/xml.go new file mode 100644 index 000000000..821c7393d --- /dev/null +++ b/vendor/github.com/go-openapi/runtime/xml.go @@ -0,0 +1,36 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 runtime + +import ( + "encoding/xml" + "io" +) + +// XMLConsumer creates a new XML consumer +func XMLConsumer() Consumer { + return ConsumerFunc(func(reader io.Reader, data interface{}) error { + dec := xml.NewDecoder(reader) + return dec.Decode(data) + }) +} + +// XMLProducer creates a new XML producer +func XMLProducer() Producer { + return ProducerFunc(func(writer io.Writer, data interface{}) error { + enc := xml.NewEncoder(writer) + return enc.Encode(data) + }) +} diff --git a/vendor/github.com/go-openapi/validate/.editorconfig b/vendor/github.com/go-openapi/validate/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/validate/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/validate/.gitignore b/vendor/github.com/go-openapi/validate/.gitignore new file mode 100644 index 000000000..fea8b84ec --- /dev/null +++ b/vendor/github.com/go-openapi/validate/.gitignore @@ -0,0 +1,5 @@ +secrets.yml +coverage.out +*.cov +*.out +playground diff --git a/vendor/github.com/go-openapi/validate/.golangci.yml b/vendor/github.com/go-openapi/validate/.golangci.yml new file mode 100644 index 000000000..c2c507132 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/.golangci.yml @@ -0,0 +1,20 @@ +linters-settings: + govet: + check-shadowing: true + golint: + min-confidence: 0 + gocyclo: + min-complexity: 25 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 2 + +linters: + enable-all: true + disable: + - maligned + - lll diff --git a/vendor/github.com/go-openapi/validate/.travis.yml b/vendor/github.com/go-openapi/validate/.travis.yml new file mode 100644 index 000000000..dd3a4b29f --- /dev/null +++ b/vendor/github.com/go-openapi/validate/.travis.yml @@ -0,0 +1,19 @@ +after_success: +- bash <(curl -s https://codecov.io/bash) +go: +- 1.11.x +- 1.12.x +install: +- GO111MODULE=off go get -u gotest.tools/gotestsum +env: +- GO111MODULE=on +language: go +notifications: + slack: + secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA= +script: +- gotestsum -f short-verbose -- -race ./... +- gotestsum -f short-verbose -- -timeout=20m -coverprofile=coverage.txt -covermode=atomic -args -enable-long ./... +- gotestsum -f short-verbose -- -timeout=30m -args -enable-go-swagger ./... +- go get -u github.com/go-openapi/runtime@master +- gotestsum -f short-verbose -- -timeout=30m github.com/go-openapi/runtime/... diff --git a/vendor/github.com/go-openapi/validate/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/validate/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/validate/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/validate/LICENSE b/vendor/github.com/go-openapi/validate/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/vendor/github.com/go-openapi/validate/README.md b/vendor/github.com/go-openapi/validate/README.md new file mode 100644 index 000000000..08fb352bc --- /dev/null +++ b/vendor/github.com/go-openapi/validate/README.md @@ -0,0 +1,6 @@ +# Validation helpers [![Build Status](https://travis-ci.org/go-openapi/validate.svg?branch=master)](https://travis-ci.org/go-openapi/validate) [![codecov](https://codecov.io/gh/go-openapi/validate/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/validate/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/go-openapi/validate?status.svg)](http://godoc.org/github.com/go-openapi/validate) +[![GolangCI](https://golangci.com/badges/github.com/go-openapi/validate.svg)](https://golangci.com) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/validate)](https://goreportcard.com/report/github.com/go-openapi/validate) diff --git a/vendor/github.com/go-openapi/validate/debug.go b/vendor/github.com/go-openapi/validate/debug.go new file mode 100644 index 000000000..8815fd935 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/debug.go @@ -0,0 +1,47 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" +) + +var ( + // Debug is true when the SWAGGER_DEBUG env var is not empty. + // It enables a more verbose logging of validators. + Debug = os.Getenv("SWAGGER_DEBUG") != "" + // validateLogger is a debug logger for this package + validateLogger *log.Logger +) + +func init() { + debugOptions() +} + +func debugOptions() { + validateLogger = log.New(os.Stdout, "validate:", log.LstdFlags) +} + +func debugLog(msg string, args ...interface{}) { + // A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog() + if Debug { + _, file1, pos1, _ := runtime.Caller(1) + validateLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...)) + } +} diff --git a/vendor/github.com/go-openapi/validate/default_validator.go b/vendor/github.com/go-openapi/validate/default_validator.go new file mode 100644 index 000000000..35c631be6 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/default_validator.go @@ -0,0 +1,278 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "strings" + + "github.com/go-openapi/spec" +) + +// defaultValidator validates default values in a spec. +// According to Swagger spec, default values MUST validate their schema. +type defaultValidator struct { + SpecValidator *SpecValidator + visitedSchemas map[string]bool +} + +// resetVisited resets the internal state of visited schemas +func (d *defaultValidator) resetVisited() { + d.visitedSchemas = map[string]bool{} +} + +// beingVisited asserts a schema is being visited +func (d *defaultValidator) beingVisited(path string) { + d.visitedSchemas[path] = true +} + +// isVisited tells if a path has already been visited +func (d *defaultValidator) isVisited(path string) bool { + found := d.visitedSchemas[path] + if !found { + // search for overlapping paths + frags := strings.Split(path, ".") + if len(frags) < 2 { + // shortcut exit on smaller paths + return found + } + last := len(frags) - 1 + var currentFragStr, parent string + for i := range frags { + if i == 0 { + currentFragStr = frags[last] + } else { + currentFragStr = strings.Join([]string{frags[last-i], currentFragStr}, ".") + } + if i < last { + parent = strings.Join(frags[0:last-i], ".") + } else { + parent = "" + } + if strings.HasSuffix(parent, currentFragStr) { + found = true + break + } + } + } + return found +} + +// Validate validates the default values declared in the swagger spec +func (d *defaultValidator) Validate() (errs *Result) { + errs = new(Result) + if d == nil || d.SpecValidator == nil { + return errs + } + d.resetVisited() + errs.Merge(d.validateDefaultValueValidAgainstSchema()) // error - + return errs +} + +func (d *defaultValidator) validateDefaultValueValidAgainstSchema() *Result { + // every default value that is specified must validate against the schema for that property + // headers, items, parameters, schema + + res := new(Result) + s := d.SpecValidator + + for method, pathItem := range s.analyzer.Operations() { + if pathItem != nil { // Safeguard + for path, op := range pathItem { + // parameters + for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { + if param.Default != nil && param.Required { + res.AddWarnings(requiredHasDefaultMsg(param.Name, param.In)) + } + + // reset explored schemas to get depth-first recursive-proof exploration + d.resetVisited() + + // Check simple parameters first + // default values provided must validate against their inline definition (no explicit schema) + if param.Default != nil && param.Schema == nil { + // check param default value is valid + red := NewParamValidator(¶m, s.KnownFormats).Validate(param.Default) + if red.HasErrorsOrWarnings() { + res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In)) + res.Merge(red) + } + } + + // Recursively follows Items and Schemas + if param.Items != nil { + red := d.validateDefaultValueItemsAgainstSchema(param.Name, param.In, ¶m, param.Items) + if red.HasErrorsOrWarnings() { + res.AddErrors(defaultValueItemsDoesNotValidateMsg(param.Name, param.In)) + res.Merge(red) + } + } + + if param.Schema != nil { + // Validate default value against schema + red := d.validateDefaultValueSchemaAgainstSchema(param.Name, param.In, param.Schema) + if red.HasErrorsOrWarnings() { + res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In)) + res.Merge(red) + } + } + } + + if op.Responses != nil { + if op.Responses.Default != nil { + // Same constraint on default Response + res.Merge(d.validateDefaultInResponse(op.Responses.Default, "default", path, 0, op.ID)) + } + // Same constraint on regular Responses + if op.Responses.StatusCodeResponses != nil { // Safeguard + for code, r := range op.Responses.StatusCodeResponses { + res.Merge(d.validateDefaultInResponse(&r, "response", path, code, op.ID)) + } + } + } else { + // Empty op.ID means there is no meaningful operation: no need to report a specific message + if op.ID != "" { + res.AddErrors(noValidResponseMsg(op.ID)) + } + } + } + } + } + if s.spec.Spec().Definitions != nil { // Safeguard + // reset explored schemas to get depth-first recursive-proof exploration + d.resetVisited() + for nm, sch := range s.spec.Spec().Definitions { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("definitions.%s", nm), "body", &sch)) + } + } + return res +} + +func (d *defaultValidator) validateDefaultInResponse(resp *spec.Response, responseType, path string, responseCode int, operationID string) *Result { + s := d.SpecValidator + + response, res := responseHelp.expandResponseRef(resp, path, s) + if !res.IsValid() { + return res + } + + responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) + + if response.Headers != nil { // Safeguard + for nm, h := range response.Headers { + // reset explored schemas to get depth-first recursive-proof exploration + d.resetVisited() + + if h.Default != nil { + red := NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Default) + if red.HasErrorsOrWarnings() { + res.AddErrors(defaultValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) + res.Merge(red) + } + } + + // Headers have inline definition, like params + if h.Items != nil { + red := d.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items) + if red.HasErrorsOrWarnings() { + res.AddErrors(defaultValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) + res.Merge(red) + } + } + + if _, err := compileRegexp(h.Pattern); err != nil { + res.AddErrors(invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) + } + + // Headers don't have schema + } + } + if response.Schema != nil { + // reset explored schemas to get depth-first recursive-proof exploration + d.resetVisited() + + red := d.validateDefaultValueSchemaAgainstSchema(responseCodeAsStr, "response", response.Schema) + if red.HasErrorsOrWarnings() { + // Additional message to make sure the context of the error is not lost + res.AddErrors(defaultValueInDoesNotValidateMsg(operationID, responseName)) + res.Merge(red) + } + } + return res +} + +func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path, in string, schema *spec.Schema) *Result { + if schema == nil || d.isVisited(path) { + // Avoids recursing if we are already done with that check + return nil + } + d.beingVisited(path) + res := new(Result) + s := d.SpecValidator + + if schema.Default != nil { + res.Merge(NewSchemaValidator(schema, s.spec.Spec(), path+".default", s.KnownFormats).Validate(schema.Default)) + } + if schema.Items != nil { + if schema.Items.Schema != nil { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+".items.default", in, schema.Items.Schema)) + } + // Multiple schemas in items + if schema.Items.Schemas != nil { // Safeguard + for i, sch := range schema.Items.Schemas { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d].default", path, i), in, &sch)) + } + } + } + if _, err := compileRegexp(schema.Pattern); err != nil { + res.AddErrors(invalidPatternInMsg(path, in, schema.Pattern)) + } + if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { + // NOTE: we keep validating values, even though additionalItems is not supported by Swagger 2.0 (and 3.0 as well) + res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalItems", path), in, schema.AdditionalItems.Schema)) + } + for propName, prop := range schema.Properties { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop)) + } + for propName, prop := range schema.PatternProperties { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(path+"."+propName, in, &prop)) + } + if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalProperties", path), in, schema.AdditionalProperties.Schema)) + } + if schema.AllOf != nil { + for i, aoSch := range schema.AllOf { + res.Merge(d.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.allOf[%d]", path, i), in, &aoSch)) + } + } + return res +} + +func (d *defaultValidator) validateDefaultValueItemsAgainstSchema(path, in string, root interface{}, items *spec.Items) *Result { + res := new(Result) + s := d.SpecValidator + if items != nil { + if items.Default != nil { + res.Merge(newItemsValidator(path, in, items, root, s.KnownFormats).Validate(0, items.Default)) + } + if items.Items != nil { + res.Merge(d.validateDefaultValueItemsAgainstSchema(path+"[0].default", in, root, items.Items)) + } + if _, err := compileRegexp(items.Pattern); err != nil { + res.AddErrors(invalidPatternInMsg(path, in, items.Pattern)) + } + } + return res +} diff --git a/vendor/github.com/go-openapi/validate/doc.go b/vendor/github.com/go-openapi/validate/doc.go new file mode 100644 index 000000000..f5ca9a5d5 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/doc.go @@ -0,0 +1,85 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate provides methods to validate a swagger specification, +as well as tools to validate data against their schema. + +This package follows Swagger 2.0. specification (aka OpenAPI 2.0). Reference +can be found here: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md. + +Validating a specification + +Validates a spec document (from JSON or YAML) against the JSON schema for swagger, +then checks a number of extra rules that can't be expressed in JSON schema. + +Entry points: + - Spec() + - NewSpecValidator() + - SpecValidator.Validate() + +Reported as errors: + [x] definition can't declare a property that's already defined by one of its ancestors + [x] definition's ancestor can't be a descendant of the same model + [x] path uniqueness: each api path should be non-verbatim (account for path param names) unique per method + [x] each security reference should contain only unique scopes + [x] each security scope in a security definition should be unique + [x] parameters in path must be unique + [x] each path parameter must correspond to a parameter placeholder and vice versa + [x] each referenceable definition must have references + [x] each definition property listed in the required array must be defined in the properties of the model + [x] each parameter should have a unique `name` and `type` combination + [x] each operation should have only 1 parameter of type body + [x] each reference must point to a valid object + [x] every default value that is specified must validate against the schema for that property + [x] items property is required for all schemas/definitions of type `array` + [x] path parameters must be declared a required + [x] headers must not contain $ref + [x] schema and property examples provided must validate against their respective object's schema + [x] examples provided must validate their schema + +Reported as warnings: + [x] path parameters should not contain any of [{,},\w] + [x] empty path + [x] unused definitions + [x] unsupported validation of examples on non-JSON media types + [x] examples in response without schema + [x] readOnly properties should not be required + +Validating a schema + +The schema validation toolkit validates data against JSON-schema-draft 04 schema. + +It is tested against the full json-schema-testing-suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), +except for the optional part (bignum, ECMA regexp, ...). + +It supports the complete JSON-schema vocabulary, including keywords not supported by Swagger (e.g. additionalItems, ...) + +Entry points: + - AgainstSchema() + - ... + +Known limitations + +With the current version of this package, the following aspects of swagger are not yet supported: + [ ] errors and warnings are not reported with key/line number in spec + [ ] default values and examples on responses only support application/json producer type + [ ] invalid numeric constraints (such as Minimum, etc..) are not checked except for default and example values + [ ] rules for collectionFormat are not implemented + [ ] no validation rule for polymorphism support (discriminator) [not done here] + [ ] valid js ECMA regexp not supported by Go regexp engine are considered invalid + [ ] arbitrary large numbers are not supported: max is math.MaxFloat64 + +*/ +package validate diff --git a/vendor/github.com/go-openapi/validate/example_validator.go b/vendor/github.com/go-openapi/validate/example_validator.go new file mode 100644 index 000000000..b2acf1055 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/example_validator.go @@ -0,0 +1,299 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "strings" + + "github.com/go-openapi/spec" +) + +// ExampleValidator validates example values defined in a spec +type exampleValidator struct { + SpecValidator *SpecValidator + visitedSchemas map[string]bool +} + +// resetVisited resets the internal state of visited schemas +func (ex *exampleValidator) resetVisited() { + ex.visitedSchemas = map[string]bool{} +} + +// beingVisited asserts a schema is being visited +func (ex *exampleValidator) beingVisited(path string) { + ex.visitedSchemas[path] = true +} + +// isVisited tells if a path has already been visited +func (ex *exampleValidator) isVisited(path string) bool { + found := ex.visitedSchemas[path] + if !found { + // search for overlapping paths + frags := strings.Split(path, ".") + if len(frags) < 2 { + // shortcut exit on smaller paths + return found + } + last := len(frags) - 1 + var currentFragStr, parent string + for i := range frags { + if i == 0 { + currentFragStr = frags[last] + } else { + currentFragStr = strings.Join([]string{frags[last-i], currentFragStr}, ".") + } + if i < last { + parent = strings.Join(frags[0:last-i], ".") + } else { + parent = "" + } + if strings.HasSuffix(parent, currentFragStr) { + found = true + break + } + } + } + return found +} + +// Validate validates the example values declared in the swagger spec +// Example values MUST conform to their schema. +// +// With Swagger 2.0, examples are supported in: +// - schemas +// - individual property +// - responses +// +func (ex *exampleValidator) Validate() (errs *Result) { + errs = new(Result) + if ex == nil || ex.SpecValidator == nil { + return errs + } + ex.resetVisited() + errs.Merge(ex.validateExampleValueValidAgainstSchema()) // error - + + return errs +} + +func (ex *exampleValidator) validateExampleValueValidAgainstSchema() *Result { + // every example value that is specified must validate against the schema for that property + // in: schemas, properties, object, items + // not in: headers, parameters without schema + + res := new(Result) + s := ex.SpecValidator + + for method, pathItem := range s.analyzer.Operations() { + if pathItem != nil { // Safeguard + for path, op := range pathItem { + // parameters + for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { + + // As of swagger 2.0, Examples are not supported in simple parameters + // However, it looks like it is supported by go-openapi + + // reset explored schemas to get depth-first recursive-proof exploration + ex.resetVisited() + + // Check simple parameters first + // default values provided must validate against their inline definition (no explicit schema) + if param.Example != nil && param.Schema == nil { + // check param default value is valid + red := NewParamValidator(¶m, s.KnownFormats).Validate(param.Example) + if red.HasErrorsOrWarnings() { + res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In)) + res.MergeAsWarnings(red) + } + } + + // Recursively follows Items and Schemas + if param.Items != nil { + red := ex.validateExampleValueItemsAgainstSchema(param.Name, param.In, ¶m, param.Items) + if red.HasErrorsOrWarnings() { + res.AddWarnings(exampleValueItemsDoesNotValidateMsg(param.Name, param.In)) + res.Merge(red) + } + } + + if param.Schema != nil { + // Validate example value against schema + red := ex.validateExampleValueSchemaAgainstSchema(param.Name, param.In, param.Schema) + if red.HasErrorsOrWarnings() { + res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In)) + res.Merge(red) + } + } + } + + if op.Responses != nil { + if op.Responses.Default != nil { + // Same constraint on default Response + res.Merge(ex.validateExampleInResponse(op.Responses.Default, "default", path, 0, op.ID)) + } + // Same constraint on regular Responses + if op.Responses.StatusCodeResponses != nil { // Safeguard + for code, r := range op.Responses.StatusCodeResponses { + res.Merge(ex.validateExampleInResponse(&r, "response", path, code, op.ID)) + } + } + } else { + // Empty op.ID means there is no meaningful operation: no need to report a specific message + if op.ID != "" { + res.AddErrors(noValidResponseMsg(op.ID)) + } + } + } + } + } + if s.spec.Spec().Definitions != nil { // Safeguard + // reset explored schemas to get depth-first recursive-proof exploration + ex.resetVisited() + for nm, sch := range s.spec.Spec().Definitions { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("definitions.%s", nm), "body", &sch)) + } + } + return res +} + +func (ex *exampleValidator) validateExampleInResponse(resp *spec.Response, responseType, path string, responseCode int, operationID string) *Result { + s := ex.SpecValidator + + response, res := responseHelp.expandResponseRef(resp, path, s) + if !res.IsValid() { // Safeguard + return res + } + + responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode) + + if response.Headers != nil { // Safeguard + for nm, h := range response.Headers { + // reset explored schemas to get depth-first recursive-proof exploration + ex.resetVisited() + + if h.Example != nil { + red := NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Example) + if red.HasErrorsOrWarnings() { + res.AddWarnings(exampleValueHeaderDoesNotValidateMsg(operationID, nm, responseName)) + res.MergeAsWarnings(red) + } + } + + // Headers have inline definition, like params + if h.Items != nil { + red := ex.validateExampleValueItemsAgainstSchema(nm, "header", &h, h.Items) + if red.HasErrorsOrWarnings() { + res.AddWarnings(exampleValueHeaderItemsDoesNotValidateMsg(operationID, nm, responseName)) + res.MergeAsWarnings(red) + } + } + + if _, err := compileRegexp(h.Pattern); err != nil { + res.AddErrors(invalidPatternInHeaderMsg(operationID, nm, responseName, h.Pattern, err)) + } + + // Headers don't have schema + } + } + if response.Schema != nil { + // reset explored schemas to get depth-first recursive-proof exploration + ex.resetVisited() + + red := ex.validateExampleValueSchemaAgainstSchema(responseCodeAsStr, "response", response.Schema) + if red.HasErrorsOrWarnings() { + // Additional message to make sure the context of the error is not lost + res.AddWarnings(exampleValueInDoesNotValidateMsg(operationID, responseName)) + res.Merge(red) + } + } + + if response.Examples != nil { + if response.Schema != nil { + if example, ok := response.Examples["application/json"]; ok { + res.MergeAsWarnings(NewSchemaValidator(response.Schema, s.spec.Spec(), path, s.KnownFormats).Validate(example)) + } else { + // TODO: validate other media types too + res.AddWarnings(examplesMimeNotSupportedMsg(operationID, responseName)) + } + } else { + res.AddWarnings(examplesWithoutSchemaMsg(operationID, responseName)) + } + } + return res +} + +func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path, in string, schema *spec.Schema) *Result { + if schema == nil || ex.isVisited(path) { + // Avoids recursing if we are already done with that check + return nil + } + ex.beingVisited(path) + s := ex.SpecValidator + res := new(Result) + + if schema.Example != nil { + res.MergeAsWarnings(NewSchemaValidator(schema, s.spec.Spec(), path+".example", s.KnownFormats).Validate(schema.Example)) + } + if schema.Items != nil { + if schema.Items.Schema != nil { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+".items.example", in, schema.Items.Schema)) + } + // Multiple schemas in items + if schema.Items.Schemas != nil { // Safeguard + for i, sch := range schema.Items.Schemas { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d].example", path, i), in, &sch)) + } + } + } + if _, err := compileRegexp(schema.Pattern); err != nil { + res.AddErrors(invalidPatternInMsg(path, in, schema.Pattern)) + } + if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { + // NOTE: we keep validating values, even though additionalItems is unsupported in Swagger 2.0 (and 3.0 as well) + res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalItems", path), in, schema.AdditionalItems.Schema)) + } + for propName, prop := range schema.Properties { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+"."+propName, in, &prop)) + } + for propName, prop := range schema.PatternProperties { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(path+"."+propName, in, &prop)) + } + if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalProperties", path), in, schema.AdditionalProperties.Schema)) + } + if schema.AllOf != nil { + for i, aoSch := range schema.AllOf { + res.Merge(ex.validateExampleValueSchemaAgainstSchema(fmt.Sprintf("%s.allOf[%d]", path, i), in, &aoSch)) + } + } + return res +} + +func (ex *exampleValidator) validateExampleValueItemsAgainstSchema(path, in string, root interface{}, items *spec.Items) *Result { + res := new(Result) + s := ex.SpecValidator + if items != nil { + if items.Example != nil { + res.MergeAsWarnings(newItemsValidator(path, in, items, root, s.KnownFormats).Validate(0, items.Example)) + } + if items.Items != nil { + res.Merge(ex.validateExampleValueItemsAgainstSchema(path+"[0].example", in, root, items.Items)) + } + if _, err := compileRegexp(items.Pattern); err != nil { + res.AddErrors(invalidPatternInMsg(path, in, items.Pattern)) + } + } + return res +} diff --git a/vendor/github.com/go-openapi/validate/formats.go b/vendor/github.com/go-openapi/validate/formats.go new file mode 100644 index 000000000..b7afe981b --- /dev/null +++ b/vendor/github.com/go-openapi/validate/formats.go @@ -0,0 +1,73 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "reflect" + + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +type formatValidator struct { + Format string + Path string + In string + KnownFormats strfmt.Registry +} + +func (f *formatValidator) SetPath(path string) { + f.Path = path +} + +func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool { + doit := func() bool { + if source == nil { + return false + } + switch source.(type) { + case *spec.Items: + it := source.(*spec.Items) + return kind == reflect.String && f.KnownFormats.ContainsName(it.Format) + case *spec.Parameter: + par := source.(*spec.Parameter) + return kind == reflect.String && f.KnownFormats.ContainsName(par.Format) + case *spec.Schema: + sch := source.(*spec.Schema) + return kind == reflect.String && f.KnownFormats.ContainsName(sch.Format) + case *spec.Header: + hdr := source.(*spec.Header) + return kind == reflect.String && f.KnownFormats.ContainsName(hdr.Format) + } + return false + } + r := doit() + debugLog("format validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind) + return r +} + +func (f *formatValidator) Validate(val interface{}) *Result { + result := new(Result) + debugLog("validating \"%v\" against format: %s", val, f.Format) + + if err := FormatOf(f.Path, f.In, f.Format, val.(string), f.KnownFormats); err != nil { + result.AddErrors(err) + } + + if result.HasErrors() { + return result + } + return nil +} diff --git a/vendor/github.com/go-openapi/validate/go.mod b/vendor/github.com/go-openapi/validate/go.mod new file mode 100644 index 000000000..1197fcd64 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/go.mod @@ -0,0 +1,14 @@ +module github.com/go-openapi/validate + +require ( + github.com/go-openapi/analysis v0.19.2 + github.com/go-openapi/errors v0.19.2 + github.com/go-openapi/jsonpointer v0.19.2 + github.com/go-openapi/loads v0.19.2 + github.com/go-openapi/runtime v0.19.0 + github.com/go-openapi/spec v0.19.2 + github.com/go-openapi/strfmt v0.19.0 + github.com/go-openapi/swag v0.19.2 + github.com/stretchr/testify v1.3.0 + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/vendor/github.com/go-openapi/validate/go.sum b/vendor/github.com/go-openapi/validate/go.sum new file mode 100644 index 000000000..7b65517fd --- /dev/null +++ b/vendor/github.com/go-openapi/validate/go.sum @@ -0,0 +1,103 @@ +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-openapi/validate/helpers.go b/vendor/github.com/go-openapi/validate/helpers.go new file mode 100644 index 000000000..7ac877109 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/helpers.go @@ -0,0 +1,265 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +// TODO: define this as package validate/internal +// This must be done while keeping CI intact with all tests and test coverage + +import ( + "reflect" + "strconv" + "strings" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" +) + +const swaggerBody = "body" +const objectType = "object" + +// Helpers available at the package level +var ( + pathHelp *pathHelper + valueHelp *valueHelper + errorHelp *errorHelper + paramHelp *paramHelper + responseHelp *responseHelper +) + +type errorHelper struct { + // A collection of unexported helpers for error construction +} + +func (h *errorHelper) sErr(err errors.Error) *Result { + // Builds a Result from standard errors.Error + return &Result{Errors: []error{err}} +} + +func (h *errorHelper) addPointerError(res *Result, err error, ref string, fromPath string) *Result { + // Provides more context on error messages + // reported by the jsoinpointer package by altering the passed Result + if err != nil { + res.AddErrors(cannotResolveRefMsg(fromPath, ref, err)) + } + return res +} + +type pathHelper struct { + // A collection of unexported helpers for path validation +} + +func (h *pathHelper) stripParametersInPath(path string) string { + // Returns a path stripped from all path parameters, with multiple or trailing slashes removed. + // + // Stripping is performed on a slash-separated basis, e.g '/a{/b}' remains a{/b} and not /a. + // - Trailing "/" make a difference, e.g. /a/ !~ /a (ex: canary/bitbucket.org/swagger.json) + // - presence or absence of a parameter makes a difference, e.g. /a/{log} !~ /a/ (ex: canary/kubernetes/swagger.json) + + // Regexp to extract parameters from path, with surrounding {}. + // NOTE: important non-greedy modifier + rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`) + strippedSegments := []string{} + + for _, segment := range strings.Split(path, "/") { + strippedSegments = append(strippedSegments, rexParsePathParam.ReplaceAllString(segment, "X")) + } + return strings.Join(strippedSegments, "/") +} + +func (h *pathHelper) extractPathParams(path string) (params []string) { + // Extracts all params from a path, with surrounding "{}" + rexParsePathParam := mustCompileRegexp(`{[^{}]+?}`) + + for _, segment := range strings.Split(path, "/") { + for _, v := range rexParsePathParam.FindAllStringSubmatch(segment, -1) { + params = append(params, v...) + } + } + return +} + +type valueHelper struct { + // A collection of unexported helpers for value validation +} + +func (h *valueHelper) asInt64(val interface{}) int64 { + // Number conversion function for int64, without error checking + // (implements an implicit type upgrade). + v := reflect.ValueOf(val) + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return int64(v.Uint()) + case reflect.Float32, reflect.Float64: + return int64(v.Float()) + default: + //panic("Non numeric value in asInt64()") + return 0 + } +} + +func (h *valueHelper) asUint64(val interface{}) uint64 { + // Number conversion function for uint64, without error checking + // (implements an implicit type upgrade). + v := reflect.ValueOf(val) + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return uint64(v.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return v.Uint() + case reflect.Float32, reflect.Float64: + return uint64(v.Float()) + default: + //panic("Non numeric value in asUint64()") + return 0 + } +} + +// Same for unsigned floats +func (h *valueHelper) asFloat64(val interface{}) float64 { + // Number conversion function for float64, without error checking + // (implements an implicit type upgrade). + v := reflect.ValueOf(val) + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(v.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return float64(v.Uint()) + case reflect.Float32, reflect.Float64: + return v.Float() + default: + //panic("Non numeric value in asFloat64()") + return 0 + } +} + +type paramHelper struct { + // A collection of unexported helpers for parameters resolution +} + +func (h *paramHelper) safeExpandedParamsFor(path, method, operationID string, res *Result, s *SpecValidator) (params []spec.Parameter) { + operation, ok := s.analyzer.OperationFor(method, path) + if ok { + // expand parameters first if necessary + resolvedParams := []spec.Parameter{} + for _, ppr := range operation.Parameters { + resolvedParam, red := h.resolveParam(path, method, operationID, &ppr, s) + res.Merge(red) + if resolvedParam != nil { + resolvedParams = append(resolvedParams, *resolvedParam) + } + } + // remove params with invalid expansion from Slice + operation.Parameters = resolvedParams + + for _, ppr := range s.analyzer.SafeParamsFor(method, path, + func(p spec.Parameter, err error) bool { + // since params have already been expanded, there are few causes for error + res.AddErrors(someParametersBrokenMsg(path, method, operationID)) + // original error from analyzer + res.AddErrors(err) + return true + }) { + params = append(params, ppr) + } + } + return +} + +func (h *paramHelper) resolveParam(path, method, operationID string, param *spec.Parameter, s *SpecValidator) (*spec.Parameter, *Result) { + // Ensure parameter is expanded + var err error + res := new(Result) + isRef := param.Ref.String() != "" + if s.spec.SpecFilePath() == "" { + err = spec.ExpandParameterWithRoot(param, s.spec.Spec(), nil) + } else { + err = spec.ExpandParameter(param, s.spec.SpecFilePath()) + + } + if err != nil { // Safeguard + // NOTE: we may enter enter here when the whole parameter is an unresolved $ref + refPath := strings.Join([]string{"\"" + path + "\"", method}, ".") + errorHelp.addPointerError(res, err, param.Ref.String(), refPath) + return nil, res + } + res.Merge(h.checkExpandedParam(param, param.Name, param.In, operationID, isRef)) + return param, res +} + +func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation string, isRef bool) *Result { + // Secure parameter structure after $ref resolution + res := new(Result) + simpleZero := spec.SimpleSchema{} + // Try to explain why... best guess + if pr.In == swaggerBody && (pr.SimpleSchema != simpleZero && pr.SimpleSchema.Type != objectType) { + if isRef { + // Most likely, a $ref with a sibling is an unwanted situation: in itself this is a warning... + // but we detect it because of the following error: + // schema took over Parameter for an unexplained reason + res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation)) + } + res.AddErrors(invalidParameterDefinitionMsg(path, in, operation)) + } else if pr.In != swaggerBody && pr.Schema != nil { + if isRef { + res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation)) + } + res.AddErrors(invalidParameterDefinitionAsSchemaMsg(path, in, operation)) + } else if (pr.In == swaggerBody && pr.Schema == nil) || + (pr.In != swaggerBody && pr.SimpleSchema == simpleZero) { // Safeguard + // Other unexpected mishaps + res.AddErrors(invalidParameterDefinitionMsg(path, in, operation)) + } + return res +} + +type responseHelper struct { + // A collection of unexported helpers for response resolution +} + +func (r *responseHelper) expandResponseRef( + response *spec.Response, + path string, s *SpecValidator) (*spec.Response, *Result) { + // Ensure response is expanded + var err error + res := new(Result) + if s.spec.SpecFilePath() == "" { + // there is no physical document to resolve $ref in response + err = spec.ExpandResponseWithRoot(response, s.spec.Spec(), nil) + } else { + err = spec.ExpandResponse(response, s.spec.SpecFilePath()) + } + if err != nil { // Safeguard + // NOTE: we may enter here when the whole response is an unresolved $ref. + errorHelp.addPointerError(res, err, response.Ref.String(), path) + return nil, res + } + return response, res +} + +func (r *responseHelper) responseMsgVariants( + responseType string, + responseCode int) (responseName, responseCodeAsStr string) { + // Path variants for messages + if responseType == "default" { + responseCodeAsStr = "default" + responseName = "default response" + } else { + responseCodeAsStr = strconv.Itoa(responseCode) + responseName = "response " + responseCodeAsStr + } + return +} diff --git a/vendor/github.com/go-openapi/validate/object_validator.go b/vendor/github.com/go-openapi/validate/object_validator.go new file mode 100644 index 000000000..df0c5c14e --- /dev/null +++ b/vendor/github.com/go-openapi/validate/object_validator.go @@ -0,0 +1,268 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "reflect" + "regexp" + "strings" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +type objectValidator struct { + Path string + In string + MaxProperties *int64 + MinProperties *int64 + Required []string + Properties map[string]spec.Schema + AdditionalProperties *spec.SchemaOrBool + PatternProperties map[string]spec.Schema + Root interface{} + KnownFormats strfmt.Registry + Options SchemaValidatorOptions +} + +func (o *objectValidator) SetPath(path string) { + o.Path = path +} + +func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool { + // TODO: this should also work for structs + // there is a problem in the type validator where it will be unhappy about null values + // so that requires more testing + r := reflect.TypeOf(source) == specSchemaType && (kind == reflect.Map || kind == reflect.Struct) + debugLog("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind) + return r +} + +func (o *objectValidator) isPropertyName() bool { + p := strings.Split(o.Path, ".") + return p[len(p)-1] == "properties" && p[len(p)-2] != "properties" +} + +func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]interface{}) { + if t, typeFound := val["type"]; typeFound { + if tpe, ok := t.(string); ok && tpe == "array" { + if _, itemsKeyFound := val["items"]; !itemsKeyFound { + res.AddErrors(errors.Required("items", o.Path)) + } + } + } +} + +func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string]interface{}) { + if !o.isPropertyName() { + if _, itemsKeyFound := val["items"]; itemsKeyFound { + t, typeFound := val["type"] + if typeFound { + if tpe, ok := t.(string); !ok || tpe != "array" { + res.AddErrors(errors.InvalidType(o.Path, o.In, "array", nil)) + } + } else { + // there is no type + res.AddErrors(errors.Required("type", o.Path)) + } + } + } +} + +func (o *objectValidator) precheck(res *Result, val map[string]interface{}) { + o.checkArrayMustHaveItems(res, val) + if !o.Options.DisableObjectArrayTypeCheck { + o.checkItemsMustBeTypeArray(res, val) + } +} + +func (o *objectValidator) Validate(data interface{}) *Result { + val := data.(map[string]interface{}) + // TODO: guard against nil data + numKeys := int64(len(val)) + + if o.MinProperties != nil && numKeys < *o.MinProperties { + return errorHelp.sErr(errors.TooFewProperties(o.Path, o.In, *o.MinProperties)) + } + if o.MaxProperties != nil && numKeys > *o.MaxProperties { + return errorHelp.sErr(errors.TooManyProperties(o.Path, o.In, *o.MaxProperties)) + } + + res := new(Result) + + o.precheck(res, val) + + // check validity of field names + if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows { + // Case: additionalProperties: false + for k := range val { + _, regularProperty := o.Properties[k] + matched := false + + for pk := range o.PatternProperties { + if matches, _ := regexp.MatchString(pk, k); matches { + matched = true + break + } + } + + if !regularProperty && k != "$schema" && k != "id" && !matched { + // Special properties "$schema" and "id" are ignored + res.AddErrors(errors.PropertyNotAllowed(o.Path, o.In, k)) + + // BUG(fredbi): This section should move to a part dedicated to spec validation as + // it will conflict with regular schemas where a property "headers" is defined. + + // + // Croaks a more explicit message on top of the standard one + // on some recognized cases. + // + // NOTE: edge cases with invalid type assertion are simply ignored here. + // NOTE: prefix your messages here by "IMPORTANT!" so there are not filtered + // by higher level callers (the IMPORTANT! tag will be eventually + // removed). + switch k { + // $ref is forbidden in header + case "headers": + if val[k] != nil { + if headers, mapOk := val[k].(map[string]interface{}); mapOk { + for headerKey, headerBody := range headers { + if headerBody != nil { + if headerSchema, mapOfMapOk := headerBody.(map[string]interface{}); mapOfMapOk { + if _, found := headerSchema["$ref"]; found { + var msg string + if refString, stringOk := headerSchema["$ref"].(string); stringOk { + msg = strings.Join([]string{", one may not use $ref=\":", refString, "\""}, "") + } + res.AddErrors(refNotAllowedInHeaderMsg(o.Path, headerKey, msg)) + } + } + } + } + } + } + /* + case "$ref": + if val[k] != nil { + // TODO: check context of that ref: warn about siblings, check against invalid context + } + */ + } + } + } + } else { + // Cases: no additionalProperties (implying: true), or additionalProperties: true, or additionalProperties: { <> } + for key, value := range val { + _, regularProperty := o.Properties[key] + + // Validates property against "patternProperties" if applicable + // BUG(fredbi): succeededOnce is always false + + // NOTE: how about regular properties which do not match patternProperties? + matched, succeededOnce, _ := o.validatePatternProperty(key, value, res) + + if !(regularProperty || matched || succeededOnce) { + + // Cases: properties which are not regular properties and have not been matched by the PatternProperties validator + if o.AdditionalProperties != nil && o.AdditionalProperties.Schema != nil { + // AdditionalProperties as Schema + r := NewSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...).Validate(value) + res.mergeForField(data.(map[string]interface{}), key, r) + } else if regularProperty && !(matched || succeededOnce) { + // TODO: this is dead code since regularProperty=false here + res.AddErrors(errors.FailedAllPatternProperties(o.Path, o.In, key)) + } + } + } + // Valid cases: additionalProperties: true or undefined + } + + createdFromDefaults := map[string]bool{} + + // Property types: + // - regular Property + for pName := range o.Properties { + pSchema := o.Properties[pName] // one instance per iteration + rName := pName + if o.Path != "" { + rName = o.Path + "." + pName + } + + // Recursively validates each property against its schema + if v, ok := val[pName]; ok { + r := NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats, o.Options.Options()...).Validate(v) + res.mergeForField(data.(map[string]interface{}), pName, r) + } else if pSchema.Default != nil { + // If a default value is defined, creates the property from defaults + // NOTE: JSON schema does not enforce default values to be valid against schema. Swagger does. + createdFromDefaults[pName] = true + res.addPropertySchemata(data.(map[string]interface{}), pName, &pSchema) + } + } + + // Check required properties + if len(o.Required) > 0 { + for _, k := range o.Required { + if _, ok := val[k]; !ok && !createdFromDefaults[k] { + res.AddErrors(errors.Required(o.Path+"."+k, o.In)) + continue + } + } + } + + // Check patternProperties + // TODO: it looks like we have done that twice in many cases + for key, value := range val { + _, regularProperty := o.Properties[key] + matched, _ /*succeededOnce*/, patterns := o.validatePatternProperty(key, value, res) + if !regularProperty && (matched /*|| succeededOnce*/) { + for _, pName := range patterns { + if v, ok := o.PatternProperties[pName]; ok { + r := NewSchemaValidator(&v, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...).Validate(value) + res.mergeForField(data.(map[string]interface{}), key, r) + } + } + } + } + return res +} + +// TODO: succeededOnce is not used anywhere +func (o *objectValidator) validatePatternProperty(key string, value interface{}, result *Result) (bool, bool, []string) { + matched := false + succeededOnce := false + var patterns []string + + for k, schema := range o.PatternProperties { + sch := schema + if match, _ := regexp.MatchString(k, key); match { + patterns = append(patterns, k) + matched = true + validator := NewSchemaValidator(&sch, o.Root, o.Path+"."+key, o.KnownFormats, o.Options.Options()...) + + res := validator.Validate(value) + result.Merge(res) + } + } + + // BUG(fredbi): can't get to here. Should remove dead code (commented out). + + //if succeededOnce { + // result.Inc() + //} + + return matched, succeededOnce, patterns +} diff --git a/vendor/github.com/go-openapi/validate/options.go b/vendor/github.com/go-openapi/validate/options.go new file mode 100644 index 000000000..deeec2f2e --- /dev/null +++ b/vendor/github.com/go-openapi/validate/options.go @@ -0,0 +1,43 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import "sync" + +// Opts specifies validation options for a SpecValidator. +// +// NOTE: other options might be needed, for example a go-swagger specific mode. +type Opts struct { + ContinueOnErrors bool // true: continue reporting errors, even if spec is invalid +} + +var ( + defaultOpts = Opts{ContinueOnErrors: false} // default is to stop validation on errors + defaultOptsMutex = &sync.Mutex{} +) + +// SetContinueOnErrors sets global default behavior regarding spec validation errors reporting. +// +// For extended error reporting, you most likely want to set it to true. +// For faster validation, it's better to give up early when a spec is detected as invalid: set it to false (this is the default). +// +// Setting this mode does NOT affect the validation status. +// +// NOTE: this method affects global defaults. It is not suitable for a concurrent usage. +func SetContinueOnErrors(c bool) { + defer defaultOptsMutex.Unlock() + defaultOptsMutex.Lock() + defaultOpts.ContinueOnErrors = c +} diff --git a/vendor/github.com/go-openapi/validate/result.go b/vendor/github.com/go-openapi/validate/result.go new file mode 100644 index 000000000..ae9b8dbf2 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/result.go @@ -0,0 +1,484 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "reflect" + "strings" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" +) + +// Result represents a validation result set, composed of +// errors and warnings. +// +// It is used to keep track of all detected errors and warnings during +// the validation of a specification. +// +// Matchcount is used to determine +// which errors are relevant in the case of AnyOf, OneOf +// schema validation. Results from the validation branch +// with most matches get eventually selected. +// +// TODO: keep path of key originating the error +type Result struct { + Errors []error + Warnings []error + MatchCount int + + // the object data + data interface{} + + // Schemata for the root object + rootObjectSchemata schemata + // Schemata for object fields + fieldSchemata []fieldSchemata + // Schemata for slice items + itemSchemata []itemSchemata + + cachedFieldSchemta map[FieldKey][]*spec.Schema + cachedItemSchemata map[ItemKey][]*spec.Schema +} + +// FieldKey is a pair of an object and a field, usable as a key for a map. +type FieldKey struct { + object reflect.Value // actually a map[string]interface{}, but the latter cannot be a key + field string +} + +// ItemKey is a pair of a slice and an index, usable as a key for a map. +type ItemKey struct { + slice reflect.Value // actually a []interface{}, but the latter cannot be a key + index int +} + +// NewFieldKey returns a pair of an object and field usable as a key of a map. +func NewFieldKey(obj map[string]interface{}, field string) FieldKey { + return FieldKey{object: reflect.ValueOf(obj), field: field} +} + +// Object returns the underlying object of this key. +func (fk *FieldKey) Object() map[string]interface{} { + return fk.object.Interface().(map[string]interface{}) +} + +// Field returns the underlying field of this key. +func (fk *FieldKey) Field() string { + return fk.field +} + +// NewItemKey returns a pair of a slice and index usable as a key of a map. +func NewItemKey(slice interface{}, i int) ItemKey { + return ItemKey{slice: reflect.ValueOf(slice), index: i} +} + +// Slice returns the underlying slice of this key. +func (ik *ItemKey) Slice() []interface{} { + return ik.slice.Interface().([]interface{}) +} + +// Index returns the underlying index of this key. +func (ik *ItemKey) Index() int { + return ik.index +} + +type fieldSchemata struct { + obj map[string]interface{} + field string + schemata schemata +} + +type itemSchemata struct { + slice reflect.Value + index int + schemata schemata +} + +// Merge merges this result with the other one(s), preserving match counts etc. +func (r *Result) Merge(others ...*Result) *Result { + for _, other := range others { + if other == nil { + continue + } + r.mergeWithoutRootSchemata(other) + r.rootObjectSchemata.Append(other.rootObjectSchemata) + } + return r +} + +// Data returns the original data object used for validation. Mutating this renders +// the result invalid. +func (r *Result) Data() interface{} { + return r.data +} + +// RootObjectSchemata returns the schemata which apply to the root object. +func (r *Result) RootObjectSchemata() []*spec.Schema { + return r.rootObjectSchemata.Slice() +} + +// FieldSchemata returns the schemata which apply to fields in objects. +func (r *Result) FieldSchemata() map[FieldKey][]*spec.Schema { + if r.cachedFieldSchemta != nil { + return r.cachedFieldSchemta + } + + ret := make(map[FieldKey][]*spec.Schema, len(r.fieldSchemata)) + for _, fs := range r.fieldSchemata { + key := NewFieldKey(fs.obj, fs.field) + if fs.schemata.one != nil { + ret[key] = append(ret[key], fs.schemata.one) + } else if len(fs.schemata.multiple) > 0 { + ret[key] = append(ret[key], fs.schemata.multiple...) + } + } + r.cachedFieldSchemta = ret + return ret +} + +// ItemSchemata returns the schemata which apply to items in slices. +func (r *Result) ItemSchemata() map[ItemKey][]*spec.Schema { + if r.cachedItemSchemata != nil { + return r.cachedItemSchemata + } + + ret := make(map[ItemKey][]*spec.Schema, len(r.itemSchemata)) + for _, ss := range r.itemSchemata { + key := NewItemKey(ss.slice, ss.index) + if ss.schemata.one != nil { + ret[key] = append(ret[key], ss.schemata.one) + } else if len(ss.schemata.multiple) > 0 { + ret[key] = append(ret[key], ss.schemata.multiple...) + } + } + r.cachedItemSchemata = ret + return ret +} + +func (r *Result) resetCaches() { + r.cachedFieldSchemta = nil + r.cachedItemSchemata = nil +} + +// mergeForField merges other into r, assigning other's root schemata to the given Object and field name. +func (r *Result) mergeForField(obj map[string]interface{}, field string, other *Result) *Result { + if other == nil { + return r + } + r.mergeWithoutRootSchemata(other) + + if other.rootObjectSchemata.Len() > 0 { + if r.fieldSchemata == nil { + r.fieldSchemata = make([]fieldSchemata, len(obj)) + } + r.fieldSchemata = append(r.fieldSchemata, fieldSchemata{ + obj: obj, + field: field, + schemata: other.rootObjectSchemata, + }) + } + + return r +} + +// mergeForSlice merges other into r, assigning other's root schemata to the given slice and index. +func (r *Result) mergeForSlice(slice reflect.Value, i int, other *Result) *Result { + if other == nil { + return r + } + r.mergeWithoutRootSchemata(other) + + if other.rootObjectSchemata.Len() > 0 { + if r.itemSchemata == nil { + r.itemSchemata = make([]itemSchemata, slice.Len()) + } + r.itemSchemata = append(r.itemSchemata, itemSchemata{ + slice: slice, + index: i, + schemata: other.rootObjectSchemata, + }) + } + + return r +} + +// addRootObjectSchemata adds the given schemata for the root object of the result. +// The slice schemata might be reused. I.e. do not modify it after being added to a result. +func (r *Result) addRootObjectSchemata(s *spec.Schema) { + r.rootObjectSchemata.Append(schemata{one: s}) +} + +// addPropertySchemata adds the given schemata for the object and field. +// The slice schemata might be reused. I.e. do not modify it after being added to a result. +func (r *Result) addPropertySchemata(obj map[string]interface{}, fld string, schema *spec.Schema) { + if r.fieldSchemata == nil { + r.fieldSchemata = make([]fieldSchemata, 0, len(obj)) + } + r.fieldSchemata = append(r.fieldSchemata, fieldSchemata{obj: obj, field: fld, schemata: schemata{one: schema}}) +} + +// addSliceSchemata adds the given schemata for the slice and index. +// The slice schemata might be reused. I.e. do not modify it after being added to a result. +func (r *Result) addSliceSchemata(slice reflect.Value, i int, schema *spec.Schema) { + if r.itemSchemata == nil { + r.itemSchemata = make([]itemSchemata, 0, slice.Len()) + } + r.itemSchemata = append(r.itemSchemata, itemSchemata{slice: slice, index: i, schemata: schemata{one: schema}}) +} + +// mergeWithoutRootSchemata merges other into r, ignoring the rootObject schemata. +func (r *Result) mergeWithoutRootSchemata(other *Result) { + r.resetCaches() + r.AddErrors(other.Errors...) + r.AddWarnings(other.Warnings...) + r.MatchCount += other.MatchCount + + if other.fieldSchemata != nil { + if r.fieldSchemata == nil { + r.fieldSchemata = other.fieldSchemata + } else { + for _, x := range other.fieldSchemata { + r.fieldSchemata = append(r.fieldSchemata, x) + } + } + } + + if other.itemSchemata != nil { + if r.itemSchemata == nil { + r.itemSchemata = other.itemSchemata + } else { + for _, x := range other.itemSchemata { + r.itemSchemata = append(r.itemSchemata, x) + } + } + } +} + +// MergeAsErrors merges this result with the other one(s), preserving match counts etc. +// +// Warnings from input are merged as Errors in the returned merged Result. +func (r *Result) MergeAsErrors(others ...*Result) *Result { + for _, other := range others { + if other != nil { + r.resetCaches() + r.AddErrors(other.Errors...) + r.AddErrors(other.Warnings...) + r.MatchCount += other.MatchCount + } + } + return r +} + +// MergeAsWarnings merges this result with the other one(s), preserving match counts etc. +// +// Errors from input are merged as Warnings in the returned merged Result. +func (r *Result) MergeAsWarnings(others ...*Result) *Result { + for _, other := range others { + if other != nil { + r.resetCaches() + r.AddWarnings(other.Errors...) + r.AddWarnings(other.Warnings...) + r.MatchCount += other.MatchCount + } + } + return r +} + +// AddErrors adds errors to this validation result (if not already reported). +// +// Since the same check may be passed several times while exploring the +// spec structure (via $ref, ...) reported messages are kept +// unique. +func (r *Result) AddErrors(errors ...error) { + for _, e := range errors { + found := false + if e != nil { + for _, isReported := range r.Errors { + if e.Error() == isReported.Error() { + found = true + break + } + } + if !found { + r.Errors = append(r.Errors, e) + } + } + } +} + +// AddWarnings adds warnings to this validation result (if not already reported). +func (r *Result) AddWarnings(warnings ...error) { + for _, e := range warnings { + found := false + if e != nil { + for _, isReported := range r.Warnings { + if e.Error() == isReported.Error() { + found = true + break + } + } + if !found { + r.Warnings = append(r.Warnings, e) + } + } + } +} + +func (r *Result) keepRelevantErrors() *Result { + // TODO: this one is going to disapear... + // keepRelevantErrors strips a result from standard errors and keeps + // the ones which are supposedly more accurate. + // + // The original result remains unaffected (creates a new instance of Result). + // This method is used to work around the "matchCount" filter which would otherwise + // strip our result from some accurate error reporting from lower level validators. + // + // NOTE: this implementation with a placeholder (IMPORTANT!) is neither clean nor + // very efficient. On the other hand, relying on go-openapi/errors to manipulate + // codes would require to change a lot here. So, for the moment, let's go with + // placeholders. + strippedErrors := []error{} + for _, e := range r.Errors { + if strings.HasPrefix(e.Error(), "IMPORTANT!") { + strippedErrors = append(strippedErrors, fmt.Errorf(strings.TrimPrefix(e.Error(), "IMPORTANT!"))) + } + } + strippedWarnings := []error{} + for _, e := range r.Warnings { + if strings.HasPrefix(e.Error(), "IMPORTANT!") { + strippedWarnings = append(strippedWarnings, fmt.Errorf(strings.TrimPrefix(e.Error(), "IMPORTANT!"))) + } + } + strippedResult := new(Result) + strippedResult.Errors = strippedErrors + strippedResult.Warnings = strippedWarnings + return strippedResult +} + +// IsValid returns true when this result is valid. +// +// Returns true on a nil *Result. +func (r *Result) IsValid() bool { + if r == nil { + return true + } + return len(r.Errors) == 0 +} + +// HasErrors returns true when this result is invalid. +// +// Returns false on a nil *Result. +func (r *Result) HasErrors() bool { + if r == nil { + return false + } + return !r.IsValid() +} + +// HasWarnings returns true when this result contains warnings. +// +// Returns false on a nil *Result. +func (r *Result) HasWarnings() bool { + if r == nil { + return false + } + return len(r.Warnings) > 0 +} + +// HasErrorsOrWarnings returns true when this result contains +// either errors or warnings. +// +// Returns false on a nil *Result. +func (r *Result) HasErrorsOrWarnings() bool { + if r == nil { + return false + } + return len(r.Errors) > 0 || len(r.Warnings) > 0 +} + +// Inc increments the match count +func (r *Result) Inc() { + r.MatchCount++ +} + +// AsError renders this result as an error interface +// +// TODO: reporting / pretty print with path ordered and indented +func (r *Result) AsError() error { + if r.IsValid() { + return nil + } + return errors.CompositeValidationError(r.Errors...) +} + +// schemata is an arbitrary number of schemata. It does a distinction between zero, +// one and many schemata to avoid slice allocations. +type schemata struct { + // one is set if there is exactly one schema. In that case multiple must be nil. + one *spec.Schema + // multiple is an arbitrary number of schemas. If it is set, one must be nil. + multiple []*spec.Schema +} + +func (s *schemata) Len() int { + if s.one != nil { + return 1 + } + return len(s.multiple) +} + +func (s *schemata) Slice() []*spec.Schema { + if s == nil { + return nil + } + if s.one != nil { + return []*spec.Schema{s.one} + } + return s.multiple +} + +// appendSchemata appends the schemata in other to s. It mutated s in-place. +func (s *schemata) Append(other schemata) { + if other.one == nil && len(other.multiple) == 0 { + return + } + if s.one == nil && len(s.multiple) == 0 { + *s = other + return + } + + if s.one != nil { + if other.one != nil { + s.multiple = []*spec.Schema{s.one, other.one} + } else { + t := make([]*spec.Schema, 0, 1+len(other.multiple)) + s.multiple = append(append(t, s.one), other.multiple...) + } + s.one = nil + } else { + if other.one != nil { + s.multiple = append(s.multiple, other.one) + } else { + if cap(s.multiple) >= len(s.multiple)+len(other.multiple) { + s.multiple = append(s.multiple, other.multiple...) + } else { + t := make([]*spec.Schema, 0, len(s.multiple)+len(other.multiple)) + s.multiple = append(append(t, s.multiple...), other.multiple...) + } + } + } +} diff --git a/vendor/github.com/go-openapi/validate/rexp.go b/vendor/github.com/go-openapi/validate/rexp.go new file mode 100644 index 000000000..5a0824395 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/rexp.go @@ -0,0 +1,71 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + re "regexp" + "sync" + "sync/atomic" +) + +// Cache for compiled regular expressions +var ( + cacheMutex = &sync.Mutex{} + reDict = atomic.Value{} //map[string]*re.Regexp +) + +func compileRegexp(pattern string) (*re.Regexp, error) { + if cache, ok := reDict.Load().(map[string]*re.Regexp); ok { + if r := cache[pattern]; r != nil { + return r, nil + } + } + + r, err := re.Compile(pattern) + if err != nil { + return nil, err + } + cacheRegexp(r) + return r, nil +} + +func mustCompileRegexp(pattern string) *re.Regexp { + if cache, ok := reDict.Load().(map[string]*re.Regexp); ok { + if r := cache[pattern]; r != nil { + return r + } + } + + r := re.MustCompile(pattern) + cacheRegexp(r) + return r +} + +func cacheRegexp(r *re.Regexp) { + cacheMutex.Lock() + defer cacheMutex.Unlock() + + if cache, ok := reDict.Load().(map[string]*re.Regexp); !ok || cache[r.String()] == nil { + newCache := map[string]*re.Regexp{ + r.String(): r, + } + + for k, v := range cache { + newCache[k] = v + } + + reDict.Store(newCache) + } +} diff --git a/vendor/github.com/go-openapi/validate/schema.go b/vendor/github.com/go-openapi/validate/schema.go new file mode 100644 index 000000000..9bf8f2eb7 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/schema.go @@ -0,0 +1,253 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "encoding/json" + "reflect" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +var ( + specSchemaType = reflect.TypeOf(&spec.Schema{}) + specParameterType = reflect.TypeOf(&spec.Parameter{}) + specItemsType = reflect.TypeOf(&spec.Items{}) + specHeaderType = reflect.TypeOf(&spec.Header{}) +) + +// SchemaValidator validates data against a JSON schema +type SchemaValidator struct { + Path string + in string + Schema *spec.Schema + validators []valueValidator + Root interface{} + KnownFormats strfmt.Registry + Options *SchemaValidatorOptions +} + +// AgainstSchema validates the specified data against the provided schema, using a registry of supported formats. +// +// When no pre-parsed *spec.Schema structure is provided, it uses a JSON schema as default. See example. +func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry) error { + res := NewSchemaValidator(schema, nil, "", formats).Validate(data) + if res.HasErrors() { + return errors.CompositeValidationError(res.Errors...) + } + return nil +} + +// NewSchemaValidator creates a new schema validator. +// +// Panics if the provided schema is invalid. +func NewSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...Option) *SchemaValidator { + if schema == nil { + return nil + } + + if rootSchema == nil { + rootSchema = schema + } + + if schema.ID != "" || schema.Ref.String() != "" || schema.Ref.IsRoot() { + err := spec.ExpandSchema(schema, rootSchema, nil) + if err != nil { + msg := invalidSchemaProvidedMsg(err).Error() + panic(msg) + } + } + s := SchemaValidator{Path: root, in: "body", Schema: schema, Root: rootSchema, KnownFormats: formats, Options: &SchemaValidatorOptions{}} + for _, o := range options { + o(s.Options) + } + s.validators = []valueValidator{ + s.typeValidator(), + s.schemaPropsValidator(), + s.stringValidator(), + s.formatValidator(), + s.numberValidator(), + s.sliceValidator(), + s.commonValidator(), + s.objectValidator(), + } + return &s +} + +// SetPath sets the path for this schema valdiator +func (s *SchemaValidator) SetPath(path string) { + s.Path = path +} + +// Applies returns true when this schema validator applies +func (s *SchemaValidator) Applies(source interface{}, kind reflect.Kind) bool { + _, ok := source.(*spec.Schema) + return ok +} + +// Validate validates the data against the schema +func (s *SchemaValidator) Validate(data interface{}) *Result { + result := &Result{data: data} + if s == nil { + return result + } + if s.Schema != nil { + result.addRootObjectSchemata(s.Schema) + } + + if data == nil { + result.Merge(s.validators[0].Validate(data)) // type validator + result.Merge(s.validators[6].Validate(data)) // common validator + return result + } + + tpe := reflect.TypeOf(data) + kind := tpe.Kind() + for kind == reflect.Ptr { + tpe = tpe.Elem() + kind = tpe.Kind() + } + d := data + + if kind == reflect.Struct { + // NOTE: since reflect retrieves the true nature of types + // this means that all strfmt types passed here (e.g. strfmt.Datetime, etc..) + // are converted here to strings, and structs are systematically converted + // to map[string]interface{}. + d = swag.ToDynamicJSON(data) + } + + // TODO: this part should be handed over to type validator + // Handle special case of json.Number data (number marshalled as string) + isnumber := s.Schema.Type.Contains("number") || s.Schema.Type.Contains("integer") + if num, ok := data.(json.Number); ok && isnumber { + if s.Schema.Type.Contains("integer") { // avoid lossy conversion + in, erri := num.Int64() + if erri != nil { + result.AddErrors(invalidTypeConversionMsg(s.Path, erri)) + result.Inc() + return result + } + d = in + } else { + nf, errf := num.Float64() + if errf != nil { + result.AddErrors(invalidTypeConversionMsg(s.Path, errf)) + result.Inc() + return result + } + d = nf + } + + tpe = reflect.TypeOf(d) + kind = tpe.Kind() + } + + for _, v := range s.validators { + if !v.Applies(s.Schema, kind) { + debugLog("%T does not apply for %v", v, kind) + continue + } + + err := v.Validate(d) + result.Merge(err) + result.Inc() + } + result.Inc() + + return result +} + +func (s *SchemaValidator) typeValidator() valueValidator { + return &typeValidator{Type: s.Schema.Type, Nullable: s.Schema.Nullable, Format: s.Schema.Format, In: s.in, Path: s.Path} +} + +func (s *SchemaValidator) commonValidator() valueValidator { + return &basicCommonValidator{ + Path: s.Path, + In: s.in, + Enum: s.Schema.Enum, + } +} + +func (s *SchemaValidator) sliceValidator() valueValidator { + return &schemaSliceValidator{ + Path: s.Path, + In: s.in, + MaxItems: s.Schema.MaxItems, + MinItems: s.Schema.MinItems, + UniqueItems: s.Schema.UniqueItems, + AdditionalItems: s.Schema.AdditionalItems, + Items: s.Schema.Items, + Root: s.Root, + KnownFormats: s.KnownFormats, + } +} + +func (s *SchemaValidator) numberValidator() valueValidator { + return &numberValidator{ + Path: s.Path, + In: s.in, + Default: s.Schema.Default, + MultipleOf: s.Schema.MultipleOf, + Maximum: s.Schema.Maximum, + ExclusiveMaximum: s.Schema.ExclusiveMaximum, + Minimum: s.Schema.Minimum, + ExclusiveMinimum: s.Schema.ExclusiveMinimum, + } +} + +func (s *SchemaValidator) stringValidator() valueValidator { + return &stringValidator{ + Path: s.Path, + In: s.in, + MaxLength: s.Schema.MaxLength, + MinLength: s.Schema.MinLength, + Pattern: s.Schema.Pattern, + } +} + +func (s *SchemaValidator) formatValidator() valueValidator { + return &formatValidator{ + Path: s.Path, + In: s.in, + Format: s.Schema.Format, + KnownFormats: s.KnownFormats, + } +} + +func (s *SchemaValidator) schemaPropsValidator() valueValidator { + sch := s.Schema + return newSchemaPropsValidator(s.Path, s.in, sch.AllOf, sch.OneOf, sch.AnyOf, sch.Not, sch.Dependencies, s.Root, s.KnownFormats, s.Options.Options()...) +} + +func (s *SchemaValidator) objectValidator() valueValidator { + return &objectValidator{ + Path: s.Path, + In: s.in, + MaxProperties: s.Schema.MaxProperties, + MinProperties: s.Schema.MinProperties, + Required: s.Schema.Required, + Properties: s.Schema.Properties, + AdditionalProperties: s.Schema.AdditionalProperties, + PatternProperties: s.Schema.PatternProperties, + Root: s.Root, + KnownFormats: s.KnownFormats, + Options: *s.Options, + } +} diff --git a/vendor/github.com/go-openapi/validate/schema_messages.go b/vendor/github.com/go-openapi/validate/schema_messages.go new file mode 100644 index 000000000..786e2e355 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/schema_messages.go @@ -0,0 +1,78 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "github.com/go-openapi/errors" +) + +// Error messages related to schema validation and returned as results. +const ( + // ArrayDoesNotAllowAdditionalItemsError when an additionalItems construct is not verified by the array values provided. + // + // TODO: should move to package go-openapi/errors + ArrayDoesNotAllowAdditionalItemsError = "array doesn't allow for additional items" + + // HasDependencyError indicates that a dependencies construct was not verified + HasDependencyError = "%q has a dependency on %s" + + // InvalidSchemaProvidedError indicates that the schema provided to validate a value cannot be properly compiled + InvalidSchemaProvidedError = "Invalid schema provided to SchemaValidator: %v" + + // InvalidTypeConversionError indicates that a numerical conversion for the given type could not be carried on + InvalidTypeConversionError = "invalid type conversion in %s: %v " + + // MustValidateAtLeastOneSchemaError indicates that in a AnyOf construct, none of the schema constraints specified were verified + MustValidateAtLeastOneSchemaError = "%q must validate at least one schema (anyOf)" + + // MustValidateOnlyOneSchemaError indicates that in a OneOf construct, either none of the schema constraints specified were verified, or several were + MustValidateOnlyOneSchemaError = "%q must validate one and only one schema (oneOf). %s" + + // MustValidateAllSchemasError indicates that in a AllOf construct, at least one of the schema constraints specified were not verified + // + // TODO: punctuation in message + MustValidateAllSchemasError = "%q must validate all the schemas (allOf)%s" + + // MustNotValidateSchemaError indicates that in a Not construct, the schema constraint specified was verified + MustNotValidateSchemaError = "%q must not validate the schema (not)" +) + +// Warning messages related to schema validation and returned as results +const () + +func invalidSchemaProvidedMsg(err error) errors.Error { + return errors.New(InternalErrorCode, InvalidSchemaProvidedError, err) +} +func invalidTypeConversionMsg(path string, err error) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidTypeConversionError, path, err) +} +func mustValidateOnlyOneSchemaMsg(path, additionalMsg string) errors.Error { + return errors.New(errors.CompositeErrorCode, MustValidateOnlyOneSchemaError, path, additionalMsg) +} +func mustValidateAtLeastOneSchemaMsg(path string) errors.Error { + return errors.New(errors.CompositeErrorCode, MustValidateAtLeastOneSchemaError, path) +} +func mustValidateAllSchemasMsg(path, additionalMsg string) errors.Error { + return errors.New(errors.CompositeErrorCode, MustValidateAllSchemasError, path, additionalMsg) +} +func mustNotValidatechemaMsg(path string) errors.Error { + return errors.New(errors.CompositeErrorCode, MustNotValidateSchemaError, path) +} +func hasADependencyMsg(path, depkey string) errors.Error { + return errors.New(errors.CompositeErrorCode, HasDependencyError, path, depkey) +} +func arrayDoesNotAllowAdditionalItemsMsg() errors.Error { + return errors.New(errors.CompositeErrorCode, ArrayDoesNotAllowAdditionalItemsError) +} diff --git a/vendor/github.com/go-openapi/validate/schema_option.go b/vendor/github.com/go-openapi/validate/schema_option.go new file mode 100644 index 000000000..f328b56b8 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/schema_option.go @@ -0,0 +1,33 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +type SchemaValidatorOptions struct { + DisableObjectArrayTypeCheck bool +} + +type Option func(*SchemaValidatorOptions) + +func DisableObjectArrayTypeCheck(disable bool) Option { + return func(svo *SchemaValidatorOptions) { + svo.DisableObjectArrayTypeCheck = disable + } +} + +func (svo SchemaValidatorOptions) Options() []Option { + return []Option{ + DisableObjectArrayTypeCheck(svo.DisableObjectArrayTypeCheck), + } +} diff --git a/vendor/github.com/go-openapi/validate/schema_props.go b/vendor/github.com/go-openapi/validate/schema_props.go new file mode 100644 index 000000000..5643c783c --- /dev/null +++ b/vendor/github.com/go-openapi/validate/schema_props.go @@ -0,0 +1,240 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "reflect" + + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +type schemaPropsValidator struct { + Path string + In string + AllOf []spec.Schema + OneOf []spec.Schema + AnyOf []spec.Schema + Not *spec.Schema + Dependencies spec.Dependencies + anyOfValidators []SchemaValidator + allOfValidators []SchemaValidator + oneOfValidators []SchemaValidator + notValidator *SchemaValidator + Root interface{} + KnownFormats strfmt.Registry + Options SchemaValidatorOptions +} + +func (s *schemaPropsValidator) SetPath(path string) { + s.Path = path +} + +func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry, options ...Option) *schemaPropsValidator { + anyValidators := make([]SchemaValidator, 0, len(anyOf)) + for _, v := range anyOf { + v := v + anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats, options...)) + } + allValidators := make([]SchemaValidator, 0, len(allOf)) + for _, v := range allOf { + v := v + allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats, options...)) + } + oneValidators := make([]SchemaValidator, 0, len(oneOf)) + for _, v := range oneOf { + v := v + oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats, options...)) + } + + var notValidator *SchemaValidator + if not != nil { + notValidator = NewSchemaValidator(not, root, path, formats, options...) + } + + schOptions := &SchemaValidatorOptions{} + for _, o := range options { + o(schOptions) + } + return &schemaPropsValidator{ + Path: path, + In: in, + AllOf: allOf, + OneOf: oneOf, + AnyOf: anyOf, + Not: not, + Dependencies: deps, + anyOfValidators: anyValidators, + allOfValidators: allValidators, + oneOfValidators: oneValidators, + notValidator: notValidator, + Root: root, + KnownFormats: formats, + Options: *schOptions, + } +} + +func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool { + r := reflect.TypeOf(source) == specSchemaType + debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + return r +} + +func (s *schemaPropsValidator) Validate(data interface{}) *Result { + mainResult := new(Result) + + // Intermediary error results + + // IMPORTANT! messages from underlying validators + keepResultAnyOf := new(Result) + keepResultOneOf := new(Result) + keepResultAllOf := new(Result) + + // Validates at least one in anyOf schemas + var firstSuccess *Result + if len(s.anyOfValidators) > 0 { + var bestFailures *Result + succeededOnce := false + for _, anyOfSchema := range s.anyOfValidators { + result := anyOfSchema.Validate(data) + // We keep inner IMPORTANT! errors no matter what MatchCount tells us + keepResultAnyOf.Merge(result.keepRelevantErrors()) + if result.IsValid() { + bestFailures = nil + succeededOnce = true + if firstSuccess == nil { + firstSuccess = result + } + keepResultAnyOf = new(Result) + break + } + // MatchCount is used to select errors from the schema with most positive checks + if bestFailures == nil || result.MatchCount > bestFailures.MatchCount { + bestFailures = result + } + } + + if !succeededOnce { + mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path)) + } + if bestFailures != nil { + mainResult.Merge(bestFailures) + } else if firstSuccess != nil { + mainResult.Merge(firstSuccess) + } + } + + // Validates exactly one in oneOf schemas + if len(s.oneOfValidators) > 0 { + var bestFailures *Result + var firstSuccess *Result + validated := 0 + + for _, oneOfSchema := range s.oneOfValidators { + result := oneOfSchema.Validate(data) + // We keep inner IMPORTANT! errors no matter what MatchCount tells us + keepResultOneOf.Merge(result.keepRelevantErrors()) + if result.IsValid() { + validated++ + bestFailures = nil + if firstSuccess == nil { + firstSuccess = result + } + keepResultOneOf = new(Result) + continue + } + // MatchCount is used to select errors from the schema with most positive checks + if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) { + bestFailures = result + } + } + + if validated != 1 { + additionalMsg := "" + if validated == 0 { + additionalMsg = "Found none valid" + } else { + additionalMsg = fmt.Sprintf("Found %d valid alternatives", validated) + } + + mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, additionalMsg)) + if bestFailures != nil { + mainResult.Merge(bestFailures) + } + } else if firstSuccess != nil { + mainResult.Merge(firstSuccess) + } + } + + // Validates all of allOf schemas + if len(s.allOfValidators) > 0 { + validated := 0 + + for _, allOfSchema := range s.allOfValidators { + result := allOfSchema.Validate(data) + // We keep inner IMPORTANT! errors no matter what MatchCount tells us + keepResultAllOf.Merge(result.keepRelevantErrors()) + //keepResultAllOf.Merge(result) + if result.IsValid() { + validated++ + } + mainResult.Merge(result) + } + + if validated != len(s.allOfValidators) { + additionalMsg := "" + if validated == 0 { + additionalMsg = ". None validated" + } + + mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, additionalMsg)) + } + } + + if s.notValidator != nil { + result := s.notValidator.Validate(data) + // We keep inner IMPORTANT! errors no matter what MatchCount tells us + if result.IsValid() { + mainResult.AddErrors(mustNotValidatechemaMsg(s.Path)) + } + } + + if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map { + val := data.(map[string]interface{}) + for key := range val { + if dep, ok := s.Dependencies[key]; ok { + + if dep.Schema != nil { + mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats, s.Options.Options()...).Validate(data)) + continue + } + + if len(dep.Property) > 0 { + for _, depKey := range dep.Property { + if _, ok := val[depKey]; !ok { + mainResult.AddErrors(hasADependencyMsg(s.Path, depKey)) + } + } + } + } + } + } + + mainResult.Inc() + // In the end we retain best failures for schema validation + // plus, if any, composite errors which may explain special cases (tagged as IMPORTANT!). + return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf) +} diff --git a/vendor/github.com/go-openapi/validate/slice_validator.go b/vendor/github.com/go-openapi/validate/slice_validator.go new file mode 100644 index 000000000..6e615946b --- /dev/null +++ b/vendor/github.com/go-openapi/validate/slice_validator.go @@ -0,0 +1,104 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "reflect" + + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +type schemaSliceValidator struct { + Path string + In string + MaxItems *int64 + MinItems *int64 + UniqueItems bool + AdditionalItems *spec.SchemaOrBool + Items *spec.SchemaOrArray + Root interface{} + KnownFormats strfmt.Registry +} + +func (s *schemaSliceValidator) SetPath(path string) { + s.Path = path +} + +func (s *schemaSliceValidator) Applies(source interface{}, kind reflect.Kind) bool { + _, ok := source.(*spec.Schema) + r := ok && kind == reflect.Slice + return r +} + +func (s *schemaSliceValidator) Validate(data interface{}) *Result { + result := new(Result) + if data == nil { + return result + } + val := reflect.ValueOf(data) + size := val.Len() + + if s.Items != nil && s.Items.Schema != nil { + validator := NewSchemaValidator(s.Items.Schema, s.Root, s.Path, s.KnownFormats) + for i := 0; i < size; i++ { + validator.SetPath(fmt.Sprintf("%s.%d", s.Path, i)) + value := val.Index(i) + result.mergeForSlice(val, i, validator.Validate(value.Interface())) + } + } + + itemsSize := 0 + if s.Items != nil && len(s.Items.Schemas) > 0 { + itemsSize = len(s.Items.Schemas) + for i := 0; i < itemsSize; i++ { + validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats) + if val.Len() <= i { + break + } + result.mergeForSlice(val, int(i), validator.Validate(val.Index(i).Interface())) + } + } + if s.AdditionalItems != nil && itemsSize < size { + if s.Items != nil && len(s.Items.Schemas) > 0 && !s.AdditionalItems.Allows { + result.AddErrors(arrayDoesNotAllowAdditionalItemsMsg()) + } + if s.AdditionalItems.Schema != nil { + for i := itemsSize; i < size-itemsSize+1; i++ { + validator := NewSchemaValidator(s.AdditionalItems.Schema, s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats) + result.mergeForSlice(val, int(i), validator.Validate(val.Index(int(i)).Interface())) + } + } + } + + if s.MinItems != nil { + if err := MinItems(s.Path, s.In, int64(size), *s.MinItems); err != nil { + result.AddErrors(err) + } + } + if s.MaxItems != nil { + if err := MaxItems(s.Path, s.In, int64(size), *s.MaxItems); err != nil { + result.AddErrors(err) + } + } + if s.UniqueItems { + if err := UniqueItems(s.Path, s.In, val.Interface()); err != nil { + result.AddErrors(err) + } + } + result.Inc() + return result +} diff --git a/vendor/github.com/go-openapi/validate/spec.go b/vendor/github.com/go-openapi/validate/spec.go new file mode 100644 index 000000000..08ccd22fe --- /dev/null +++ b/vendor/github.com/go-openapi/validate/spec.go @@ -0,0 +1,777 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/go-openapi/analysis" + "github.com/go-openapi/errors" + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/loads" + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +// Spec validates an OpenAPI 2.0 specification document. +// +// Returns an error flattening in a single standard error, all validation messages. +// +// - TODO: $ref should not have siblings +// - TODO: make sure documentation reflects all checks and warnings +// - TODO: check on discriminators +// - TODO: explicit message on unsupported keywords (better than "forbidden property"...) +// - TODO: full list of unresolved refs +// - TODO: validate numeric constraints (issue#581): this should be handled like defaults and examples +// - TODO: option to determine if we validate for go-swagger or in a more general context +// - TODO: check on required properties to support anyOf, allOf, oneOf +// +// NOTE: SecurityScopes are maps: no need to check uniqueness +// +func Spec(doc *loads.Document, formats strfmt.Registry) error { + errs, _ /*warns*/ := NewSpecValidator(doc.Schema(), formats).Validate(doc) + if errs.HasErrors() { + return errors.CompositeValidationError(errs.Errors...) + } + return nil +} + +// SpecValidator validates a swagger 2.0 spec +type SpecValidator struct { + schema *spec.Schema // swagger 2.0 schema + spec *loads.Document + analyzer *analysis.Spec + expanded *loads.Document + KnownFormats strfmt.Registry + Options Opts // validation options +} + +// NewSpecValidator creates a new swagger spec validator instance +func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidator { + return &SpecValidator{ + schema: schema, + KnownFormats: formats, + Options: defaultOpts, + } +} + +// Validate validates the swagger spec +func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Result) { + var sd *loads.Document + errs = new(Result) + + switch v := data.(type) { + case *loads.Document: + sd = v + } + if sd == nil { + errs.AddErrors(invalidDocumentMsg()) + return + } + s.spec = sd + s.analyzer = analysis.New(sd.Spec()) + + warnings = new(Result) + + // Swagger schema validator + schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats) + var obj interface{} + + // Raw spec unmarshalling errors + if err := json.Unmarshal(sd.Raw(), &obj); err != nil { + // NOTE: under normal conditions, the *load.Document has been already unmarshalled + // So this one is just a paranoid check on the behavior of the spec package + panic(InvalidDocumentError) + } + + defer func() { + // errs holds all errors and warnings, + // warnings only warnings + errs.MergeAsWarnings(warnings) + warnings.AddErrors(errs.Warnings...) + }() + + errs.Merge(schv.Validate(obj)) // error - + // There may be a point in continuing to try and determine more accurate errors + if !s.Options.ContinueOnErrors && errs.HasErrors() { + return // no point in continuing + } + + errs.Merge(s.validateReferencesValid()) // error - + // There may be a point in continuing to try and determine more accurate errors + if !s.Options.ContinueOnErrors && errs.HasErrors() { + return // no point in continuing + } + + errs.Merge(s.validateDuplicateOperationIDs()) + errs.Merge(s.validateDuplicatePropertyNames()) // error - + errs.Merge(s.validateParameters()) // error - + errs.Merge(s.validateItems()) // error - + + // Properties in required definition MUST validate their schema + // Properties SHOULD NOT be declared as both required and readOnly (warning) + errs.Merge(s.validateRequiredDefinitions()) // error and warning + + // There may be a point in continuing to try and determine more accurate errors + if !s.Options.ContinueOnErrors && errs.HasErrors() { + return // no point in continuing + } + + // Values provided as default MUST validate their schema + df := &defaultValidator{SpecValidator: s} + errs.Merge(df.Validate()) + + // Values provided as examples MUST validate their schema + // Value provided as examples in a response without schema generate a warning + // Known limitations: examples in responses for mime type not application/json are ignored (warning) + ex := &exampleValidator{SpecValidator: s} + errs.Merge(ex.Validate()) + + errs.Merge(s.validateNonEmptyPathParamNames()) + + //errs.Merge(s.validateRefNoSibling()) // warning only + errs.Merge(s.validateReferenced()) // warning only + + return +} + +func (s *SpecValidator) validateNonEmptyPathParamNames() *Result { + res := new(Result) + if s.spec.Spec().Paths == nil { + // There is no Paths object: error + res.AddErrors(noValidPathMsg()) + } else { + if s.spec.Spec().Paths.Paths == nil { + // Paths may be empty: warning + res.AddWarnings(noValidPathMsg()) + } else { + for k := range s.spec.Spec().Paths.Paths { + if strings.Contains(k, "{}") { + res.AddErrors(emptyPathParameterMsg(k)) + } + } + } + } + return res +} + +func (s *SpecValidator) validateDuplicateOperationIDs() *Result { + // OperationID, if specified, must be unique across the board + res := new(Result) + known := make(map[string]int) + for _, v := range s.analyzer.OperationIDs() { + if v != "" { + known[v]++ + } + } + for k, v := range known { + if v > 1 { + res.AddErrors(nonUniqueOperationIDMsg(k, v)) + } + } + return res +} + +type dupProp struct { + Name string + Definition string +} + +func (s *SpecValidator) validateDuplicatePropertyNames() *Result { + // definition can't declare a property that's already defined by one of its ancestors + res := new(Result) + for k, sch := range s.spec.Spec().Definitions { + if len(sch.AllOf) == 0 { + continue + } + + knownanc := map[string]struct{}{ + "#/definitions/" + k: {}, + } + + ancs, rec := s.validateCircularAncestry(k, sch, knownanc) + if rec != nil && (rec.HasErrors() || !rec.HasWarnings()) { + res.Merge(rec) + } + if len(ancs) > 0 { + res.AddErrors(circularAncestryDefinitionMsg(k, ancs)) + return res + } + + knowns := make(map[string]struct{}) + dups, rep := s.validateSchemaPropertyNames(k, sch, knowns) + if rep != nil && (rep.HasErrors() || rep.HasWarnings()) { + res.Merge(rep) + } + if len(dups) > 0 { + var pns []string + for _, v := range dups { + pns = append(pns, v.Definition+"."+v.Name) + } + res.AddErrors(duplicatePropertiesMsg(k, pns)) + } + + } + return res +} + +func (s *SpecValidator) resolveRef(ref *spec.Ref) (*spec.Schema, error) { + if s.spec.SpecFilePath() != "" { + return spec.ResolveRefWithBase(s.spec.Spec(), ref, &spec.ExpandOptions{RelativeBase: s.spec.SpecFilePath()}) + } + // NOTE: it looks like with the new spec resolver, this code is now unrecheable + return spec.ResolveRef(s.spec.Spec(), ref) +} + +func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, knowns map[string]struct{}) ([]dupProp, *Result) { + var dups []dupProp + + schn := nm + schc := &sch + res := new(Result) + + for schc.Ref.String() != "" { + // gather property names + reso, err := s.resolveRef(&schc.Ref) + if err != nil { + errorHelp.addPointerError(res, err, schc.Ref.String(), nm) + return dups, res + } + schc = reso + schn = sch.Ref.String() + } + + if len(schc.AllOf) > 0 { + for _, chld := range schc.AllOf { + dup, rep := s.validateSchemaPropertyNames(schn, chld, knowns) + if rep != nil && (rep.HasErrors() || rep.HasWarnings()) { + res.Merge(rep) + } + dups = append(dups, dup...) + } + return dups, res + } + + for k := range schc.Properties { + _, ok := knowns[k] + if ok { + dups = append(dups, dupProp{Name: k, Definition: schn}) + } else { + knowns[k] = struct{}{} + } + } + + return dups, res +} + +func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, knowns map[string]struct{}) ([]string, *Result) { + res := new(Result) + + if sch.Ref.String() == "" && len(sch.AllOf) == 0 { // Safeguard. We should not be able to actually get there + return nil, res + } + var ancs []string + + schn := nm + schc := &sch + + for schc.Ref.String() != "" { + reso, err := s.resolveRef(&schc.Ref) + if err != nil { + errorHelp.addPointerError(res, err, schc.Ref.String(), nm) + return ancs, res + } + schc = reso + schn = sch.Ref.String() + } + + if schn != nm && schn != "" { + if _, ok := knowns[schn]; ok { + ancs = append(ancs, schn) + } + knowns[schn] = struct{}{} + + if len(ancs) > 0 { + return ancs, res + } + } + + if len(schc.AllOf) > 0 { + for _, chld := range schc.AllOf { + if chld.Ref.String() != "" || len(chld.AllOf) > 0 { + anc, rec := s.validateCircularAncestry(schn, chld, knowns) + if rec != nil && (rec.HasErrors() || !rec.HasWarnings()) { + res.Merge(rec) + } + ancs = append(ancs, anc...) + if len(ancs) > 0 { + return ancs, res + } + } + } + } + return ancs, res +} + +func (s *SpecValidator) validateItems() *Result { + // validate parameter, items, schema and response objects for presence of item if type is array + res := new(Result) + + for method, pi := range s.analyzer.Operations() { + for path, op := range pi { + for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { + + if param.TypeName() == "array" && param.ItemsTypeName() == "" { + res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID)) + continue + } + if param.In != "body" { + if param.Items != nil { + items := param.Items + for items.TypeName() == "array" { + if items.ItemsTypeName() == "" { + res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID)) + break + } + items = items.Items + } + } + } else { + // In: body + if param.Schema != nil { + res.Merge(s.validateSchemaItems(*param.Schema, fmt.Sprintf("body param %q", param.Name), op.ID)) + } + } + } + + var responses []spec.Response + if op.Responses != nil { + if op.Responses.Default != nil { + responses = append(responses, *op.Responses.Default) + } + if op.Responses.StatusCodeResponses != nil { + for _, v := range op.Responses.StatusCodeResponses { + responses = append(responses, v) + } + } + } + + for _, resp := range responses { + // Response headers with array + for hn, hv := range resp.Headers { + if hv.TypeName() == "array" && hv.ItemsTypeName() == "" { + res.AddErrors(arrayInHeaderRequiresItemsMsg(hn, op.ID)) + } + } + if resp.Schema != nil { + res.Merge(s.validateSchemaItems(*resp.Schema, "response body", op.ID)) + } + } + } + } + return res +} + +// Verifies constraints on array type +func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) *Result { + res := new(Result) + if !schema.Type.Contains("array") { + return res + } + + if schema.Items == nil || schema.Items.Len() == 0 { + res.AddErrors(arrayRequiresItemsMsg(prefix, opID)) + return res + } + + if schema.Items.Schema != nil { + schema = *schema.Items.Schema + if _, err := compileRegexp(schema.Pattern); err != nil { + res.AddErrors(invalidItemsPatternMsg(prefix, opID, schema.Pattern)) + } + + res.Merge(s.validateSchemaItems(schema, prefix, opID)) + } + return res +} + +func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOperation []string) *Result { + // Each defined operation path parameters must correspond to a named element in the API's path pattern. + // (For example, you cannot have a path parameter named id for the following path /pets/{petId} but you must have a path parameter named petId.) + res := new(Result) + for _, l := range fromPath { + var matched bool + for _, r := range fromOperation { + if l == "{"+r+"}" { + matched = true + break + } + } + if !matched { + res.AddErrors(noParameterInPathMsg(l)) + } + } + + for _, p := range fromOperation { + var matched bool + for _, r := range fromPath { + if "{"+p+"}" == r { + matched = true + break + } + } + if !matched { + res.AddErrors(pathParamNotInPathMsg(path, p)) + } + } + + return res +} + +func (s *SpecValidator) validateReferenced() *Result { + var res Result + res.MergeAsWarnings(s.validateReferencedParameters()) + res.MergeAsWarnings(s.validateReferencedResponses()) + res.MergeAsWarnings(s.validateReferencedDefinitions()) + return &res +} + +func (s *SpecValidator) validateReferencedParameters() *Result { + // Each referenceable definition should have references. + params := s.spec.Spec().Parameters + if len(params) == 0 { + return nil + } + + expected := make(map[string]struct{}) + for k := range params { + expected["#/parameters/"+jsonpointer.Escape(k)] = struct{}{} + } + for _, k := range s.analyzer.AllParameterReferences() { + if _, ok := expected[k]; ok { + delete(expected, k) + } + } + + if len(expected) == 0 { + return nil + } + result := new(Result) + for k := range expected { + result.AddWarnings(unusedParamMsg(k)) + } + return result +} + +func (s *SpecValidator) validateReferencedResponses() *Result { + // Each referenceable definition should have references. + responses := s.spec.Spec().Responses + if len(responses) == 0 { + return nil + } + + expected := make(map[string]struct{}) + for k := range responses { + expected["#/responses/"+jsonpointer.Escape(k)] = struct{}{} + } + for _, k := range s.analyzer.AllResponseReferences() { + if _, ok := expected[k]; ok { + delete(expected, k) + } + } + + if len(expected) == 0 { + return nil + } + result := new(Result) + for k := range expected { + result.AddWarnings(unusedResponseMsg(k)) + } + return result +} + +func (s *SpecValidator) validateReferencedDefinitions() *Result { + // Each referenceable definition must have references. + defs := s.spec.Spec().Definitions + if len(defs) == 0 { + return nil + } + + expected := make(map[string]struct{}) + for k := range defs { + expected["#/definitions/"+jsonpointer.Escape(k)] = struct{}{} + } + for _, k := range s.analyzer.AllDefinitionReferences() { + if _, ok := expected[k]; ok { + delete(expected, k) + } + } + + if len(expected) == 0 { + return nil + } + + result := new(Result) + for k := range expected { + result.AddWarnings(unusedDefinitionMsg(k)) + } + return result +} + +func (s *SpecValidator) validateRequiredDefinitions() *Result { + // Each property listed in the required array must be defined in the properties of the model + res := new(Result) + +DEFINITIONS: + for d, schema := range s.spec.Spec().Definitions { + if schema.Required != nil { // Safeguard + for _, pn := range schema.Required { + red := s.validateRequiredProperties(pn, d, &schema) + res.Merge(red) + if !red.IsValid() && !s.Options.ContinueOnErrors { + break DEFINITIONS // there is an error, let's stop that bleeding + } + } + } + } + return res +} + +func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Schema) *Result { + // Takes care of recursive property definitions, which may be nested in additionalProperties schemas + res := new(Result) + propertyMatch := false + patternMatch := false + additionalPropertiesMatch := false + isReadOnly := false + + // Regular properties + if _, ok := v.Properties[path]; ok { + propertyMatch = true + isReadOnly = v.Properties[path].ReadOnly + } + + // NOTE: patternProperties are not supported in swagger. Even though, we continue validation here + // We check all defined patterns: if one regexp is invalid, croaks an error + for pp, pv := range v.PatternProperties { + re, err := compileRegexp(pp) + if err != nil { + res.AddErrors(invalidPatternMsg(pp, in)) + } else if re.MatchString(path) { + patternMatch = true + if !propertyMatch { + isReadOnly = pv.ReadOnly + } + } + } + + if !(propertyMatch || patternMatch) { + if v.AdditionalProperties != nil { + if v.AdditionalProperties.Allows && v.AdditionalProperties.Schema == nil { + additionalPropertiesMatch = true + } else if v.AdditionalProperties.Schema != nil { + // additionalProperties as schema are upported in swagger + // recursively validates additionalProperties schema + // TODO : anyOf, allOf, oneOf like in schemaPropsValidator + red := s.validateRequiredProperties(path, in, v.AdditionalProperties.Schema) + if red.IsValid() { + additionalPropertiesMatch = true + if !propertyMatch && !patternMatch { + isReadOnly = v.AdditionalProperties.Schema.ReadOnly + } + } + res.Merge(red) + } + } + } + + if !(propertyMatch || patternMatch || additionalPropertiesMatch) { + res.AddErrors(requiredButNotDefinedMsg(path, in)) + } + + if isReadOnly { + res.AddWarnings(readOnlyAndRequiredMsg(in, path)) + } + return res +} + +func (s *SpecValidator) validateParameters() *Result { + // - for each method, path is unique, regardless of path parameters + // e.g. GET:/petstore/{id}, GET:/petstore/{pet}, GET:/petstore are + // considered duplicate paths + // - each parameter should have a unique `name` and `type` combination + // - each operation should have only 1 parameter of type body + // - there must be at most 1 parameter in body + // - parameters with pattern property must specify valid patterns + // - $ref in parameters must resolve + // - path param must be required + res := new(Result) + rexGarbledPathSegment := mustCompileRegexp(`.*[{}\s]+.*`) + for method, pi := range s.analyzer.Operations() { + methodPaths := make(map[string]map[string]string) + if pi != nil { // Safeguard + for path, op := range pi { + pathToAdd := pathHelp.stripParametersInPath(path) + + // Warn on garbled path afer param stripping + if rexGarbledPathSegment.MatchString(pathToAdd) { + res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd)) + } + + // Check uniqueness of stripped paths + if _, found := methodPaths[method][pathToAdd]; found { + + // Sort names for stable, testable output + if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 { + res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd])) + } else { + res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path)) + } + } else { + if _, found := methodPaths[method]; !found { + methodPaths[method] = map[string]string{} + } + methodPaths[method][pathToAdd] = path //Original non stripped path + + } + + var bodyParams []string + var paramNames []string + var hasForm, hasBody bool + + // Check parameters names uniqueness for operation + // TODO: should be done after param expansion + res.Merge(s.checkUniqueParams(path, method, op)) + + for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) { + // Validate pattern regexp for parameters with a Pattern property + if _, err := compileRegexp(pr.Pattern); err != nil { + res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern)) + } + + // There must be at most one parameter in body: list them all + if pr.In == "body" { + bodyParams = append(bodyParams, fmt.Sprintf("%q", pr.Name)) + hasBody = true + } + + if pr.In == "path" { + paramNames = append(paramNames, pr.Name) + // Path declared in path must have the required: true property + if !pr.Required { + res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name)) + } + } + + if pr.In == "formData" { + hasForm = true + } + } + + // In:formData and In:body are mutually exclusive + if hasBody && hasForm { + res.AddErrors(bothFormDataAndBodyMsg(op.ID)) + } + // There must be at most one body param + // Accurately report situations when more than 1 body param is declared (possibly unnamed) + if len(bodyParams) > 1 { + sort.Strings(bodyParams) + res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams)) + } + + // Check uniqueness of parameters in path + paramsInPath := pathHelp.extractPathParams(path) + for i, p := range paramsInPath { + for j, q := range paramsInPath { + if p == q && i > j { + res.AddErrors(pathParamNotUniqueMsg(path, p, q)) + break + } + } + } + + // Warns about possible malformed params in path + rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`) + for _, p := range paramsInPath { + if rexGarbledParam.MatchString(p) { + res.AddWarnings(pathParamGarbledMsg(path, p)) + } + } + + // Match params from path vs params from params section + res.Merge(s.validatePathParamPresence(path, paramsInPath, paramNames)) + } + } + } + return res +} + +func (s *SpecValidator) validateReferencesValid() *Result { + // each reference must point to a valid object + res := new(Result) + for _, r := range s.analyzer.AllRefs() { + if !r.IsValidURI(s.spec.SpecFilePath()) { // Safeguard - spec should always yield a valid URI + res.AddErrors(invalidRefMsg(r.String())) + } + } + if !res.HasErrors() { + // NOTE: with default settings, loads.Document.Expanded() + // stops on first error. Anyhow, the expand option to continue + // on errors fails to report errors at all. + exp, err := s.spec.Expanded() + if err != nil { + res.AddErrors(unresolvedReferencesMsg(err)) + } + s.expanded = exp + } + return res +} + +func (s *SpecValidator) checkUniqueParams(path, method string, op *spec.Operation) *Result { + // Check for duplicate parameters declaration in param section. + // Each parameter should have a unique `name` and `type` combination + // NOTE: this could be factorized in analysis (when constructing the params map) + // However, there are some issues with such a factorization: + // - analysis does not seem to fully expand params + // - param keys may be altered by x-go-name + res := new(Result) + pnames := make(map[string]struct{}) + + if op.Parameters != nil { // Safeguard + for _, ppr := range op.Parameters { + var ok bool + pr, red := paramHelp.resolveParam(path, method, op.ID, &ppr, s) + res.Merge(red) + + if pr != nil && pr.Name != "" { // params with empty name does no participate the check + key := fmt.Sprintf("%s#%s", pr.In, pr.Name) + + if _, ok = pnames[key]; ok { + res.AddErrors(duplicateParamNameMsg(pr.In, pr.Name, op.ID)) + } + pnames[key] = struct{}{} + } + } + } + return res +} + +// SetContinueOnErrors sets the ContinueOnErrors option for this validator. +func (s *SpecValidator) SetContinueOnErrors(c bool) { + s.Options.ContinueOnErrors = c +} diff --git a/vendor/github.com/go-openapi/validate/spec_messages.go b/vendor/github.com/go-openapi/validate/spec_messages.go new file mode 100644 index 000000000..441bb5197 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/spec_messages.go @@ -0,0 +1,354 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "net/http" + + "github.com/go-openapi/errors" +) + +// Error messages related to spec validation and returned as results. +const ( + // ArrayRequiresItemsError ... + ArrayRequiresItemsError = "%s for %q is a collection without an element type (array requires items definition)" + + // ArrayInParamRequiresItemsError ... + ArrayInParamRequiresItemsError = "param %q for %q is a collection without an element type (array requires item definition)" + + // ArrayInHeaderRequiresItemsError ... + ArrayInHeaderRequiresItemsError = "header %q for %q is a collection without an element type (array requires items definition)" + + // BothFormDataAndBodyError indicates that an operation specifies both a body and a formData parameter, which is forbidden + BothFormDataAndBodyError = "operation %q has both formData and body parameters. Only one such In: type may be used for a given operation" + + // CannotResolveRefError when a $ref could not be resolved + CannotResolveReferenceError = "could not resolve reference in %s to $ref %s: %v" + + // CircularAncestryDefinitionError ... + CircularAncestryDefinitionError = "definition %q has circular ancestry: %v" + + // DefaultValueDoesNotValidateError results from an invalid default value provided + DefaultValueDoesNotValidateError = "default value for %s in %s does not validate its schema" + + // DefaultValueItemsDoesNotValidateError results from an invalid default value provided for Items + DefaultValueItemsDoesNotValidateError = "default value for %s.items in %s does not validate its schema" + + // DefaultValueHeaderDoesNotValidateError results from an invalid default value provided in header + DefaultValueHeaderDoesNotValidateError = "in operation %q, default value in header %s for %s does not validate its schema" + + // DefaultValueHeaderItemsDoesNotValidateError results from an invalid default value provided in header.items + DefaultValueHeaderItemsDoesNotValidateError = "in operation %q, default value in header.items %s for %s does not validate its schema" + + // DefaultValueInDoesNotValidateError ... + DefaultValueInDoesNotValidateError = "in operation %q, default value in %s does not validate its schema" + + // DuplicateParamNameError ... + DuplicateParamNameError = "duplicate parameter name %q for %q in operation %q" + + // DuplicatePropertiesError ... + DuplicatePropertiesError = "definition %q contains duplicate properties: %v" + + // ExampleValueDoesNotValidateError results from an invalid example value provided + ExampleValueDoesNotValidateError = "example value for %s in %s does not validate its schema" + + // ExampleValueItemsDoesNotValidateError results from an invalid example value provided for Items + ExampleValueItemsDoesNotValidateError = "example value for %s.items in %s does not validate its schema" + + // ExampleValueHeaderDoesNotValidateError results from an invalid example value provided in header + ExampleValueHeaderDoesNotValidateError = "in operation %q, example value in header %s for %s does not validate its schema" + + // ExampleValueHeaderItemsDoesNotValidateError results from an invalid example value provided in header.items + ExampleValueHeaderItemsDoesNotValidateError = "in operation %q, example value in header.items %s for %s does not validate its schema" + + // ExampleValueInDoesNotValidateError ... + ExampleValueInDoesNotValidateError = "in operation %q, example value in %s does not validate its schema" + + // EmptyPathParameterError means that a path parameter was found empty (e.g. "{}") + EmptyPathParameterError = "%q contains an empty path parameter" + + // InvalidDocumentError states that spec validation only processes spec.Document objects + InvalidDocumentError = "spec validator can only validate spec.Document objects" + + // InvalidItemsPatternError indicates an Items definition with invalid pattern + InvalidItemsPatternError = "%s for %q has invalid items pattern: %q" + + // InvalidParameterDefinitionError indicates an error detected on a parameter definition + InvalidParameterDefinitionError = "invalid definition for parameter %s in %s in operation %q" + + // InvalidParameterDefinitionAsSchemaError indicates an error detected on a parameter definition, which was mistaken with a schema definition. + // Most likely, this situation is encountered whenever a $ref has been added as a sibling of the parameter definition. + InvalidParameterDefinitionAsSchemaError = "invalid definition as Schema for parameter %s in %s in operation %q" + + // InvalidPatternError ... + InvalidPatternError = "pattern %q is invalid in %s" + + // InvalidPatternInError indicates an invalid pattern in a schema or items definition + InvalidPatternInError = "%s in %s has invalid pattern: %q" + + // InvalidPatternInHeaderError indicates a header definition with an invalid pattern + InvalidPatternInHeaderError = "in operation %q, header %s for %s has invalid pattern %q: %v" + + // InvalidPatternInParamError ... + InvalidPatternInParamError = "operation %q has invalid pattern in param %q: %q" + + // InvalidReferenceError indicates that a $ref property could not be resolved + InvalidReferenceError = "invalid ref %q" + + // InvalidResponseDefinitionAsSchemaError indicates an error detected on a response definition, which was mistaken with a schema definition. + // Most likely, this situation is encountered whenever a $ref has been added as a sibling of the response definition. + InvalidResponseDefinitionAsSchemaError = "invalid definition as Schema for response %s in %s" + + // MultipleBodyParamError indicates that an operation specifies multiple parameter with in: body + MultipleBodyParamError = "operation %q has more than 1 body param: %v" + + // NonUniqueOperationIDError indicates that the same operationId has been specified several times + NonUniqueOperationIDError = "%q is defined %d times" + + // NoParameterInPathError indicates that a path was found without any parameter + NoParameterInPathError = "path param %q has no parameter definition" + + // NoValidPathErrorOrWarning indicates that no single path could be validated. If Paths is empty, this message is only a warning. + NoValidPathErrorOrWarning = "spec has no valid path defined" + + // NoValidResponseError indicates that no valid response description could be found for an operation + NoValidResponseError = "operation %q has no valid response" + + // PathOverlapError ... + PathOverlapError = "path %s overlaps with %s" + + // PathParamNotInPathError indicates that a parameter specified with in: path was not found in the path specification + PathParamNotInPathError = "path param %q is not present in path %q" + + // PathParamNotUniqueError ... + PathParamNotUniqueError = "params in path %q must be unique: %q conflicts with %q" + + // PathParamNotRequiredError ... + PathParamRequiredError = "in operation %q,path param %q must be declared as required" + + // RefNotAllowedInHeaderError indicates a $ref was found in a header definition, which is not allowed by Swagger + RefNotAllowedInHeaderError = "IMPORTANT!in %q: $ref are not allowed in headers. In context for header %q%s" + + // RequiredButNotDefinedError ... + RequiredButNotDefinedError = "%q is present in required but not defined as property in definition %q" + + // SomeParametersBrokenError indicates that some parameters could not be resolved, which might result in partial checks to be carried on + SomeParametersBrokenError = "some parameters definitions are broken in %q.%s. Cannot carry on full checks on parameters for operation %s" + + // UnresolvedReferencesError indicates that at least one $ref could not be resolved + UnresolvedReferencesError = "some references could not be resolved in spec. First found: %v" +) + +// Warning messages related to spec validation and returned as results +const ( + // ExamplesWithoutSchemaWarning indicates that examples are provided for a response,but not schema to validate the example against + ExamplesWithoutSchemaWarning = "Examples provided without schema in operation %q, %s" + + // ExamplesMimeNotSupportedWarning indicates that examples are provided with a mime type different than application/json, which + // the validator dos not support yetl + ExamplesMimeNotSupportedWarning = "No validation attempt for examples for media types other than application/json, in operation %q, %s" + + // PathParamGarbledWarning ... + PathParamGarbledWarning = "in path %q, param %q contains {,} or white space. Albeit not stricly illegal, this is probably no what you want" + + // PathStrippedParamGarbledWarning ... + PathStrippedParamGarbledWarning = "path stripped from path parameters %s contains {,} or white space. This is probably no what you want." + + // ReadOnlyAndRequiredWarning ... + ReadOnlyAndRequiredWarning = "Required property %s in %q should not be marked as both required and readOnly" + + // RefShouldNotHaveSiblingsWarning indicates that a $ref was found with a sibling definition. This results in the $ref taking over its siblings, + // which is most likely not wanted. + RefShouldNotHaveSiblingsWarning = "$ref property should have no sibling in %q.%s" + + // RequiredHasDefaultWarning indicates that a required parameter property should not have a default + RequiredHasDefaultWarning = "%s in %s has a default value and is required as parameter" + + // UnusedDefinitionWarning ... + UnusedDefinitionWarning = "definition %q is not used anywhere" + + // UnusedParamWarning ... + UnusedParamWarning = "parameter %q is not used anywhere" + + // UnusedResponseWarning ... + UnusedResponseWarning = "response %q is not used anywhere" +) + +// Additional error codes +const ( + // InternalErrorCode reports an internal technical error + InternalErrorCode = http.StatusInternalServerError + // NotFoundErrorCode indicates that a resource (e.g. a $ref) could not be found + NotFoundErrorCode = http.StatusNotFound +) + +func invalidDocumentMsg() errors.Error { + return errors.New(InternalErrorCode, InvalidDocumentError) +} +func invalidRefMsg(path string) errors.Error { + return errors.New(NotFoundErrorCode, InvalidReferenceError, path) +} +func unresolvedReferencesMsg(err error) errors.Error { + return errors.New(errors.CompositeErrorCode, UnresolvedReferencesError, err) +} +func noValidPathMsg() errors.Error { + return errors.New(errors.CompositeErrorCode, NoValidPathErrorOrWarning) +} +func emptyPathParameterMsg(path string) errors.Error { + return errors.New(errors.CompositeErrorCode, EmptyPathParameterError, path) +} +func nonUniqueOperationIDMsg(path string, i int) errors.Error { + return errors.New(errors.CompositeErrorCode, NonUniqueOperationIDError, path, i) +} +func circularAncestryDefinitionMsg(path string, args interface{}) errors.Error { + return errors.New(errors.CompositeErrorCode, CircularAncestryDefinitionError, path, args) +} +func duplicatePropertiesMsg(path string, args interface{}) errors.Error { + return errors.New(errors.CompositeErrorCode, DuplicatePropertiesError, path, args) +} +func pathParamNotInPathMsg(path, param string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathParamNotInPathError, param, path) +} +func arrayRequiresItemsMsg(path, operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, ArrayRequiresItemsError, path, operation) +} +func arrayInParamRequiresItemsMsg(path, operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, ArrayInParamRequiresItemsError, path, operation) +} +func arrayInHeaderRequiresItemsMsg(path, operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, ArrayInHeaderRequiresItemsError, path, operation) +} +func invalidItemsPatternMsg(path, operation, pattern string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidItemsPatternError, path, operation, pattern) +} +func invalidPatternMsg(pattern, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidPatternError, pattern, path) +} +func requiredButNotDefinedMsg(path, definition string) errors.Error { + return errors.New(errors.CompositeErrorCode, RequiredButNotDefinedError, path, definition) +} +func pathParamGarbledMsg(path, param string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathParamGarbledWarning, path, param) +} +func pathStrippedParamGarbledMsg(path string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathStrippedParamGarbledWarning, path) +} +func pathOverlapMsg(path, arg string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathOverlapError, path, arg) +} +func invalidPatternInParamMsg(operation, param, pattern string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidPatternInParamError, operation, param, pattern) +} +func pathParamRequiredMsg(operation, param string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathParamRequiredError, operation, param) +} +func bothFormDataAndBodyMsg(operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, BothFormDataAndBodyError, operation) +} +func multipleBodyParamMsg(operation string, args interface{}) errors.Error { + return errors.New(errors.CompositeErrorCode, MultipleBodyParamError, operation, args) +} +func pathParamNotUniqueMsg(path, param, arg string) errors.Error { + return errors.New(errors.CompositeErrorCode, PathParamNotUniqueError, path, param, arg) +} +func duplicateParamNameMsg(path, param, operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, DuplicateParamNameError, param, path, operation) +} +func unusedParamMsg(arg string) errors.Error { + return errors.New(errors.CompositeErrorCode, UnusedParamWarning, arg) +} +func unusedDefinitionMsg(arg string) errors.Error { + return errors.New(errors.CompositeErrorCode, UnusedDefinitionWarning, arg) +} +func unusedResponseMsg(arg string) errors.Error { + return errors.New(errors.CompositeErrorCode, UnusedResponseWarning, arg) +} +func readOnlyAndRequiredMsg(path, param string) errors.Error { + return errors.New(errors.CompositeErrorCode, ReadOnlyAndRequiredWarning, param, path) +} +func noParameterInPathMsg(param string) errors.Error { + return errors.New(errors.CompositeErrorCode, NoParameterInPathError, param) +} +func requiredHasDefaultMsg(param, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, RequiredHasDefaultWarning, param, path) +} +func defaultValueDoesNotValidateMsg(param, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, DefaultValueDoesNotValidateError, param, path) +} +func defaultValueItemsDoesNotValidateMsg(param, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, DefaultValueItemsDoesNotValidateError, param, path) +} +func noValidResponseMsg(operation string) errors.Error { + return errors.New(errors.CompositeErrorCode, NoValidResponseError, operation) +} +func defaultValueHeaderDoesNotValidateMsg(operation, header, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, DefaultValueHeaderDoesNotValidateError, operation, header, path) +} +func defaultValueHeaderItemsDoesNotValidateMsg(operation, header, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, DefaultValueHeaderItemsDoesNotValidateError, operation, header, path) +} +func invalidPatternInHeaderMsg(operation, header, path, pattern string, args interface{}) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidPatternInHeaderError, operation, header, path, pattern, args) +} +func invalidPatternInMsg(path, in, pattern string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidPatternInError, path, in, pattern) +} +func defaultValueInDoesNotValidateMsg(operation, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, DefaultValueInDoesNotValidateError, operation, path) +} +func exampleValueDoesNotValidateMsg(param, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExampleValueDoesNotValidateError, param, path) +} +func exampleValueItemsDoesNotValidateMsg(param, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExampleValueItemsDoesNotValidateError, param, path) +} +func exampleValueHeaderDoesNotValidateMsg(operation, header, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExampleValueHeaderDoesNotValidateError, operation, header, path) +} +func exampleValueHeaderItemsDoesNotValidateMsg(operation, header, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExampleValueHeaderItemsDoesNotValidateError, operation, header, path) +} +func exampleValueInDoesNotValidateMsg(operation, path string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExampleValueInDoesNotValidateError, operation, path) +} +func examplesWithoutSchemaMsg(operation, response string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExamplesWithoutSchemaWarning, operation, response) +} +func examplesMimeNotSupportedMsg(operation, response string) errors.Error { + return errors.New(errors.CompositeErrorCode, ExamplesMimeNotSupportedWarning, operation, response) +} +func refNotAllowedInHeaderMsg(path, header, ref string) errors.Error { + return errors.New(errors.CompositeErrorCode, RefNotAllowedInHeaderError, path, header, ref) +} +func cannotResolveRefMsg(path, ref string, err error) errors.Error { + return errors.New(errors.CompositeErrorCode, CannotResolveReferenceError, path, ref, err) +} +func invalidParameterDefinitionMsg(path, method, operationID string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidParameterDefinitionError, path, method, operationID) +} +func invalidParameterDefinitionAsSchemaMsg(path, method, operationID string) errors.Error { + return errors.New(errors.CompositeErrorCode, InvalidParameterDefinitionAsSchemaError, path, method, operationID) +} + +// disabled +//func invalidResponseDefinitionAsSchemaMsg(path, method string) errors.Error { +// return errors.New(errors.CompositeErrorCode, InvalidResponseDefinitionAsSchemaError, path, method) +//} +func someParametersBrokenMsg(path, method, operationID string) errors.Error { + return errors.New(errors.CompositeErrorCode, SomeParametersBrokenError, path, method, operationID) +} +func refShouldNotHaveSiblingsMsg(path, operationID string) errors.Error { + return errors.New(errors.CompositeErrorCode, RefShouldNotHaveSiblingsWarning, operationID, path) +} diff --git a/vendor/github.com/go-openapi/validate/type.go b/vendor/github.com/go-openapi/validate/type.go new file mode 100644 index 000000000..ba0e956d6 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/type.go @@ -0,0 +1,178 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "reflect" + "strings" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +type typeValidator struct { + Type spec.StringOrArray + Nullable bool + Format string + In string + Path string +} + +func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) { + // internal type to JSON type with swagger 2.0 format (with go-openapi/strfmt extensions), + // see https://github.com/go-openapi/strfmt/blob/master/README.md + // TODO: this switch really is some sort of reverse lookup for formats. It should be provided by strfmt. + switch data.(type) { + case []byte, strfmt.Base64, *strfmt.Base64: + return "string", "byte" + case strfmt.CreditCard, *strfmt.CreditCard: + return "string", "creditcard" + case strfmt.Date, *strfmt.Date: + return "string", "date" + case strfmt.DateTime, *strfmt.DateTime: + return "string", "date-time" + case strfmt.Duration, *strfmt.Duration: + return "string", "duration" + case runtime.File, *runtime.File: + return "file", "" + case strfmt.Email, *strfmt.Email: + return "string", "email" + case strfmt.HexColor, *strfmt.HexColor: + return "string", "hexcolor" + case strfmt.Hostname, *strfmt.Hostname: + return "string", "hostname" + case strfmt.IPv4, *strfmt.IPv4: + return "string", "ipv4" + case strfmt.IPv6, *strfmt.IPv6: + return "string", "ipv6" + case strfmt.ISBN, *strfmt.ISBN: + return "string", "isbn" + case strfmt.ISBN10, *strfmt.ISBN10: + return "string", "isbn10" + case strfmt.ISBN13, *strfmt.ISBN13: + return "string", "isbn13" + case strfmt.MAC, *strfmt.MAC: + return "string", "mac" + case strfmt.ObjectId, *strfmt.ObjectId: + return "string", "bsonobjectid" + case strfmt.Password, *strfmt.Password: + return "string", "password" + case strfmt.RGBColor, *strfmt.RGBColor: + return "string", "rgbcolor" + case strfmt.SSN, *strfmt.SSN: + return "string", "ssn" + case strfmt.URI, *strfmt.URI: + return "string", "uri" + case strfmt.UUID, *strfmt.UUID: + return "string", "uuid" + case strfmt.UUID3, *strfmt.UUID3: + return "string", "uuid3" + case strfmt.UUID4, *strfmt.UUID4: + return "string", "uuid4" + case strfmt.UUID5, *strfmt.UUID5: + return "string", "uuid5" + // TODO: missing binary (io.ReadCloser) + // TODO: missing json.Number + default: + val := reflect.ValueOf(data) + tpe := val.Type() + switch tpe.Kind() { + case reflect.Bool: + return "boolean", "" + case reflect.String: + return "string", "" + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32: + // NOTE: that is the spec. With go-openapi, is that not uint32 for unsigned integers? + return "integer", "int32" + case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64: + return "integer", "int64" + case reflect.Float32: + // NOTE: is that not "float"? + return "number", "float32" + case reflect.Float64: + // NOTE: is that not "double"? + return "number", "float64" + // NOTE: go arrays (reflect.Array) are not supported (fixed length) + case reflect.Slice: + return "array", "" + case reflect.Map, reflect.Struct: + return "object", "" + case reflect.Interface: + // What to do here? + panic("dunno what to do here") + case reflect.Ptr: + return t.schemaInfoForType(reflect.Indirect(val).Interface()) + } + } + return "", "" +} + +func (t *typeValidator) SetPath(path string) { + t.Path = path +} + +func (t *typeValidator) Applies(source interface{}, kind reflect.Kind) bool { + // typeValidator applies to Schema, Parameter and Header objects + stpe := reflect.TypeOf(source) + r := (len(t.Type) > 0 || t.Format != "") && (stpe == specSchemaType || stpe == specParameterType || stpe == specHeaderType) + debugLog("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind) + return r +} + +func (t *typeValidator) Validate(data interface{}) *Result { + result := new(Result) + result.Inc() + if data == nil || reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)), reflect.ValueOf(data)) { + // nil or zero value for the passed structure require Type: null + if len(t.Type) > 0 && !t.Type.Contains("null") && !t.Nullable { // TODO: if a property is not required it also passes this + return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), "null")) + } + return result + } + + // check if the type matches, should be used in every validator chain as first item + val := reflect.Indirect(reflect.ValueOf(data)) + kind := val.Kind() + + // infer schema type (JSON) and format from passed data type + schType, format := t.schemaInfoForType(data) + + debugLog("path: %s, schType: %s, format: %s, expType: %s, expFmt: %s, kind: %s", t.Path, schType, format, t.Type, t.Format, val.Kind().String()) + + // check numerical types + // TODO: check unsigned ints + // TODO: check json.Number (see schema.go) + isLowerInt := t.Format == "int64" && format == "int32" + isLowerFloat := t.Format == "float64" && format == "float32" + isFloatInt := schType == "number" && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains("integer") + isIntFloat := schType == "integer" && t.Type.Contains("number") + + if kind != reflect.String && kind != reflect.Slice && t.Format != "" && !(t.Type.Contains(schType) || format == t.Format || isFloatInt || isIntFloat || isLowerInt || isLowerFloat) { + // TODO: test case + return errorHelp.sErr(errors.InvalidType(t.Path, t.In, t.Format, format)) + } + + if !(t.Type.Contains("number") || t.Type.Contains("integer")) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) { + return result + } + + if !(t.Type.Contains(schType) || isFloatInt || isIntFloat) { + return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), schType)) + } + return result +} diff --git a/vendor/github.com/go-openapi/validate/update-fixtures.sh b/vendor/github.com/go-openapi/validate/update-fixtures.sh new file mode 100644 index 000000000..21b06e2b0 --- /dev/null +++ b/vendor/github.com/go-openapi/validate/update-fixtures.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eu -o pipefail +dir=$(git rev-parse --show-toplevel) +scratch=$(mktemp -d -t tmp.XXXXXXXXXX) + +function finish { + rm -rf "$scratch" +} +trap finish EXIT SIGHUP SIGINT SIGTERM + +cd "$scratch" +git clone https://github.com/json-schema-org/JSON-Schema-Test-Suite Suite +cp -r Suite/tests/draft4/* "$dir/fixtures/jsonschema_suite" +cp -a Suite/remotes "$dir/fixtures/jsonschema_suite" diff --git a/vendor/github.com/go-openapi/validate/validator.go b/vendor/github.com/go-openapi/validate/validator.go new file mode 100644 index 000000000..df700d3cd --- /dev/null +++ b/vendor/github.com/go-openapi/validate/validator.go @@ -0,0 +1,641 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "reflect" + + "github.com/go-openapi/errors" + "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" +) + +// An EntityValidator is an interface for things that can validate entities +type EntityValidator interface { + Validate(interface{}) *Result +} + +type valueValidator interface { + SetPath(path string) + Applies(interface{}, reflect.Kind) bool + Validate(interface{}) *Result +} + +type itemsValidator struct { + items *spec.Items + root interface{} + path string + in string + validators []valueValidator + KnownFormats strfmt.Registry +} + +func newItemsValidator(path, in string, items *spec.Items, root interface{}, formats strfmt.Registry) *itemsValidator { + iv := &itemsValidator{path: path, in: in, items: items, root: root, KnownFormats: formats} + iv.validators = []valueValidator{ + &typeValidator{ + Type: spec.StringOrArray([]string{items.Type}), + Nullable: items.Nullable, + Format: items.Format, + In: in, + Path: path, + }, + iv.stringValidator(), + iv.formatValidator(), + iv.numberValidator(), + iv.sliceValidator(), + iv.commonValidator(), + } + return iv +} + +func (i *itemsValidator) Validate(index int, data interface{}) *Result { + tpe := reflect.TypeOf(data) + kind := tpe.Kind() + mainResult := new(Result) + path := fmt.Sprintf("%s.%d", i.path, index) + + for _, validator := range i.validators { + validator.SetPath(path) + if validator.Applies(i.root, kind) { + result := validator.Validate(data) + mainResult.Merge(result) + mainResult.Inc() + if result != nil && result.HasErrors() { + return mainResult + } + } + } + return mainResult +} + +func (i *itemsValidator) commonValidator() valueValidator { + return &basicCommonValidator{ + In: i.in, + Default: i.items.Default, + Enum: i.items.Enum, + } +} + +func (i *itemsValidator) sliceValidator() valueValidator { + return &basicSliceValidator{ + In: i.in, + Default: i.items.Default, + MaxItems: i.items.MaxItems, + MinItems: i.items.MinItems, + UniqueItems: i.items.UniqueItems, + Source: i.root, + Items: i.items.Items, + KnownFormats: i.KnownFormats, + } +} + +func (i *itemsValidator) numberValidator() valueValidator { + return &numberValidator{ + In: i.in, + Default: i.items.Default, + MultipleOf: i.items.MultipleOf, + Maximum: i.items.Maximum, + ExclusiveMaximum: i.items.ExclusiveMaximum, + Minimum: i.items.Minimum, + ExclusiveMinimum: i.items.ExclusiveMinimum, + Type: i.items.Type, + Format: i.items.Format, + } +} + +func (i *itemsValidator) stringValidator() valueValidator { + return &stringValidator{ + In: i.in, + Default: i.items.Default, + MaxLength: i.items.MaxLength, + MinLength: i.items.MinLength, + Pattern: i.items.Pattern, + AllowEmptyValue: false, + } +} + +func (i *itemsValidator) formatValidator() valueValidator { + return &formatValidator{ + In: i.in, + //Default: i.items.Default, + Format: i.items.Format, + KnownFormats: i.KnownFormats, + } +} + +type basicCommonValidator struct { + Path string + In string + Default interface{} + Enum []interface{} +} + +func (b *basicCommonValidator) SetPath(path string) { + b.Path = path +} + +func (b *basicCommonValidator) Applies(source interface{}, kind reflect.Kind) bool { + switch source.(type) { + case *spec.Parameter, *spec.Schema, *spec.Header: + return true + } + return false +} + +func (b *basicCommonValidator) Validate(data interface{}) (res *Result) { + if len(b.Enum) > 0 { + for _, enumValue := range b.Enum { + actualType := reflect.TypeOf(enumValue) + if actualType != nil { // Safeguard + expectedValue := reflect.ValueOf(data) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) { + return nil + } + } + } + } + return errorHelp.sErr(errors.EnumFail(b.Path, b.In, data, b.Enum)) + } + return nil +} + +// A HeaderValidator has very limited subset of validations to apply +type HeaderValidator struct { + name string + header *spec.Header + validators []valueValidator + KnownFormats strfmt.Registry +} + +// NewHeaderValidator creates a new header validator object +func NewHeaderValidator(name string, header *spec.Header, formats strfmt.Registry) *HeaderValidator { + p := &HeaderValidator{name: name, header: header, KnownFormats: formats} + p.validators = []valueValidator{ + &typeValidator{ + Type: spec.StringOrArray([]string{header.Type}), + Nullable: header.Nullable, + Format: header.Format, + In: "header", + Path: name, + }, + p.stringValidator(), + p.formatValidator(), + p.numberValidator(), + p.sliceValidator(), + p.commonValidator(), + } + return p +} + +// Validate the value of the header against its schema +func (p *HeaderValidator) Validate(data interface{}) *Result { + result := new(Result) + tpe := reflect.TypeOf(data) + kind := tpe.Kind() + + for _, validator := range p.validators { + if validator.Applies(p.header, kind) { + if err := validator.Validate(data); err != nil { + result.Merge(err) + if err.HasErrors() { + return result + } + } + } + } + return nil +} + +func (p *HeaderValidator) commonValidator() valueValidator { + return &basicCommonValidator{ + Path: p.name, + In: "response", + Default: p.header.Default, + Enum: p.header.Enum, + } +} + +func (p *HeaderValidator) sliceValidator() valueValidator { + return &basicSliceValidator{ + Path: p.name, + In: "response", + Default: p.header.Default, + MaxItems: p.header.MaxItems, + MinItems: p.header.MinItems, + UniqueItems: p.header.UniqueItems, + Items: p.header.Items, + Source: p.header, + KnownFormats: p.KnownFormats, + } +} + +func (p *HeaderValidator) numberValidator() valueValidator { + return &numberValidator{ + Path: p.name, + In: "response", + Default: p.header.Default, + MultipleOf: p.header.MultipleOf, + Maximum: p.header.Maximum, + ExclusiveMaximum: p.header.ExclusiveMaximum, + Minimum: p.header.Minimum, + ExclusiveMinimum: p.header.ExclusiveMinimum, + Type: p.header.Type, + Format: p.header.Format, + } +} + +func (p *HeaderValidator) stringValidator() valueValidator { + return &stringValidator{ + Path: p.name, + In: "response", + Default: p.header.Default, + Required: true, + MaxLength: p.header.MaxLength, + MinLength: p.header.MinLength, + Pattern: p.header.Pattern, + AllowEmptyValue: false, + } +} + +func (p *HeaderValidator) formatValidator() valueValidator { + return &formatValidator{ + Path: p.name, + In: "response", + //Default: p.header.Default, + Format: p.header.Format, + KnownFormats: p.KnownFormats, + } +} + +// A ParamValidator has very limited subset of validations to apply +type ParamValidator struct { + param *spec.Parameter + validators []valueValidator + KnownFormats strfmt.Registry +} + +// NewParamValidator creates a new param validator object +func NewParamValidator(param *spec.Parameter, formats strfmt.Registry) *ParamValidator { + p := &ParamValidator{param: param, KnownFormats: formats} + p.validators = []valueValidator{ + &typeValidator{ + Type: spec.StringOrArray([]string{param.Type}), + Nullable: param.Nullable, + Format: param.Format, + In: param.In, + Path: param.Name, + }, + p.stringValidator(), + p.formatValidator(), + p.numberValidator(), + p.sliceValidator(), + p.commonValidator(), + } + return p +} + +// Validate the data against the description of the parameter +func (p *ParamValidator) Validate(data interface{}) *Result { + result := new(Result) + tpe := reflect.TypeOf(data) + kind := tpe.Kind() + + // TODO: validate type + for _, validator := range p.validators { + if validator.Applies(p.param, kind) { + if err := validator.Validate(data); err != nil { + result.Merge(err) + if err.HasErrors() { + return result + } + } + } + } + return nil +} + +func (p *ParamValidator) commonValidator() valueValidator { + return &basicCommonValidator{ + Path: p.param.Name, + In: p.param.In, + Default: p.param.Default, + Enum: p.param.Enum, + } +} + +func (p *ParamValidator) sliceValidator() valueValidator { + return &basicSliceValidator{ + Path: p.param.Name, + In: p.param.In, + Default: p.param.Default, + MaxItems: p.param.MaxItems, + MinItems: p.param.MinItems, + UniqueItems: p.param.UniqueItems, + Items: p.param.Items, + Source: p.param, + KnownFormats: p.KnownFormats, + } +} + +func (p *ParamValidator) numberValidator() valueValidator { + return &numberValidator{ + Path: p.param.Name, + In: p.param.In, + Default: p.param.Default, + MultipleOf: p.param.MultipleOf, + Maximum: p.param.Maximum, + ExclusiveMaximum: p.param.ExclusiveMaximum, + Minimum: p.param.Minimum, + ExclusiveMinimum: p.param.ExclusiveMinimum, + Type: p.param.Type, + Format: p.param.Format, + } +} + +func (p *ParamValidator) stringValidator() valueValidator { + return &stringValidator{ + Path: p.param.Name, + In: p.param.In, + Default: p.param.Default, + AllowEmptyValue: p.param.AllowEmptyValue, + Required: p.param.Required, + MaxLength: p.param.MaxLength, + MinLength: p.param.MinLength, + Pattern: p.param.Pattern, + } +} + +func (p *ParamValidator) formatValidator() valueValidator { + return &formatValidator{ + Path: p.param.Name, + In: p.param.In, + //Default: p.param.Default, + Format: p.param.Format, + KnownFormats: p.KnownFormats, + } +} + +type basicSliceValidator struct { + Path string + In string + Default interface{} + MaxItems *int64 + MinItems *int64 + UniqueItems bool + Items *spec.Items + Source interface{} + itemsValidator *itemsValidator + KnownFormats strfmt.Registry +} + +func (s *basicSliceValidator) SetPath(path string) { + s.Path = path +} + +func (s *basicSliceValidator) Applies(source interface{}, kind reflect.Kind) bool { + switch source.(type) { + case *spec.Parameter, *spec.Items, *spec.Header: + return kind == reflect.Slice + } + return false +} + +func (s *basicSliceValidator) Validate(data interface{}) *Result { + val := reflect.ValueOf(data) + + size := int64(val.Len()) + if s.MinItems != nil { + if err := MinItems(s.Path, s.In, size, *s.MinItems); err != nil { + return errorHelp.sErr(err) + } + } + + if s.MaxItems != nil { + if err := MaxItems(s.Path, s.In, size, *s.MaxItems); err != nil { + return errorHelp.sErr(err) + } + } + + if s.UniqueItems { + if err := UniqueItems(s.Path, s.In, data); err != nil { + return errorHelp.sErr(err) + } + } + + if s.itemsValidator == nil && s.Items != nil { + s.itemsValidator = newItemsValidator(s.Path, s.In, s.Items, s.Source, s.KnownFormats) + } + + if s.itemsValidator != nil { + for i := 0; i < int(size); i++ { + ele := val.Index(i) + if err := s.itemsValidator.Validate(i, ele.Interface()); err != nil && err.HasErrors() { + return err + } + } + } + return nil +} + +func (s *basicSliceValidator) hasDuplicates(value reflect.Value, size int) bool { + dict := make(map[interface{}]struct{}) + for i := 0; i < size; i++ { + ele := value.Index(i) + if _, ok := dict[ele.Interface()]; ok { + return true + } + dict[ele.Interface()] = struct{}{} + } + return false +} + +type numberValidator struct { + Path string + In string + Default interface{} + MultipleOf *float64 + Maximum *float64 + ExclusiveMaximum bool + Minimum *float64 + ExclusiveMinimum bool + // Allows for more accurate behavior regarding integers + Type string + Format string +} + +func (n *numberValidator) SetPath(path string) { + n.Path = path +} + +func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool { + switch source.(type) { + case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header: + isInt := kind >= reflect.Int && kind <= reflect.Uint64 + isFloat := kind == reflect.Float32 || kind == reflect.Float64 + r := isInt || isFloat + debugLog("schema props validator for %q applies %t for %T (kind: %v) isInt=%t, isFloat=%t\n", n.Path, r, source, kind, isInt, isFloat) + return r + } + debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind) + return false +} + +// Validate provides a validator for generic JSON numbers, +// +// By default, numbers are internally represented as float64. +// Formats float, or float32 may alter this behavior by mapping to float32. +// A special validation process is followed for integers, with optional "format": +// this is an attempt to provide a validation with native types. +// +// NOTE: since the constraint specified (boundary, multipleOf) is unmarshalled +// as float64, loss of information remains possible (e.g. on very large integers). +// +// Since this value directly comes from the unmarshalling, it is not possible +// at this stage of processing to check further and guarantee the correctness of such values. +// +// Normally, the JSON Number.MAX_SAFE_INTEGER (resp. Number.MIN_SAFE_INTEGER) +// would check we do not get such a loss. +// +// If this is the case, replace AddErrors() by AddWarnings() and IsValid() by !HasWarnings(). +// +// TODO: consider replacing boundary check errors by simple warnings. +// +// TODO: default boundaries with MAX_SAFE_INTEGER are not checked (specific to json.Number?) +func (n *numberValidator) Validate(val interface{}) *Result { + res := new(Result) + + resMultiple := new(Result) + resMinimum := new(Result) + resMaximum := new(Result) + + // Used only to attempt to validate constraint on value, + // even though value or constraint specified do not match type and format + data := valueHelp.asFloat64(val) + + // Is the provided value within the range of the specified numeric type and format? + res.AddErrors(IsValueValidAgainstRange(val, n.Type, n.Format, "Checked", n.Path)) + + if n.MultipleOf != nil { + // Is the constraint specifier within the range of the specific numeric type and format? + resMultiple.AddErrors(IsValueValidAgainstRange(*n.MultipleOf, n.Type, n.Format, "MultipleOf", n.Path)) + if resMultiple.IsValid() { + // Constraint validated with compatible types + if err := MultipleOfNativeType(n.Path, n.In, val, *n.MultipleOf); err != nil { + resMultiple.Merge(errorHelp.sErr(err)) + } + } else { + // Constraint nevertheless validated, converted as general number + if err := MultipleOf(n.Path, n.In, data, *n.MultipleOf); err != nil { + resMultiple.Merge(errorHelp.sErr(err)) + } + } + } + + if n.Maximum != nil { + // Is the constraint specifier within the range of the specific numeric type and format? + resMaximum.AddErrors(IsValueValidAgainstRange(*n.Maximum, n.Type, n.Format, "Maximum boundary", n.Path)) + if resMaximum.IsValid() { + // Constraint validated with compatible types + if err := MaximumNativeType(n.Path, n.In, val, *n.Maximum, n.ExclusiveMaximum); err != nil { + resMaximum.Merge(errorHelp.sErr(err)) + } + } else { + // Constraint nevertheless validated, converted as general number + if err := Maximum(n.Path, n.In, data, *n.Maximum, n.ExclusiveMaximum); err != nil { + resMaximum.Merge(errorHelp.sErr(err)) + } + } + } + + if n.Minimum != nil { + // Is the constraint specifier within the range of the specific numeric type and format? + resMinimum.AddErrors(IsValueValidAgainstRange(*n.Minimum, n.Type, n.Format, "Minimum boundary", n.Path)) + if resMinimum.IsValid() { + // Constraint validated with compatible types + if err := MinimumNativeType(n.Path, n.In, val, *n.Minimum, n.ExclusiveMinimum); err != nil { + resMinimum.Merge(errorHelp.sErr(err)) + } + } else { + // Constraint nevertheless validated, converted as general number + if err := Minimum(n.Path, n.In, data, *n.Minimum, n.ExclusiveMinimum); err != nil { + resMinimum.Merge(errorHelp.sErr(err)) + } + } + } + res.Merge(resMultiple, resMinimum, resMaximum) + res.Inc() + return res +} + +type stringValidator struct { + Default interface{} + Required bool + AllowEmptyValue bool + MaxLength *int64 + MinLength *int64 + Pattern string + Path string + In string +} + +func (s *stringValidator) SetPath(path string) { + s.Path = path +} + +func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool { + switch source.(type) { + case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header: + r := kind == reflect.String + debugLog("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind) + return r + } + debugLog("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind) + return false +} + +func (s *stringValidator) Validate(val interface{}) *Result { + data, ok := val.(string) + if !ok { + return errorHelp.sErr(errors.InvalidType(s.Path, s.In, "string", val)) + } + + if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") { + if err := RequiredString(s.Path, s.In, data); err != nil { + return errorHelp.sErr(err) + } + } + + if s.MaxLength != nil { + if err := MaxLength(s.Path, s.In, data, *s.MaxLength); err != nil { + return errorHelp.sErr(err) + } + } + + if s.MinLength != nil { + if err := MinLength(s.Path, s.In, data, *s.MinLength); err != nil { + return errorHelp.sErr(err) + } + } + + if s.Pattern != "" { + if err := Pattern(s.Path, s.In, data, s.Pattern); err != nil { + return errorHelp.sErr(err) + } + } + return nil +} diff --git a/vendor/github.com/go-openapi/validate/values.go b/vendor/github.com/go-openapi/validate/values.go new file mode 100644 index 000000000..24606da8d --- /dev/null +++ b/vendor/github.com/go-openapi/validate/values.go @@ -0,0 +1,398 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed 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 validate + +import ( + "fmt" + "reflect" + "unicode/utf8" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Enum validates if the data is a member of the enum +func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation { + val := reflect.ValueOf(enum) + if val.Kind() != reflect.Slice { + return nil + } + + var values []interface{} + for i := 0; i < val.Len(); i++ { + ele := val.Index(i) + enumValue := ele.Interface() + if data != nil { + if reflect.DeepEqual(data, enumValue) { + return nil + } + actualType := reflect.TypeOf(enumValue) + if actualType == nil { // Safeguard. Frankly, I don't know how we may get a nil + continue + } + expectedValue := reflect.ValueOf(data) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + // Attempt comparison after type conversion + if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) { + return nil + } + } + } + values = append(values, enumValue) + } + return errors.EnumFail(path, in, data, values) +} + +// MinItems validates that there are at least n items in a slice +func MinItems(path, in string, size, min int64) *errors.Validation { + if size < min { + return errors.TooFewItems(path, in, min) + } + return nil +} + +// MaxItems validates that there are at most n items in a slice +func MaxItems(path, in string, size, max int64) *errors.Validation { + if size > max { + return errors.TooManyItems(path, in, max) + } + return nil +} + +// UniqueItems validates that the provided slice has unique elements +func UniqueItems(path, in string, data interface{}) *errors.Validation { + val := reflect.ValueOf(data) + if val.Kind() != reflect.Slice { + return nil + } + var unique []interface{} + for i := 0; i < val.Len(); i++ { + v := val.Index(i).Interface() + for _, u := range unique { + if reflect.DeepEqual(v, u) { + return errors.DuplicateItems(path, in) + } + } + unique = append(unique, v) + } + return nil +} + +// MinLength validates a string for minimum length +func MinLength(path, in, data string, minLength int64) *errors.Validation { + strLen := int64(utf8.RuneCount([]byte(data))) + if strLen < minLength { + return errors.TooShort(path, in, minLength) + } + return nil +} + +// MaxLength validates a string for maximum length +func MaxLength(path, in, data string, maxLength int64) *errors.Validation { + strLen := int64(utf8.RuneCount([]byte(data))) + if strLen > maxLength { + return errors.TooLong(path, in, maxLength) + } + return nil +} + +// Required validates an interface for requiredness +func Required(path, in string, data interface{}) *errors.Validation { + val := reflect.ValueOf(data) + if val.IsValid() { + if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) { + return errors.Required(path, in) + } + return nil + } + return errors.Required(path, in) +} + +// RequiredString validates a string for requiredness +func RequiredString(path, in, data string) *errors.Validation { + if data == "" { + return errors.Required(path, in) + } + return nil +} + +// RequiredNumber validates a number for requiredness +func RequiredNumber(path, in string, data float64) *errors.Validation { + if data == 0 { + return errors.Required(path, in) + } + return nil +} + +// Pattern validates a string against a regular expression +func Pattern(path, in, data, pattern string) *errors.Validation { + re, err := compileRegexp(pattern) + if err != nil { + return errors.FailedPattern(path, in, fmt.Sprintf("%s, but pattern is invalid: %s", pattern, err.Error())) + } + if !re.MatchString(data) { + return errors.FailedPattern(path, in, pattern) + } + return nil +} + +// MaximumInt validates if a number is smaller than a given maximum +func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation { + if (!exclusive && data > max) || (exclusive && data >= max) { + return errors.ExceedsMaximumInt(path, in, max, exclusive) + } + return nil +} + +// MaximumUint validates if a number is smaller than a given maximum +func MaximumUint(path, in string, data, max uint64, exclusive bool) *errors.Validation { + if (!exclusive && data > max) || (exclusive && data >= max) { + return errors.ExceedsMaximumUint(path, in, max, exclusive) + } + return nil +} + +// Maximum validates if a number is smaller than a given maximum +func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation { + if (!exclusive && data > max) || (exclusive && data >= max) { + return errors.ExceedsMaximum(path, in, max, exclusive) + } + return nil +} + +// Minimum validates if a number is smaller than a given minimum +func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation { + if (!exclusive && data < min) || (exclusive && data <= min) { + return errors.ExceedsMinimum(path, in, min, exclusive) + } + return nil +} + +// MinimumInt validates if a number is smaller than a given minimum +func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation { + if (!exclusive && data < min) || (exclusive && data <= min) { + return errors.ExceedsMinimumInt(path, in, min, exclusive) + } + return nil +} + +// MinimumUint validates if a number is smaller than a given minimum +func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation { + if (!exclusive && data < min) || (exclusive && data <= min) { + return errors.ExceedsMinimumUint(path, in, min, exclusive) + } + return nil +} + +// MultipleOf validates if the provided number is a multiple of the factor +func MultipleOf(path, in string, data, factor float64) *errors.Validation { + // multipleOf factor must be positive + if factor < 0 { + return errors.MultipleOfMustBePositive(path, in, factor) + } + var mult float64 + if factor < 1 { + mult = 1 / factor * data + } else { + mult = data / factor + } + if !swag.IsFloat64AJSONInteger(mult) { + return errors.NotMultipleOf(path, in, factor) + } + return nil +} + +// MultipleOfInt validates if the provided integer is a multiple of the factor +func MultipleOfInt(path, in string, data int64, factor int64) *errors.Validation { + // multipleOf factor must be positive + if factor < 0 { + return errors.MultipleOfMustBePositive(path, in, factor) + } + mult := data / factor + if mult*factor != data { + return errors.NotMultipleOf(path, in, factor) + } + return nil +} + +// MultipleOfUint validates if the provided unsigned integer is a multiple of the factor +func MultipleOfUint(path, in string, data, factor uint64) *errors.Validation { + mult := data / factor + if mult*factor != data { + return errors.NotMultipleOf(path, in, factor) + } + return nil +} + +// FormatOf validates if a string matches a format in the format registry +func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation { + if registry == nil { + registry = strfmt.Default + } + if ok := registry.ContainsName(format); !ok { + return errors.InvalidTypeName(format) + } + if ok := registry.Validates(format, data); !ok { + return errors.InvalidType(path, in, format, data) + } + return nil +} + +// MaximumNativeType provides native type constraint validation as a facade +// to various numeric types versions of Maximum constraint check. +// +// Assumes that any possible loss conversion during conversion has been +// checked beforehand. +// +// NOTE: currently, the max value is marshalled as a float64, no matter what, +// which means there may be a loss during conversions (e.g. for very large integers) +// +// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free +func MaximumNativeType(path, in string, val interface{}, max float64, exclusive bool) *errors.Validation { + kind := reflect.ValueOf(val).Type().Kind() + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + value := valueHelp.asInt64(val) + return MaximumInt(path, in, value, int64(max), exclusive) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + value := valueHelp.asUint64(val) + if max < 0 { + return errors.ExceedsMaximum(path, in, max, exclusive) + } + return MaximumUint(path, in, value, uint64(max), exclusive) + case reflect.Float32, reflect.Float64: + fallthrough + default: + value := valueHelp.asFloat64(val) + return Maximum(path, in, value, max, exclusive) + } +} + +// MinimumNativeType provides native type constraint validation as a facade +// to various numeric types versions of Minimum constraint check. +// +// Assumes that any possible loss conversion during conversion has been +// checked beforehand. +// +// NOTE: currently, the min value is marshalled as a float64, no matter what, +// which means there may be a loss during conversions (e.g. for very large integers) +// +// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free +func MinimumNativeType(path, in string, val interface{}, min float64, exclusive bool) *errors.Validation { + kind := reflect.ValueOf(val).Type().Kind() + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + value := valueHelp.asInt64(val) + return MinimumInt(path, in, value, int64(min), exclusive) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + value := valueHelp.asUint64(val) + if min < 0 { + return nil + } + return MinimumUint(path, in, value, uint64(min), exclusive) + case reflect.Float32, reflect.Float64: + fallthrough + default: + value := valueHelp.asFloat64(val) + return Minimum(path, in, value, min, exclusive) + } +} + +// MultipleOfNativeType provides native type constraint validation as a facade +// to various numeric types version of MultipleOf constraint check. +// +// Assumes that any possible loss conversion during conversion has been +// checked beforehand. +// +// NOTE: currently, the multipleOf factor is marshalled as a float64, no matter what, +// which means there may be a loss during conversions (e.g. for very large integers) +// +// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free +func MultipleOfNativeType(path, in string, val interface{}, multipleOf float64) *errors.Validation { + kind := reflect.ValueOf(val).Type().Kind() + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + value := valueHelp.asInt64(val) + return MultipleOfInt(path, in, value, int64(multipleOf)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + value := valueHelp.asUint64(val) + return MultipleOfUint(path, in, value, uint64(multipleOf)) + case reflect.Float32, reflect.Float64: + fallthrough + default: + value := valueHelp.asFloat64(val) + return MultipleOf(path, in, value, multipleOf) + } +} + +// IsValueValidAgainstRange checks that a numeric value is compatible with +// the range defined by Type and Format, that is, may be converted without loss. +// +// NOTE: this check is about type capacity and not formal verification such as: 1.0 != 1L +func IsValueValidAgainstRange(val interface{}, typeName, format, prefix, path string) error { + kind := reflect.ValueOf(val).Type().Kind() + + // What is the string representation of val + stringRep := "" + switch kind { + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + stringRep = swag.FormatUint64(valueHelp.asUint64(val)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + stringRep = swag.FormatInt64(valueHelp.asInt64(val)) + case reflect.Float32, reflect.Float64: + stringRep = swag.FormatFloat64(valueHelp.asFloat64(val)) + default: + return fmt.Errorf("%s value number range checking called with invalid (non numeric) val type in %s", prefix, path) + } + + var errVal error + + switch typeName { + case "integer": + switch format { + case "int32": + _, errVal = swag.ConvertInt32(stringRep) + case "uint32": + _, errVal = swag.ConvertUint32(stringRep) + case "uint64": + _, errVal = swag.ConvertUint64(stringRep) + case "int64": + fallthrough + default: + _, errVal = swag.ConvertInt64(stringRep) + } + case "number": + fallthrough + default: + switch format { + case "float", "float32": + _, errVal = swag.ConvertFloat32(stringRep) + case "double", "float64": + fallthrough + default: + // No check can be performed here since + // no number beyond float64 is supported + } + } + if errVal != nil { // We don't report the actual errVal from strconv + if format != "" { + errVal = fmt.Errorf("%s value must be of type %s with format %s in %s", prefix, typeName, format, path) + } else { + errVal = fmt.Errorf("%s value must be of type %s (default format) in %s", prefix, typeName, path) + } + } + return errVal +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cf05e33e0..28d48de25 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,9 +7,9 @@ github.com/Azure/go-ansiterm github.com/Azure/go-ansiterm/winterm # github.com/Azure/go-autorest/autorest v0.9.0 => github.com/Azure/go-autorest/autorest v0.9.0 github.com/Azure/go-autorest/autorest +github.com/Azure/go-autorest/autorest/azure # github.com/Azure/go-autorest/autorest/adal v0.5.0 => github.com/Azure/go-autorest/autorest/adal v0.5.0 github.com/Azure/go-autorest/autorest/adal -github.com/Azure/go-autorest/autorest/azure # github.com/Azure/go-autorest/autorest/date v0.1.0 => github.com/Azure/go-autorest/autorest/date v0.1.0 github.com/Azure/go-autorest/autorest/date # github.com/Azure/go-autorest/logger v0.1.0 => github.com/Azure/go-autorest/logger v0.1.0 @@ -166,9 +166,9 @@ github.com/elastic/go-elasticsearch/v7/estransport github.com/elastic/go-elasticsearch/v7/internal/version # github.com/emicklei/go-restful v2.9.5+incompatible => github.com/emicklei/go-restful v2.9.5+incompatible github.com/emicklei/go-restful +github.com/emicklei/go-restful/log # github.com/emicklei/go-restful-openapi v1.0.0 => github.com/emicklei/go-restful-openapi v1.0.0 github.com/emicklei/go-restful-openapi -github.com/emicklei/go-restful/log # github.com/emirpasic/gods v1.12.0 => github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists @@ -195,18 +195,27 @@ github.com/globalsign/mgo/internal/json github.com/go-ldap/ldap # github.com/go-logr/logr v0.1.0 => github.com/go-logr/logr v0.1.0 github.com/go-logr/logr +# github.com/go-openapi/analysis v0.19.2 => github.com/go-openapi/analysis v0.19.2 +github.com/go-openapi/analysis +github.com/go-openapi/analysis/internal # github.com/go-openapi/errors v0.19.2 => github.com/go-openapi/errors v0.19.2 github.com/go-openapi/errors # github.com/go-openapi/jsonpointer v0.19.3 => github.com/go-openapi/jsonpointer v0.19.3 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.19.3 => github.com/go-openapi/jsonreference v0.19.3 github.com/go-openapi/jsonreference +# github.com/go-openapi/loads v0.19.2 => github.com/go-openapi/loads v0.19.2 +github.com/go-openapi/loads +# github.com/go-openapi/runtime v0.19.0 => github.com/go-openapi/runtime v0.19.0 +github.com/go-openapi/runtime # github.com/go-openapi/spec v0.19.3 => github.com/go-openapi/spec v0.19.3 github.com/go-openapi/spec # github.com/go-openapi/strfmt v0.19.0 => github.com/go-openapi/strfmt v0.19.0 github.com/go-openapi/strfmt # github.com/go-openapi/swag v0.19.5 => github.com/go-openapi/swag v0.19.5 github.com/go-openapi/swag +# github.com/go-openapi/validate v0.19.2 => github.com/go-openapi/validate v0.19.2 +github.com/go-openapi/validate # github.com/go-playground/locales v0.12.1 => github.com/go-playground/locales v0.12.1 github.com/go-playground/locales github.com/go-playground/locales/currency