diff --git a/changelog/14217.txt b/changelog/14217.txt deleted file mode 100644 index de42fca36b05..000000000000 --- a/changelog/14217.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -sdk: Change OpenAPI code generator to extract request objects into /components/schemas and reference them by name. -``` diff --git a/sdk/framework/backend.go b/sdk/framework/backend.go index ecb88f5c4667..cdee46f48611 100644 --- a/sdk/framework/backend.go +++ b/sdk/framework/backend.go @@ -198,7 +198,7 @@ func (b *Backend) HandleRequest(ctx context.Context, req *logical.Request) (*log // If the path is empty and it is a help operation, handle that. if req.Path == "" && req.Operation == logical.HelpOperation { - return b.handleRootHelp(req) + return b.handleRootHelp() } // Find the matching route @@ -457,7 +457,7 @@ func (b *Backend) route(path string) (*Path, map[string]string) { return nil, nil } -func (b *Backend) handleRootHelp(req *logical.Request) (*logical.Response, error) { +func (b *Backend) handleRootHelp() (*logical.Response, error) { // Build a mapping of the paths and get the paths alphabetized to // make the output prettier. pathsMap := make(map[string]*Path) @@ -486,18 +486,9 @@ func (b *Backend) handleRootHelp(req *logical.Request) (*logical.Response, error return nil, err } - // Plugins currently don't have a direct knowledge of their own "type" - // (e.g. "kv", "cubbyhole"). It defaults to the name of the executable but - // can be overridden when the plugin is mounted. Since we need this type to - // form the request & response full names, we are passing it as an optional - // request parameter to the plugin's root help endpoint. If specified in - // the request, the type will be used as part of the request/response body - // names in the OAS document. - requestResponsePrefix := req.GetString("requestResponsePrefix") - // Build OpenAPI response for the entire backend doc := NewOASDocument() - if err := documentPaths(b, requestResponsePrefix, doc); err != nil { + if err := documentPaths(b, doc); err != nil { b.Logger().Warn("error generating OpenAPI", "error", err) } diff --git a/sdk/framework/openapi.go b/sdk/framework/openapi.go index 87240ecc8586..fb760774ba68 100644 --- a/sdk/framework/openapi.go +++ b/sdk/framework/openapi.go @@ -32,9 +32,6 @@ func NewOASDocument() *OASDocument { }, }, Paths: make(map[string]*OASPathItem), - Components: OASComponents{ - Schemas: make(map[string]*OASSchema), - }, } } @@ -81,14 +78,9 @@ func NewOASDocumentFromMap(input map[string]interface{}) (*OASDocument, error) { } type OASDocument struct { - Version string `json:"openapi" mapstructure:"openapi"` - Info OASInfo `json:"info"` - Paths map[string]*OASPathItem `json:"paths"` - Components OASComponents `json:"components"` -} - -type OASComponents struct { - Schemas map[string]*OASSchema `json:"schemas"` + Version string `json:"openapi" mapstructure:"openapi"` + Info OASInfo `json:"info"` + Paths map[string]*OASPathItem `json:"paths"` } type OASInfo struct { @@ -156,7 +148,6 @@ type OASMediaTypeObject struct { } type OASSchema struct { - Ref string `json:"$ref,omitempty"` Type string `json:"type,omitempty"` Description string `json:"description,omitempty"` Properties map[string]*OASSchema `json:"properties,omitempty"` @@ -213,9 +204,9 @@ var ( ) // documentPaths parses all paths in a framework.Backend into OpenAPI paths. -func documentPaths(backend *Backend, requestResponsePrefix string, doc *OASDocument) error { +func documentPaths(backend *Backend, doc *OASDocument) error { for _, p := range backend.Paths { - if err := documentPath(p, backend.SpecialPaths(), requestResponsePrefix, backend.BackendType, doc); err != nil { + if err := documentPath(p, backend.SpecialPaths(), backend.BackendType, doc); err != nil { return err } } @@ -224,7 +215,7 @@ func documentPaths(backend *Backend, requestResponsePrefix string, doc *OASDocum } // documentPath parses a framework.Path into one or more OpenAPI paths. -func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix string, backendType logical.BackendType, doc *OASDocument) error { +func documentPath(p *Path, specialPaths *logical.Paths, backendType logical.BackendType, doc *OASDocument) error { var sudoPaths []string var unauthPaths []string @@ -233,7 +224,7 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st unauthPaths = specialPaths.Unauthenticated } - // Convert optional parameters into distinct patterns to be processed independently. + // Convert optional parameters into distinct patterns to be process independently. paths := expandPattern(p.Pattern) for _, path := range paths { @@ -367,12 +358,10 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st // Set the final request body. Only JSON request data is supported. if len(s.Properties) > 0 || s.Example != nil { - requestName := constructRequestName(requestResponsePrefix, path) - doc.Components.Schemas[requestName] = s op.RequestBody = &OASRequestBody{ Content: OASContent{ "application/json": &OASMediaTypeObject{ - Schema: &OASSchema{Ref: fmt.Sprintf("#/components/schemas/%s", requestName)}, + Schema: s, }, }, } @@ -470,30 +459,6 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st return nil } -// constructRequestName joins the given prefix with the path elements into a -// CamelCaseRequest string. -// -// For example, prefix="kv" & path=/config/lease/{name} => KvConfigLeaseRequest -func constructRequestName(requestResponsePrefix string, path string) string { - var b strings.Builder - - b.WriteString(strings.Title(requestResponsePrefix)) - - // split the path by / _ - separators - for _, token := range strings.FieldsFunc(path, func(r rune) bool { - return r == '/' || r == '_' || r == '-' - }) { - // exclude request fields - if !strings.ContainsAny(token, "{}") { - b.WriteString(strings.Title(token)) - } - } - - b.WriteString("Request") - - return b.String() -} - func specialPathMatch(path string, specialPaths []string) bool { // Test for exact or prefix match of special paths. for _, sp := range specialPaths { diff --git a/sdk/framework/openapi_test.go b/sdk/framework/openapi_test.go index fa14d2eb88c8..7e514481de08 100644 --- a/sdk/framework/openapi_test.go +++ b/sdk/framework/openapi_test.go @@ -271,7 +271,7 @@ func TestOpenAPI_SpecialPaths(t *testing.T) { Root: test.rootPaths, Unauthenticated: test.unauthPaths, } - err := documentPath(&path, sp, "kv", logical.TypeLogical, doc) + err := documentPath(&path, sp, logical.TypeLogical, doc) if err != nil { t.Fatal(err) } @@ -515,11 +515,11 @@ func TestOpenAPI_OperationID(t *testing.T) { for _, context := range []string{"", "bar"} { doc := NewOASDocument() - err := documentPath(path1, nil, "kv", logical.TypeLogical, doc) + err := documentPath(path1, nil, logical.TypeLogical, doc) if err != nil { t.Fatal(err) } - err = documentPath(path2, nil, "kv", logical.TypeLogical, doc) + err = documentPath(path2, nil, logical.TypeLogical, doc) if err != nil { t.Fatal(err) } @@ -579,7 +579,7 @@ func TestOpenAPI_CustomDecoder(t *testing.T) { } docOrig := NewOASDocument() - err := documentPath(p, nil, "kv", logical.TypeLogical, docOrig) + err := documentPath(p, nil, logical.TypeLogical, docOrig) if err != nil { t.Fatal(err) } @@ -642,7 +642,7 @@ func testPath(t *testing.T, path *Path, sp *logical.Paths, expectedJSON string) t.Helper() doc := NewOASDocument() - if err := documentPath(path, sp, "kv", logical.TypeLogical, doc); err != nil { + if err := documentPath(path, sp, logical.TypeLogical, doc); err != nil { t.Fatal(err) } doc.CreateOperationIDs("") diff --git a/sdk/framework/path.go b/sdk/framework/path.go index b316d2cc1577..4dc8ca303361 100644 --- a/sdk/framework/path.go +++ b/sdk/framework/path.go @@ -301,17 +301,9 @@ func (p *Path) helpCallback(b *Backend) OperationFunc { return nil, errwrap.Wrapf("error executing template: {{err}}", err) } - // The plugin type (e.g. "kv", "cubbyhole") is only assigned at the time - // the plugin is enabled (mounted). If specified in the request, the type - // will be used as part of the request/response names in the OAS document - var requestResponsePrefix string - if v, ok := req.Data["requestResponsePrefix"]; ok { - requestResponsePrefix = v.(string) - } - // Build OpenAPI response for this path doc := NewOASDocument() - if err := documentPath(p, b.SpecialPaths(), requestResponsePrefix, b.BackendType, doc); err != nil { + if err := documentPath(p, b.SpecialPaths(), b.BackendType, doc); err != nil { b.Logger().Warn("error generating OpenAPI", "error", err) } diff --git a/sdk/framework/testdata/legacy.json b/sdk/framework/testdata/legacy.json index cb1f7ebd3f2d..2fcb26882f52 100644 --- a/sdk/framework/testdata/legacy.json +++ b/sdk/framework/testdata/legacy.json @@ -41,7 +41,13 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/KvLookupRequest" + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "My token" + } + } } } } @@ -53,19 +59,6 @@ } } } - }, - "components": { - "schemas": { - "KvLookupRequest": { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "My token" - } - } - } - } } } diff --git a/sdk/framework/testdata/operations.json b/sdk/framework/testdata/operations.json index 94d54087b62f..4c140f92b732 100644 --- a/sdk/framework/testdata/operations.json +++ b/sdk/framework/testdata/operations.json @@ -66,7 +66,39 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/KvFooRequest" + "type": "object", + "required": ["age"], + "properties": { + "flavors": { + "type": "array", + "description": "the flavors", + "items": { + "type": "string" + } + }, + "age": { + "type": "integer", + "description": "the age", + "enum": [1, 2, 3], + "x-vault-displayAttrs": { + "name": "Age", + "sensitive": true, + "group": "Some Group", + "value": 7 + } + }, + "name": { + "type": "string", + "description": "the name", + "default": "Larry", + "pattern": "\\w([\\w-.]*\\w)?" + }, + "x-abc-token": { + "type": "string", + "description": "a header value", + "enum": ["a", "b", "c"] + } + } } } } @@ -78,44 +110,5 @@ } } } - }, - "components": { - "schemas": { - "KvFooRequest": { - "type": "object", - "required": ["age"], - "properties": { - "flavors": { - "type": "array", - "description": "the flavors", - "items": { - "type": "string" - } - }, - "age": { - "type": "integer", - "description": "the age", - "enum": [1, 2, 3], - "x-vault-displayAttrs": { - "name": "Age", - "sensitive": true, - "group": "Some Group", - "value": 7 - } - }, - "name": { - "type": "string", - "description": "the name", - "default": "Larry", - "pattern": "\\w([\\w-.]*\\w)?" - }, - "x-abc-token": { - "type": "string", - "description": "a header value", - "enum": ["a", "b", "c"] - } - } - } - } } } diff --git a/sdk/framework/testdata/operations_list.json b/sdk/framework/testdata/operations_list.json index e89622a3c40a..bea40f61a37e 100644 --- a/sdk/framework/testdata/operations_list.json +++ b/sdk/framework/testdata/operations_list.json @@ -59,9 +59,5 @@ ] } } - }, - "components": { - "schemas": { - } } } diff --git a/sdk/framework/testdata/responses.json b/sdk/framework/testdata/responses.json index b0e197babed5..bd332054c379 100644 --- a/sdk/framework/testdata/responses.json +++ b/sdk/framework/testdata/responses.json @@ -46,10 +46,6 @@ } } } - }, - "components": { - "schemas": { - } } } diff --git a/vault/logical_system.go b/vault/logical_system.go index 9ca785d1849e..d2139a4eb93b 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -4034,13 +4034,7 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re doc := framework.NewOASDocument() procMountGroup := func(group, mountPrefix string) error { - for mount, entry := range resp.Data[group].(map[string]interface{}) { - - var pluginType string - if t, ok := entry.(map[string]interface{})["type"]; ok { - pluginType = t.(string) - } - + for mount := range resp.Data[group].(map[string]interface{}) { backend := b.Core.router.MatchingBackend(ctx, mountPrefix+mount) if backend == nil { @@ -4050,7 +4044,6 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re req := &logical.Request{ Operation: logical.HelpOperation, Storage: req.Storage, - Data: map[string]interface{}{"requestResponsePrefix": pluginType}, } resp, err := backend.HandleRequest(ctx, req) @@ -4106,11 +4099,6 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re doc.Paths["/"+mountPrefix+mount+path] = obj } - - // Merge backend schema components - for e, schema := range backendDoc.Components.Schemas { - doc.Components.Schemas[e] = schema - } } return nil } diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index 4f889d7133f9..3a258395b5bb 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -3436,9 +3436,6 @@ func TestSystemBackend_OpenAPI(t *testing.T) { }, }, "paths": map[string]interface{}{}, - "components": map[string]interface{}{ - "schemas": map[string]interface{}{}, - }, } if diff := deep.Equal(oapi, exp); diff != nil {